UNPKG

@elshaer/homebridge-hdl-buspro-enhanced

Version:

Linking the HDL bus into the Homebridge widget

183 lines 8.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RelayHeater = void 0; class RelayHeater { constructor(platform, accessory, name, controller, device, // Listener is currently unused but needs to stay in the signature to align with the shared builder // that passes the relay listener instance. listener, channel, minTemperature, maxTemperature, defaultTemperature) { this.platform = platform; this.accessory = accessory; this.name = name; this.controller = controller; this.device = device; this.listener = listener; this.channel = channel; this.minTemperature = minTemperature; this.maxTemperature = maxTemperature; this.defaultTemperature = defaultTemperature; this.heaterState = { active: 0, // 0 = Off, 1 = On currentTemp: 20, targetTemp: 22, }; // HDL MFH06.432 Specific Commands this.HDL_HEATER_CONTROL_CMD = 0xE3E0; this.HDL_TEMP_SET_CMD = 0xE3E1; this.HDL_STATUS_QUERY_CMD = 0xE3E3; void this.listener; const Service = this.platform.Service; const Characteristic = this.platform.Characteristic; // Accessory Information this.accessory.getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.Manufacturer, 'HDL') .setCharacteristic(Characteristic.Model, 'MFH06.432') .setCharacteristic(Characteristic.SerialNumber, `HDL-HEATER-${this.channel}`); // Thermostat Service this.service = this.accessory.getService(Service.Thermostat) || this.accessory.addService(Service.Thermostat); this.service.setCharacteristic(Characteristic.Name, name); if (this.defaultTemperature !== undefined) { this.heaterState.targetTemp = this.clampTargetTemperature(this.defaultTemperature); } // Setup Characteristics this.configureCharacteristics(); this.setupEventListeners(); this.initializeHeater(); } configureCharacteristics() { const Characteristic = this.platform.Characteristic; const { minTarget, maxTarget } = this.getTargetBounds(); // Active State this.service.getCharacteristic(Characteristic.Active) .onGet(() => this.heaterState.active) .onSet((value) => this.setPowerState(value)); // Temperature Characteristics this.service.getCharacteristic(Characteristic.CurrentTemperature) .setProps({ minValue: Math.min(0, minTarget), maxValue: Math.max(40, maxTarget), minStep: 0.5, }) .onGet(() => this.heaterState.currentTemp); this.service.getCharacteristic(Characteristic.TargetTemperature) .setProps({ minValue: minTarget, maxValue: maxTarget, minStep: 0.5 }) .onGet(() => this.heaterState.targetTemp) .onSet((value) => this.setTargetTemperature(value)); // Heating State Characteristics this.service.getCharacteristic(Characteristic.CurrentHeatingCoolingState) .onGet(() => this.heaterState.active ? 1 : 0); this.service.getCharacteristic(Characteristic.TargetHeatingCoolingState) .setProps({ validValues: [0, 1] }) .onGet(() => this.heaterState.active ? 1 : 0) .onSet((value) => this.setPowerState(value)); } setupEventListeners() { // Listen for status updates (MFH06.432 uses 0xE3E4 for broadcast) this.device.on(0xE3E4, (command) => { if (command.data.channel === this.channel) { this.updateFromStatus(command.data); } }); } initializeHeater() { // Query initial state this.controller.send({ target: this.device, command: this.HDL_STATUS_QUERY_CMD, data: { channel: this.channel }, }, (err, res) => { if (err) { this.platform.log.error(`Failed to query heater status for ${this.name}: ${err.message ?? err}`); return; } if (res?.data) { this.updateFromStatus(res.data); return; } this.platform.log.warn(`Heater ${this.name} did not return status data on query.`); }); } updateFromStatus(data) { const Characteristic = this.platform.Characteristic; // Update power state if (data.power !== undefined) { this.heaterState.active = data.power ? 1 : 0; this.service.updateCharacteristic(Characteristic.Active, this.heaterState.active); this.service.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, this.heaterState.active ? Characteristic.CurrentHeatingCoolingState.HEAT : Characteristic.CurrentHeatingCoolingState.OFF); this.service.updateCharacteristic(Characteristic.TargetHeatingCoolingState, this.heaterState.active ? Characteristic.TargetHeatingCoolingState.HEAT : Characteristic.TargetHeatingCoolingState.OFF); } // Update temperatures (direct values, no scaling needed) if (data.currentTemp !== undefined) { this.heaterState.currentTemp = data.currentTemp; this.service.updateCharacteristic(Characteristic.CurrentTemperature, this.heaterState.currentTemp); } if (data.targetTemp !== undefined) { this.heaterState.targetTemp = this.clampTargetTemperature(data.targetTemp); this.service.updateCharacteristic(Characteristic.TargetTemperature, this.heaterState.targetTemp); } } setPowerState(state) { const Characteristic = this.platform.Characteristic; const targetState = state ? 1 : 0; this.controller.send({ target: this.device, command: this.HDL_HEATER_CONTROL_CMD, data: { channel: this.channel, status: targetState, }, }, (err) => { if (err) { this.platform.log.error(`Failed to set heater power for ${this.name}: ${err.message ?? err}`); this.service.updateCharacteristic(Characteristic.Active, this.heaterState.active); return; } this.heaterState.active = targetState; this.service.updateCharacteristic(Characteristic.Active, targetState); this.service.updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetState ? Characteristic.TargetHeatingCoolingState.HEAT : Characteristic.TargetHeatingCoolingState.OFF); this.service.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, targetState ? Characteristic.CurrentHeatingCoolingState.HEAT : Characteristic.CurrentHeatingCoolingState.OFF); this.platform.log.info(`Power state set to ${targetState ? 'ON' : 'OFF'}`); }); } setTargetTemperature(temp) { const Characteristic = this.platform.Characteristic; const previousTemp = this.heaterState.targetTemp; const targetTemp = this.clampTargetTemperature(temp); this.controller.send({ target: this.device, command: this.HDL_TEMP_SET_CMD, data: { channel: this.channel, temperature: targetTemp, }, }, (err) => { if (err) { this.platform.log.error(`Failed to set target temperature for ${this.name}: ${err.message ?? err}`); this.service.updateCharacteristic(Characteristic.TargetTemperature, previousTemp); return; } this.heaterState.targetTemp = targetTemp; this.service.updateCharacteristic(Characteristic.TargetTemperature, targetTemp); this.platform.log.info(`Target temperature set to ${this.heaterState.targetTemp}°C`); }); } getTargetBounds() { const minTarget = this.minTemperature ?? 15; const maxTarget = this.maxTemperature ?? 35; return { minTarget, maxTarget: Math.max(minTarget, maxTarget), }; } clampTargetTemperature(temp) { const { minTarget, maxTarget } = this.getTargetBounds(); return Math.min(maxTarget, Math.max(minTarget, temp)); } } exports.RelayHeater = RelayHeater; //# sourceMappingURL=RelayHeater.js.map