diff --git a/src/accessory/SwitchAccessory.ts b/src/accessory/SwitchAccessory.ts index c13d2a3b..04dfd7e2 100644 --- a/src/accessory/SwitchAccessory.ts +++ b/src/accessory/SwitchAccessory.ts @@ -1,9 +1,13 @@ import { TuyaDeviceSchema, TuyaDeviceSchemaType } from '../device/TuyaDevice'; import BaseAccessory from './BaseAccessory'; import { configureOn } from './characteristic/On'; +import { configureEnergyUsage } from './characteristic/EnergyUsage'; const SCHEMA_CODE = { - ON: ['switch', 'switch_1'], + ON: ['switch', 'switch_1'], // switch_2, switch_3, switch_4, ..., switch_usb1, switch_usb2, switch_usb3, ..., switch_backlight + CURRENT: ['cur_current'], + POWER: ['cur_power'], + VOLTAGE: ['cur_voltage'], }; export default class SwitchAccessory extends BaseAccessory { @@ -20,11 +24,14 @@ export default class SwitchAccessory extends BaseAccessory { this.accessory.removeService(oldService); } - const schema = this.device.schema.filter((schema) => schema.code.startsWith('switch') && schema.type === TuyaDeviceSchemaType.Boolean); - for (const _schema of schema) { - const name = (schema.length === 1) ? this.device.name : _schema.code; - this.configureSwitch(_schema, name); - } + const schemata = this.device.schema.filter( + (schema) => schema.code.startsWith('switch') && schema.type === TuyaDeviceSchemaType.Boolean, + ); + + schemata.forEach((schema) => { + const name = (schemata.length === 1) ? this.device.name : schema.code; + this.configureSwitch(schema, name); + }); } @@ -44,6 +51,17 @@ export default class SwitchAccessory extends BaseAccessory { } configureOn(this, service, schema); + + if (schema.code === this.getSchema(...SCHEMA_CODE.ON)?.code) { + configureEnergyUsage( + this.platform.api, + this, + service, + this.getSchema(...SCHEMA_CODE.CURRENT), + this.getSchema(...SCHEMA_CODE.POWER), + this.getSchema(...SCHEMA_CODE.VOLTAGE), + ); + } } } diff --git a/src/accessory/characteristic/EnergyUsage.ts b/src/accessory/characteristic/EnergyUsage.ts new file mode 100644 index 00000000..3fc8d633 --- /dev/null +++ b/src/accessory/characteristic/EnergyUsage.ts @@ -0,0 +1,103 @@ +import BaseAccessory from '../BaseAccessory'; +import { API, Service } from 'homebridge'; +import { TuyaDeviceSchema, TuyaDeviceSchemaIntegerProperty } from '../../device/TuyaDevice'; +import OverridedBaseAccessory from '../BaseAccessory'; + +export function configureEnergyUsage( + api: API, + accessory: OverridedBaseAccessory, + service: Service, + currentSchema?: TuyaDeviceSchema, + powerSchema?: TuyaDeviceSchema, + voltageSchema?: TuyaDeviceSchema, +) { + + if (currentSchema) { + if (isUnit(currentSchema, 'A', 'mA')) { + const amperes = createAmperesCharacteristic(api); + if (!service.testCharacteristic(amperes)) { + service.addCharacteristic(amperes).onGet( + createStatusGetter(accessory, currentSchema.code, isUnit(currentSchema, 'mA') ? 1000 : 0), + ); + } + } else { + accessory.log.warn('Unsupported current unit %p', currentSchema); + } + } + + if (powerSchema) { + if (isUnit(powerSchema, 'W')) { + const watts = createWattsCharacteristic(api); + if (!service.testCharacteristic(watts)) { + service.addCharacteristic(watts).onGet(createStatusGetter(accessory, powerSchema.code)); + } + } else { + accessory.log.warn('Unsupported power unit %p', currentSchema); + } + } + + if (voltageSchema) { + if (isUnit(voltageSchema, 'V')) { + const volts = createVoltsCharacteristic(api); + if (!service.testCharacteristic(volts)) { + service.addCharacteristic(volts).onGet(createStatusGetter(accessory, voltageSchema.code)); + } + } else { + accessory.log.warn('Unsupported voltage unit %p', currentSchema); + } + } +} + +function isUnit(schema: TuyaDeviceSchema, ...units: string[]): boolean { + return units.includes((schema.property as TuyaDeviceSchemaIntegerProperty).unit); +} + +function createStatusGetter(accessory: BaseAccessory, code: string, divisor = 1): () => number { + return () => { + const status = accessory.getStatus(code)!; + + return (status.value as number) / divisor; + }; +} + +function createAmperesCharacteristic(api: API) { + return class Amperes extends api.hap.Characteristic { + static readonly UUID = 'E863F126-079E-48FF-8F27-9C2605A29F52'; + + constructor() { + super('Amperes', Amperes.UUID, { + format: api.hap.Formats.FLOAT, + perms: [api.hap.Perms.NOTIFY, api.hap.Perms.PAIRED_READ], + unit: 'A', + }); + } + }; +} + +function createWattsCharacteristic(api: API) { + return class Watts extends api.hap.Characteristic { + static readonly UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; + + constructor() { + super('Consumption', Watts.UUID, { + format: api.hap.Formats.FLOAT, + perms: [api.hap.Perms.NOTIFY, api.hap.Perms.PAIRED_READ], + unit: 'W', + }); + } + }; +} + +function createVoltsCharacteristic(api: API) { + return class Volts extends api.hap.Characteristic { + static readonly UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52'; + + constructor() { + super('Volts', Volts.UUID, { + format: api.hap.Formats.FLOAT, + perms: [api.hap.Perms.NOTIFY, api.hap.Perms.PAIRED_READ], + unit: 'V', + }); + } + }; +}