diff --git a/src/ductless.ts b/src/ductless.ts index 62095a9..798eee7 100644 --- a/src/ductless.ts +++ b/src/ductless.ts @@ -20,6 +20,9 @@ export class KumoPlatformAccessory_ductless { private Fan: Service; private PowerSwitch: Service; private Dehumidifier: Service; + private Humidity: Service | null; + private HumidityBattery: Service | null; + private lastupdate; private lastquery; @@ -34,6 +37,16 @@ export class KumoPlatformAccessory_ductless { ) { this.directAccess = this.platform.config.directAccess; + const useExternalSensor = this.directAccess && + this.accessory.context.device.activeThermistor !== undefined && + this.accessory.context.device.activeThermistor !== 'unset'; + + if (useExternalSensor) { + this.platform.log.info('device %s uses external sensor %s', + this.accessory.context.serial, + this.accessory.context.device.activeThermistor); + } + // determine device profile and additional sensors to tailor accessory to // the capabilities of the kumo device // (not yet implemented) @@ -79,6 +92,21 @@ export class KumoPlatformAccessory_ductless { this.Fan.setCharacteristic(this.platform.Characteristic.Name, 'Fan'); this.PowerSwitch.setCharacteristic(this.platform.Characteristic.Name, 'Power'); + this.Humidity = useExternalSensor ? this.accessory.getService( + this.platform.Service.HumiditySensor) || this.accessory.addService(this.platform.Service.HumiditySensor) : null; + + this.HumidityBattery = useExternalSensor ? this.accessory.getService( + this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery) : null; + + if (this.Humidity) { + this.Humidity.setCharacteristic(this.platform.Characteristic.Name, 'Humidity Sensor'); + } + + if (this.HumidityBattery) { + this.HumidityBattery.setCharacteristic(this.platform.Characteristic.Name, 'Humidity Sensor Battery'); + this.HumidityBattery.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); + } + // create handlers for characteristics this.HeaterCooler.getCharacteristic(this.platform.Characteristic.Active) .on('get', this.handleActiveGet.bind(this)) @@ -147,6 +175,11 @@ export class KumoPlatformAccessory_ductless { // .on('get', this.handleDehumidiferActiveGet.bind(this)) // .on('set', this.handleDehumidiferActiveSet.bind(this)); + if (this.Humidity) { + this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity) + .on('get', this.handleHumidityGet.bind(this)); + } + this.updateDevice(); // setup interval for updating device for historyService @@ -239,6 +272,14 @@ export class KumoPlatformAccessory_ductless { callback(null, this.Dehumidifier.getCharacteristic(this.platform.Characteristic.On).value); } + async handleHumidityGet(callback) { + if (!this.Humidity) { + return; + } + await this.updateAccessoryCharacteristics(); + callback(null, this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).value); + } + async updateAccessoryCharacteristics() { // updateAccessoryCharacteristics @@ -259,6 +300,7 @@ export class KumoPlatformAccessory_ductless { this.updateFanSwingMode(); this.updatePowerSwitchOn(); this.updateDehumidifierSwitchOn(); + this.updateCurrentRelativeHumidity(); //this.platform.log.debug('updateAccessoryCharacteristic completed (%s)', this.accessory.context.serial) return true; @@ -306,12 +348,47 @@ export class KumoPlatformAccessory_ductless { return false; } this.platform.log.debug('%s (queryDevice_Direct): success.', this.accessory.displayName); + + if (this.Humidity) { + this.platform.log.debug('querying external sensors on %s', this.accessory.context.serial); + const sensorData = await this.platform.kumo.queryDeviceSensors_Direct(this.accessory.context.serial); + if (sensorData) { + this.accessory.context.sensors = sensorData; + } + } } // update device contect this.accessory.context.device = device; return true; - } + } + + private updateCurrentRelativeHumidity() { + if (!this.Humidity || !this.HumidityBattery) { + return; + } + let currentValue: number = this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).value; + if (this.accessory.context.sensors && this.accessory.context.sensors.length) { + const ourSensor = this.accessory.context.sensors[0]; + currentValue = ourSensor.humidity; + this.platform.log.debug('setting humidity to %s', currentValue); + + if (ourSensor.battery) { + if (ourSensor.battery < 10) { + this.platform.log.warn('!!!The sensor attached to device %s has a low battery!!!', this.accessory.context.serial) + + this.Humidity.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW); + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW); + } else { + this.Humidity.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); + } + + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.BatteryLevel, ourSensor.battery); + } + } + this.Humidity.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, currentValue); + } private updateHeaterCoolerActive() { // HeaterCooler Active diff --git a/src/ductless_simple.ts b/src/ductless_simple.ts index 0ec3ed0..0c5bd42 100755 --- a/src/ductless_simple.ts +++ b/src/ductless_simple.ts @@ -16,6 +16,8 @@ import { KUMO_LAG, KUMO_DEVICE_WAIT } from './settings'; */ export class KumoPlatformAccessory_ductless_simple { private HeaterCooler: Service; + private Humidity: Service | null; + private HumidityBattery: Service | null; private lastupdate; private lastquery; @@ -30,6 +32,16 @@ export class KumoPlatformAccessory_ductless_simple { ) { this.directAccess = this.platform.config.directAccess; + const useExternalSensor = this.directAccess && + this.accessory.context.device.activeThermistor !== undefined && + this.accessory.context.device.activeThermistor !== 'unset'; + + if (useExternalSensor) { + this.platform.log.info('device %s uses external sensor %s', + this.accessory.context.serial, + this.accessory.context.device.activeThermistor); + } + // set accessory information if (accessory.context.zoneTable.unitType !== undefined && accessory.context.zoneTable.unitType !== null) { const unitType: string = this.accessory.context.zoneTable.unitType; @@ -47,9 +59,24 @@ export class KumoPlatformAccessory_ductless_simple { this.HeaterCooler = this.accessory.getService( this.platform.Service.HeaterCooler) || this.accessory.addService(this.platform.Service.HeaterCooler); + this.Humidity = useExternalSensor ? this.accessory.getService( + this.platform.Service.HumiditySensor) || this.accessory.addService(this.platform.Service.HumiditySensor) : null; + + this.HumidityBattery = useExternalSensor ? this.accessory.getService( + this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery) : null; + // set sevice names. this.HeaterCooler.setCharacteristic(this.platform.Characteristic.Name, 'Heater/Cooler'); + if (this.Humidity) { + this.Humidity.setCharacteristic(this.platform.Characteristic.Name, 'Humidity Sensor'); + } + + if (this.HumidityBattery) { + this.HumidityBattery.setCharacteristic(this.platform.Characteristic.Name, 'Humidity Sensor Battery'); + this.HumidityBattery.setCharacteristic(this.platform.Characteristic.ChargingState, this.platform.Characteristic.ChargingState.NOT_CHARGEABLE); + } + // create handlers for characteristics this.HeaterCooler.getCharacteristic(this.platform.Characteristic.Active) .on('get', this.handleActiveGet.bind(this)) @@ -79,6 +106,11 @@ export class KumoPlatformAccessory_ductless_simple { this.HeaterCooler.getCharacteristic(this.platform.Characteristic.SwingMode) .on('set', this.handleFanSwingModeSet.bind(this)); + if (this.Humidity) { + this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity) + .on('get', this.handleHumidityGet.bind(this)); + } + this.updateDevice(); // setup interval for updating device for historyService @@ -138,6 +170,14 @@ export class KumoPlatformAccessory_ductless_simple { callback(null, this.HeaterCooler.getCharacteristic(this.platform.Characteristic.SwingMode).value); } + async handleHumidityGet(callback) { + if (!this.Humidity) { + return; + } + await this.updateAccessoryCharacteristics(); + callback(null, this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).value); + } + async updateAccessoryCharacteristics() { // updateAccessoryCharacteristics @@ -155,6 +195,7 @@ export class KumoPlatformAccessory_ductless_simple { this.updateCurrentTemperature(); this.updateFanRotationSpeed(); this.updateFanSwingMode(); + this.updateCurrentRelativeHumidity(); //this.platform.log.debug('updateAccessoryCharacteristic completed (%s)', this.accessory.context.serial) return true; @@ -202,6 +243,15 @@ export class KumoPlatformAccessory_ductless_simple { return false; } this.platform.log.debug('%s (queryDevice_Direct): success.'); + + if (this.Humidity) { + this.platform.log.debug('querying external sensors on %s', this.accessory.context.serial); + const sensorData = await this.platform.kumo.queryDeviceSensors_Direct(this.accessory.context.serial); + if (sensorData) { + this.accessory.context.sensors = sensorData; + } + } + } // update device contect @@ -316,6 +366,33 @@ export class KumoPlatformAccessory_ductless_simple { temp: currentValue, }); } + + private updateCurrentRelativeHumidity() { + if (!this.Humidity || !this.HumidityBattery) { + return; + } + let currentValue: number = this.Humidity.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity).value; + if (this.accessory.context.sensors && this.accessory.context.sensors.length) { + const ourSensor = this.accessory.context.sensors[0]; + currentValue = ourSensor.humidity; + this.platform.log.debug('setting humidity to %s', currentValue); + + if (ourSensor.battery) { + if (ourSensor.battery < 10) { + this.platform.log.warn('!!!The sensor attached to device %s has a low battery!!!', this.accessory.context.serial) + + this.Humidity.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW); + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW); + } else { + this.Humidity.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); + } + + this.HumidityBattery.updateCharacteristic(this.platform.Characteristic.BatteryLevel, ourSensor.battery); + } + } + this.Humidity.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, currentValue); + } private updateFanRotationSpeed() { // FanRotationSpeed diff --git a/src/kumo-api.ts b/src/kumo-api.ts index 7f0f0cd..217022f 100644 --- a/src/kumo-api.ts +++ b/src/kumo-api.ts @@ -63,6 +63,13 @@ interface KumoDeviceDirectInterface { vaneDir: string, } +interface KumoSensorData { + battery: number; + humidity: number; + temperature: number; + uuid: string; +} + export type KumoDeviceDirect = Readonly; // Renew Kumo security credentials every so often, in hours. @@ -354,7 +361,7 @@ export class KumoApi { return true; } - // querying sensors (not implemented as not available to test) + // querying sensors async queryDeviceSensors_Direct(serial: string) { const data = await this.directRequest('{"c":{"sensors":{}}}', serial); if(!data){ @@ -362,14 +369,13 @@ export class KumoApi { } this.log.debug(util.inspect(data, { colors: true, sorted: true, depth: 3 })); - const deviceSensors = [] as any; + const deviceSensors = [] as KumoSensorData[]; try { const sensors = data.r.sensors; for(const sensor in sensors) { if(sensors[sensor].uuid !== null && sensors[sensor].uuid !== undefined) { this.log.debug('Found sensor.uuid: %s', sensors[sensor].uuid); - const uuid:string = sensors[sensor].uuid; - deviceSensors.push(uuid); + deviceSensors.push(sensors[sensor]); } } diff --git a/src/platform.ts b/src/platform.ts index 50c7f2b..896ad12 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -203,7 +203,7 @@ export class KumoHomebridgePlatform implements DynamicPlatformPlugin { if(this.config.simpleDuctless) { new KumoPlatformAccessory_ductless_simple(this, accessory); } else { - new KumoPlatformAccessory_ductless(this, accessory); + new KumoPlatformAccessory_ductless(this, accessory); } } else { this.log.info('Initializing "%s" of unitType "%s" as generic (unspecified) unit.',