From b9028842aa70b3e57f76f87aaac7939ae1185cae Mon Sep 17 00:00:00 2001 From: Luca Ponzanelli Date: Sun, 3 Sep 2023 12:36:49 +0200 Subject: [PATCH 1/2] - add support for optional capabilities in capabilityMap - switches for fan oscillation and optional mode are added only if supported in device's capabilitie --- README.md | 3 +++ package-lock.json | 4 ++-- package.json | 4 ++-- src/multiServiceAccessory.ts | 17 ++++++++++++----- src/services/airConditionerService.ts | 27 ++++++++++++++++++--------- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 05d8496..ef0e201 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ This is a smartthings plugin for Homebridge. This requires no access to the legacy smartthings app, and doesn't require a lot of work to install. It will discover devices automatically as well as unregister devices that are removed from your smarttthings network. This is currently under development. +## New in version 1.5.15 +* Support for optional capaiblities declaration +* AirConditionerService adds fan oscillation switch and optional mode switch only if supported by device's capabilitites ## New in version 1.5.14 * Support for air conditioners optional modes (i.e., Sleep, Speed, WindFree, WindFreeSleep) * Stop logging warning if battery is low diff --git a/package-lock.json b/package-lock.json index 2c8516f..4d3ce05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-smartthings-ik", - "version": "1.5.14", + "version": "1.5.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-smartthings-ik", - "version": "1.5.14", + "version": "1.5.15", "funding": [ { "type": "paypal", diff --git a/package.json b/package.json index 0396342..50f0c81 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": false, "displayName": "SmartThings Plugin", "name": "homebridge-smartthings-ik", - "version": "1.5.14", + "version": "1.5.15", "description": "Connects SmartThings devices to Homebridge. Automatically discovers devices.", "license": "Apache-2.0", "repository": { @@ -51,4 +51,4 @@ "url": "https://venmo.com/?txn=pay&audience=public&recipients=ira-klein-3" } ] -} +} \ No newline at end of file diff --git a/src/multiServiceAccessory.ts b/src/multiServiceAccessory.ts index 482bae0..6228af9 100644 --- a/src/multiServiceAccessory.ts +++ b/src/multiServiceAccessory.ts @@ -81,9 +81,11 @@ export class MultiServiceAccessory { 'switch', 'airConditionerMode', 'airConditionerFanMode', - 'fanOscillationMode', 'thermostatCoolingSetpoint', 'temperatureMeasurement', + ], + optionalCapabilities: [ + 'fanOscillationMode', 'relativeHumidityMeasurement', 'custom.airConditionerOptionalMode', ], @@ -200,6 +202,7 @@ export class MultiServiceAccessory { component: any, capabilitiesToCover: string[], capabilities: string[], + optionalCapabilities: string[], serviceConstructor: any, ): string[] { // this.log.debug(`Testing ${serviceConstructor.name} for capabilities ${capabilitiesToCover}`); @@ -209,13 +212,15 @@ export class MultiServiceAccessory { return capabilitiesToCover; } - this.log.debug(`Creating instance of ${serviceConstructor.name} for capabilities ${capabilities}`); - const serviceInstance = new serviceConstructor(this.platform, this.accessory, componentId, capabilities, this, this.name, component); + const allCapabilities = capabilities.concat(optionalCapabilities.filter(e => capabilitiesToCover.includes(e))) + + this.log.debug(`Creating instance of ${serviceConstructor.name} for capabilities ${allCapabilities}`); + const serviceInstance = new serviceConstructor(this.platform, this.accessory, componentId, allCapabilities, this, this.name, component); this.services.push(serviceInstance); - this.log.debug(`Registered ${serviceConstructor.name} for capabilities ${capabilities}`); + this.log.debug(`Registered ${serviceConstructor.name} for capabilities ${allCapabilities}`); // remove covered capabilities and return unused - return capabilitiesToCover.filter(e => !capabilities.includes(e)); + return capabilitiesToCover.filter(e => !allCapabilities.includes(e)); } public addComponent(componentId: string, capabilities: string[]) { @@ -239,6 +244,7 @@ export class MultiServiceAccessory { component, capabilitiesToCover, entry.capabilities, + entry.optionalCapabilities || [], entry.service, ); }); @@ -250,6 +256,7 @@ export class MultiServiceAccessory { component, capabilitiesToCover, [capability], + [], service, ); }); diff --git a/src/services/airConditionerService.ts b/src/services/airConditionerService.ts index 50a6037..ee40f75 100644 --- a/src/services/airConditionerService.ts +++ b/src/services/airConditionerService.ts @@ -68,19 +68,26 @@ export class AirConditionerService extends BaseService { this.fanService = this.setupFan(platform, multiServiceAccessory); // Exposing this sensor is optional since some Samsung air conditioner always report 0 as relative humidity level - if (this.platform.config.ExposeHumiditySensorForAirConditioners) { + // or the device might not support it + if (this.isCapabilitySupported('relativeHumidityMeasurement') && this.platform.config.ExposeHumiditySensorForAirConditioners) { this.humidityService = this.setupHumiditySensor(platform, multiServiceAccessory); } - this.optionalMode = OptionalMode[this.platform.config.OptionalModeForAirConditioners]; - // Expose a switch for the optional mode. - // If the selected optional mode is undefined or not supported, changes to the switch will have no effect. - this.optionalModeSwitchService = this.setupOptionalModeSwitch(platform, multiServiceAccessory); + // Optional mode switch is exposed only if the related capability is suppoorted + if (this.isCapabilitySupported('custom.airConditionerOptionalMode')) { + this.optionalMode = OptionalMode[this.platform.config.OptionalModeForAirConditioners]; - } + // Expose a switch for the optional mode. + // If the selected optional mode is undefined or not supported, changes to the switch will have no effect. + this.optionalModeSwitchService = this.setupOptionalModeSwitch(platform, multiServiceAccessory); + } + } + private isCapabilitySupported(capability): boolean { + return this.capabilities.find(c => c === capability) != undefined; + } private setupThermostat(platform: IKHomeBridgeHomebridgePlatform, multiServiceAccessory: MultiServiceAccessory): Service { this.log.debug(`Expose Thermostat for ${this.name}`); @@ -126,9 +133,11 @@ export class AirConditionerService extends BaseService { .onGet(this.getSwitchState.bind(this)) .onSet(this.setSwitchState.bind(this)); - this.service.getCharacteristic(platform.Characteristic.SwingMode) - .onGet(this.getSwingMode.bind(this)) - .onSet(this.setSwingMode.bind(this)); + if (this.isCapabilitySupported('fanOscillationMode')) { + this.service.getCharacteristic(platform.Characteristic.SwingMode) + .onGet(this.getSwingMode.bind(this)) + .onSet(this.setSwingMode.bind(this)); + } this.service.getCharacteristic(platform.Characteristic.RotationSpeed) .onSet(this.setFanLevel.bind(this)) From 851418f5bcbaa9969e7078c1a8281748729cb0f8 Mon Sep 17 00:00:00 2001 From: Luca Ponzanelli Date: Sun, 3 Sep 2023 13:04:10 +0200 Subject: [PATCH 2/2] fix lint issues --- src/multiServiceAccessory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multiServiceAccessory.ts b/src/multiServiceAccessory.ts index 6228af9..091ec27 100644 --- a/src/multiServiceAccessory.ts +++ b/src/multiServiceAccessory.ts @@ -212,7 +212,7 @@ export class MultiServiceAccessory { return capabilitiesToCover; } - const allCapabilities = capabilities.concat(optionalCapabilities.filter(e => capabilitiesToCover.includes(e))) + const allCapabilities = capabilities.concat(optionalCapabilities.filter(e => capabilitiesToCover.includes(e))); this.log.debug(`Creating instance of ${serviceConstructor.name} for capabilities ${allCapabilities}`); const serviceInstance = new serviceConstructor(this.platform, this.accessory, componentId, allCapabilities, this, this.name, component);