UNPKG

homebridge-freeathome-local-api

Version:

Control your free@home setup using the local API provided by your System Access Point

166 lines 9.15 kB
import { FreeAtHomeAccessory } from "./freeAtHomeAccessory.js"; import { EmptyGuid, convertToString, getDataPointByPairingID } from "./util.js"; const pidControllerOnOff = 56; const pidControllerOnOffRequest = 66; const pidHeatingOn = 48; const pidCoolingOn = 50; const pidCurrentTemperature = 304; const pidTargetTemperature = 51; const pidTargetTemperatureRequest = 320; /** A room temperature controller accessory. */ export class RoomTemperatureControllerAccessory extends FreeAtHomeAccessory { platform; accessory; service; controllerOnOff; heatingOn; coolingOn; stateCurrentTemperature; stateTargetTemperature; pdControllerOnOff; pdControllerOnOffRequest; pdHeatingOn; pdCoolingOn; pdCurrentTemperature; pdTargetTemperature; pdTargetTemperatureRequest; get stateCurrentHeatingCoolingState() { if (!this.controllerOnOff) { return this.platform.Characteristic.CurrentHeatingCoolingState.OFF; } else if (this.heatingOn && !this.coolingOn) { return this.platform.Characteristic.CurrentHeatingCoolingState.HEAT; } else if (!this.heatingOn && this.coolingOn) { return this.platform.Characteristic.CurrentHeatingCoolingState.COOL; } else { if (this.heatingOn && this.coolingOn) this.platform.log.error("Invalid State: Heating and cooling cannot be on simultaneously!"); return this.platform.Characteristic.CurrentHeatingCoolingState.OFF; } } get stateTargetHeatingCoolingState() { return this.controllerOnOff ? this.platform.Characteristic.TargetHeatingCoolingState.AUTO : this.platform.Characteristic.TargetHeatingCoolingState.OFF; } /** * Constructs a new Room Temperature Controller accessory instance. * @param platform The free@home Homebridge platform controlling the accessory * @param accessory The platform accessory. */ constructor(platform, accessory) { super(platform, accessory); this.platform = platform; this.accessory = accessory; // Resolve data points if (!this.accessory.context.channel.outputs || !this.accessory.context.channel.inputs) throw new Error("Channel lacks expected input or output data points."); this.pdControllerOnOff = getDataPointByPairingID(this.accessory.context.channel.outputs, pidControllerOnOff); this.pdControllerOnOffRequest = getDataPointByPairingID(this.accessory.context.channel.inputs, pidControllerOnOffRequest); this.pdHeatingOn = getDataPointByPairingID(this.accessory.context.channel.outputs, pidHeatingOn); this.pdCoolingOn = getDataPointByPairingID(this.accessory.context.channel.outputs, pidCoolingOn); this.pdCurrentTemperature = getDataPointByPairingID(this.accessory.context.channel.outputs, pidCurrentTemperature); this.pdTargetTemperature = getDataPointByPairingID(this.accessory.context.channel.outputs, pidTargetTemperature); this.pdTargetTemperatureRequest = getDataPointByPairingID(this.accessory.context.channel.inputs, pidTargetTemperatureRequest); // set initial state this.controllerOnOff = !!parseInt(this.accessory.context.channel.outputs[this.pdControllerOnOff].value ?? "0"); this.heatingOn = !!parseInt(this.accessory.context.channel.outputs[this.pdHeatingOn].value ?? "0"); this.coolingOn = !!parseInt(this.accessory.context.channel.outputs[this.pdCoolingOn].value ?? "0"); this.stateCurrentTemperature = parseFloat(this.accessory.context.channel.outputs[this.pdCurrentTemperature].value ?? "0.0"); this.stateTargetTemperature = parseFloat(this.accessory.context.channel.outputs[this.pdTargetTemperature].value ?? "0.0"); // get the Thermostat service if it exists, otherwise create a new service instance this.service = this.accessory.getService(this.platform.Service.Thermostat) || this.accessory.addService(this.platform.Service.Thermostat); // register handlers for the Current Heating Cooling State Characteristic this.service .getCharacteristic(this.platform.Characteristic.CurrentHeatingCoolingState) .onGet(() => this.stateCurrentHeatingCoolingState); // register handlers for the Target Heating Cooling State Characteristic this.service .getCharacteristic(this.platform.Characteristic.TargetHeatingCoolingState) .onSet(this.setTargetHeatingCoolingState.bind(this)) .onGet(() => this.stateTargetHeatingCoolingState) .setProps({ validValues: [0, 3], }); // register handlers for the Current Temperature Characteristic this.service .getCharacteristic(this.platform.Characteristic.CurrentTemperature) .onGet(() => this.stateCurrentTemperature); // register handlers for the Target Temperature Characteristic this.service .getCharacteristic(this.platform.Characteristic.TargetTemperature) .onSet(this.setTargetTemperature.bind(this)) .onGet(() => this.stateTargetTemperature) .setProps({ maxValue: 35, minValue: 7, minStep: 0.5, }); // register handlers for the Temperature Display Units Characteristic this.service .getCharacteristic(this.platform.Characteristic.TemperatureDisplayUnits) .onGet(() => this.platform.Characteristic.TemperatureDisplayUnits.CELSIUS); } async setTargetTemperature(value) { // avoid unncessary updates or update cache if (value === this.stateTargetTemperature) return; else this.stateTargetTemperature = value; // log event this.platform.log.info(`${this.accessory.displayName} (Room Temperature Controller ${this.serialNumber}) set characteristic TargetTemperature -> ${convertToString(value)}`); // Heating Cooling State must not be OFF to set the target temperature await this.setTargetHeatingCoolingState(this.platform.Characteristic.TargetHeatingCoolingState.AUTO); // set data point at SysAP await this.platform.sysap.setDatapoint(EmptyGuid, this.accessory.context.deviceSerial, this.accessory.context.channelId, this.pdTargetTemperatureRequest, this.stateTargetTemperature.toFixed(1)); } async setTargetHeatingCoolingState(value) { // avoid unncessary updates or update cache if (value === this.stateTargetHeatingCoolingState) return; else this.controllerOnOff = !!value; // log event this.platform.log.info(`${this.accessory.displayName} (Room Temperature Controller ${this.serialNumber}) set characteristic TargetHeatingCoolingState -> ${convertToString(value)}`); // set data point at SysAP await this.platform.sysap.setDatapoint(EmptyGuid, this.accessory.context.deviceSerial, this.accessory.context.channelId, this.pdControllerOnOffRequest, value === this.platform.Characteristic.TargetHeatingCoolingState.OFF ? "0" : "1"); } updateDatapoint(datapoint, value) { switch (datapoint) { case this.pdHeatingOn: this.heatingOn = !!parseInt(value); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.CurrentHeatingCoolingState, this.stateCurrentHeatingCoolingState); return; case this.pdCoolingOn: this.coolingOn = !!parseInt(value); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.CurrentHeatingCoolingState, this.stateCurrentHeatingCoolingState); return; case this.pdControllerOnOff: this.controllerOnOff = !!parseInt(value); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.CurrentHeatingCoolingState, this.stateCurrentHeatingCoolingState); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.TargetHeatingCoolingState, this.stateTargetHeatingCoolingState); return; case this.pdTargetTemperature: this.stateTargetTemperature = parseFloat(value); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.TargetTemperature, this.stateTargetTemperature); return; case this.pdCurrentTemperature: this.stateCurrentTemperature = parseFloat(value); this.doUpdateDatapoint("Room Temperature Controller", this.service, this.platform.Characteristic.CurrentTemperature, this.stateCurrentTemperature); return; default: return; } } } //# sourceMappingURL=roomTemperatureControllerAccessory.js.map