diff --git a/README.md b/README.md index e144526..561db7e 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ The `defaults` has these properties: - `id` The name or id for the device that is registered in the Android/iOS App. When matching on ID please provide the `Tuya ID` as shown during Homebridge boot. - `device_type` The `device_type` to be overruled. This can be useful for dimmers that are reported as `light` by the Tuya API and don't support hue and saturation or for outlets that are reported as `switch`. +- `max_brightness` The maximum value of your dimmer light brightness. To get this, turn your dimmer/light to 100% brightness via the Tuya App. Next open your HomeKit app. Lastly view your HomeBridge logs, once the accessories load you can view the output and see the current value of each light. Something along the lines of `Characteristic.Brightness - [GET] 255` should be shown - in which case you want to set the numerical value of that log entry to the `max_brightness` value. > Note: After overriding the device type, it might appear duplicated in both HomeBridge (Accessories Tab) and the Home App. To solve this issue, go to the Homebridge settings (top right corner) and remove the device using the `Remove Single Cached Accessory` option. diff --git a/config.schema.json b/config.schema.json index 82a6a4a..ca219dc 100644 --- a/config.schema.json +++ b/config.schema.json @@ -131,6 +131,18 @@ ], "required": true }, + "max_brightness": { + "title": "Device max brightness", + "type": "number", + "default": 255, + "description": "Dimmer lights might have different maximum value, find it and set it here" + }, + "min_brightness": { + "title": "Device min brightness", + "type": "number", + "default": 1, + "description": "Dimmer lights might have different minimum value, find it and set it here" + }, "min_temper": { "title": "Minimal Temperature", "type": "string", @@ -260,6 +272,18 @@ { "key": "defaults[].id" }, + { + "key": "defaults[].max_brightness", + "condition": { + "functionBody": "return (model.defaults[arrayIndices].device_type == 'dimmer')" + } + }, + { + "key": "defaults[].min_brightness", + "condition": { + "functionBody": "return (model.defaults[arrayIndices].device_type == 'dimmer')" + } + }, { "key": "defaults[].device_type" }, diff --git a/src/accessories/DimmerAccessory.ts b/src/accessories/DimmerAccessory.ts index e94ed33..1a01c03 100644 --- a/src/accessories/DimmerAccessory.ts +++ b/src/accessories/DimmerAccessory.ts @@ -7,6 +7,7 @@ import { OnCharacteristic, } from "./characteristics"; import { TuyaDevice } from "../api/response"; +import { TuyaDeviceDefaults } from "../config"; export class DimmerAccessory extends BaseAccessory { constructor( @@ -42,4 +43,46 @@ export class DimmerAccessory extends BaseAccessory { return super.deviceSupportedCharacteristics; } + + public get maxBrightness(): number { + if (this.deviceConfig.config?.max_brightness) { + return this.deviceConfig.config.max_brightness; + } + + return 255; + } + + public get minBrightness(): number { + if (this.deviceConfig.config?.min_brightness) { + return this.deviceConfig.config.min_brightness; + } + + return 1; + } + + validateConfigOverwrites(config: TuyaDeviceDefaults): string[] { + const errors = super.validateConfigOverwrites(config); + if (config?.max_brightness) { + const maxBrightness = Number(config.max_brightness); + if (!maxBrightness) { + errors.push( + "Wrong value configured for `max_brightness`, should be a number" + ); + } else { + config.max_brightness = maxBrightness; + } + } + + if (config?.min_brightness) { + const minBrightness = Number(config.min_brightness); + if (!minBrightness) { + errors.push( + "Wrong value configured for `min_brightness`, should be a number" + ); + } else { + config.min_brightness = minBrightness; + } + } + return errors; + } } diff --git a/src/accessories/characteristics/brightness.ts b/src/accessories/characteristics/brightness.ts index 8bb9afe..df95ead 100644 --- a/src/accessories/characteristics/brightness.ts +++ b/src/accessories/characteristics/brightness.ts @@ -8,6 +8,7 @@ import { inspect } from "util"; import { TuyaWebCharacteristic } from "./base"; import { BaseAccessory } from "../BaseAccessory"; import { DeviceState } from "../../api/response"; +import { DimmerAccessory } from "../DimmerAccessory"; export class BrightnessCharacteristic extends TuyaWebCharacteristic { public static Title = "Characteristic.Brightness"; @@ -41,7 +42,13 @@ export class BrightnessCharacteristic extends TuyaWebCharacteristic { callback: CharacteristicSetCallback ): void { // Set device state in Tuya Web API - const value = ((homekitValue as number) / 10) * 9 + 10; + const dimmerPercentage = (homekitValue as number) / 100; + const correctionFactor = 10; + const value = Math.round( + (100 - correctionFactor) * dimmerPercentage + + correctionFactor + + Number.EPSILON + ); this.accessory .setDeviceState("brightnessSet", { value }, { brightness: homekitValue }) @@ -63,7 +70,11 @@ export class BrightnessCharacteristic extends TuyaWebCharacteristic { ) { stateValue = Number(data.color.brightness); } else if (data?.brightness) { - stateValue = Math.round((Number(data.brightness) / 255) * 100); + const maxBrightness = (this.accessory as DimmerAccessory).maxBrightness; + const brightness = Number(data.brightness); + stateValue = Math.round( + (brightness / maxBrightness) * 100 + Number.EPSILON + ); } if (stateValue) { diff --git a/src/api/response.ts b/src/api/response.ts index ec9e800..6332f90 100644 --- a/src/api/response.ts +++ b/src/api/response.ts @@ -22,6 +22,8 @@ type TuyaProperties = Partial<{ type CustomProperties = Partial<{ target_cover_state: CoverState; + max_brightness: number; + min_brightness: number; }>; export type DeviceState = TuyaProperties & CustomProperties; diff --git a/src/config.ts b/src/config.ts index b2235a2..df8777f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -5,6 +5,8 @@ import { TuyaDeviceType } from "./api/response"; export type TuyaDeviceDefaults = { id: string; device_type: TuyaDeviceType; + max_brightness: number; + min_brightness: number; min_temper: string | number; max_temper: string | number; current_temperature_factor: string | number;