From 7d09ad84a01b1f6f07363f705e52967899afb5cc Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Tue, 22 Nov 2022 22:04:07 +0100 Subject: [PATCH 1/3] Fix switch accessory & add support for Smart IR (wnykq) --- src/accessory/AccessoryFactory.ts | 1 + src/accessory/SwitchAccessory.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/accessory/AccessoryFactory.ts b/src/accessory/AccessoryFactory.ts index 040a5661..0876075b 100644 --- a/src/accessory/AccessoryFactory.ts +++ b/src/accessory/AccessoryFactory.ts @@ -104,6 +104,7 @@ export default class AccessoryFactory { case 'co2bj': handler = new CarbonDioxideSensorAccessory(platform, accessory); break; + case 'wnykq': case 'wsdcg': handler = new TemperatureHumiditySensorAccessory(platform, accessory); break; diff --git a/src/accessory/SwitchAccessory.ts b/src/accessory/SwitchAccessory.ts index 6ec6c47a..d0793f9b 100644 --- a/src/accessory/SwitchAccessory.ts +++ b/src/accessory/SwitchAccessory.ts @@ -21,7 +21,7 @@ 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); + 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); From 0a51077759a7dc4b17acd814c63a3271838020a5 Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Tue, 22 Nov 2022 22:20:40 +0100 Subject: [PATCH 2/3] Run eslint --fix and fix bug with error in JSON.parse --- src/device/TuyaDeviceManager.ts | 15 +++++++++++---- src/platform.ts | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/device/TuyaDeviceManager.ts b/src/device/TuyaDeviceManager.ts index ac7f9ade..fb02793d 100644 --- a/src/device/TuyaDeviceManager.ts +++ b/src/device/TuyaDeviceManager.ts @@ -2,7 +2,9 @@ import EventEmitter from 'events'; import TuyaOpenAPI from '../core/TuyaOpenAPI'; import TuyaOpenMQ from '../core/TuyaOpenMQ'; import Logger, { PrefixLogger } from '../util/Logger'; -import TuyaDevice, { TuyaDeviceSchema, TuyaDeviceSchemaMode, TuyaDeviceSchemaProperty, TuyaDeviceStatus } from './TuyaDevice'; +import TuyaDevice, { + TuyaDeviceSchema, TuyaDeviceSchemaMode, TuyaDeviceSchemaProperty, TuyaDeviceSchemaType, TuyaDeviceStatus, +} from './TuyaDevice'; enum Events { DEVICE_ADD = 'DEVICE_ADD', @@ -91,10 +93,11 @@ export default class TuyaDeviceManager extends EventEmitter { // Combine functions and status together, as it used to be. const schemas = new Map(); - for (const { code, type, values } of [...res.result.status, ...res.result.functions]) { + for (const { code, type: rawType, values } of [...res.result.status, ...res.result.functions]) { if (schemas[code]) { continue; } + const type = rawType.charAt(0).toUpperCase() + rawType.slice(1).toLowerCase(); const read = (res.result.status).find(schema => schema.code === code) !== undefined; const write = (res.result.functions).find(schema => schema.code === code) !== undefined; let mode = TuyaDeviceSchemaMode.UNKNOWN; @@ -107,7 +110,11 @@ export default class TuyaDeviceManager extends EventEmitter { } let property: TuyaDeviceSchemaProperty; try { - property = JSON.parse(values); + if (type === TuyaDeviceSchemaType.String) { + property = values; + } else { + property = JSON.parse(values); + } schemas[code] = { code, mode, type, property }; } catch (error) { this.log.error(error); @@ -125,7 +132,7 @@ export default class TuyaDeviceManager extends EventEmitter { async onMQTTMessage(topic: string, protocol: TuyaMQTTProtocol, message) { - switch(protocol) { + switch (protocol) { case TuyaMQTTProtocol.DEVICE_STATUS_UPDATE: { const { devId, status } = message; const device = this.getDevice(devId); diff --git a/src/platform.ts b/src/platform.ts index e02c81e7..38155ba2 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -256,10 +256,10 @@ export class TuyaPlatform implements DynamicPlatformPlugin { this.log.info(`Got home_id=${home_id}, name=${name}`); if (this.options.homeWhitelist) { if (this.options.homeWhitelist.includes(home_id)) { - this.log.info(`Found home_id=${home_id} in whitelist; including devices from this home.`); - homeIDList.push(home_id); + this.log.info(`Found home_id=${home_id} in whitelist; including devices from this home.`); + homeIDList.push(home_id); } else { - this.log.info(`Did not find home_id=${home_id} in whitelist; excluding devices from this home.`); + this.log.info(`Did not find home_id=${home_id} in whitelist; excluding devices from this home.`); } } else { homeIDList.push(home_id); From dbb30071cc52eb9f1119e55a560c16fd81e8103c Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Thu, 24 Nov 2022 02:06:05 +0100 Subject: [PATCH 3/3] Add new temp sensor for IR devices and revert code for subdevices properties support --- package.json | 2 +- src/accessory/AccessoryFactory.ts | 3 ++ .../TemperatureHumidityIRSensorAccessory.ts | 23 +++++++++ .../TemperatureHumiditySensorAccessory.ts | 48 ++----------------- .../configureHumiditySensor.ts | 24 ++++++++++ .../configureTemperatureSensor.ts | 24 ++++++++++ src/device/TuyaDeviceManager.ts | 15 ++---- 7 files changed, 83 insertions(+), 56 deletions(-) create mode 100644 src/accessory/TemperatureHumidityIRSensorAccessory.ts create mode 100644 src/accessory/TemperatureHumiditySensorAccessory/configureHumiditySensor.ts create mode 100644 src/accessory/TemperatureHumiditySensorAccessory/configureTemperatureSensor.ts diff --git a/package.json b/package.json index 7869ea8b..ba672083 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "main": "dist/index.js", "scripts": { - "lint": "eslint src/**/**.ts --max-warnings=0", + "lint": "eslint src/**/*.ts --max-warnings=0", "test": "jest", "watch": "npm run build && npm link && nodemon", "build": "rimraf ./dist && tsc", diff --git a/src/accessory/AccessoryFactory.ts b/src/accessory/AccessoryFactory.ts index 0876075b..0ed47a02 100644 --- a/src/accessory/AccessoryFactory.ts +++ b/src/accessory/AccessoryFactory.ts @@ -26,6 +26,7 @@ import AirQualitySensorAccessory from './AirQualitySensorAccessory'; import HumanPresenceSensorAccessory from './HumanPresenceSensorAccessory'; import HumidifierAccessory from './HumidifierAccessory'; import AirPurifierAccessory from './AirPurifierAccessory'; +import TemperatureHumidityIRSensorAccessory from './TemperatureHumidityIRSensorAccessory'; export default class AccessoryFactory { @@ -105,6 +106,8 @@ export default class AccessoryFactory { handler = new CarbonDioxideSensorAccessory(platform, accessory); break; case 'wnykq': + handler = new TemperatureHumidityIRSensorAccessory(platform, accessory); + break; case 'wsdcg': handler = new TemperatureHumiditySensorAccessory(platform, accessory); break; diff --git a/src/accessory/TemperatureHumidityIRSensorAccessory.ts b/src/accessory/TemperatureHumidityIRSensorAccessory.ts new file mode 100644 index 00000000..eaa6b1e5 --- /dev/null +++ b/src/accessory/TemperatureHumidityIRSensorAccessory.ts @@ -0,0 +1,23 @@ +import { PlatformAccessory } from 'homebridge'; +import { TuyaPlatform } from '../platform'; +import BaseAccessory from './BaseAccessory'; +import { configureHumiditySensor } from './TemperatureHumiditySensorAccessory/configureHumiditySensor'; +import { configureTemperatureSensor } from './TemperatureHumiditySensorAccessory/configureTemperatureSensor'; + + +export default class TemperatureHumidityIRSensorAccessory extends BaseAccessory { + + constructor(platform: TuyaPlatform, accessory: PlatformAccessory) { + super(platform, accessory); + + configureTemperatureSensor(this); + configureHumiditySensor(this); + } + + requiredSchema() { + return []; + } + + + +} diff --git a/src/accessory/TemperatureHumiditySensorAccessory.ts b/src/accessory/TemperatureHumiditySensorAccessory.ts index d034df48..24efd395 100644 --- a/src/accessory/TemperatureHumiditySensorAccessory.ts +++ b/src/accessory/TemperatureHumiditySensorAccessory.ts @@ -1,8 +1,8 @@ import { PlatformAccessory } from 'homebridge'; -import { TuyaDeviceSchemaIntegerProperty } from '../device/TuyaDevice'; import { TuyaPlatform } from '../platform'; -import { limit } from '../util/util'; import BaseAccessory from './BaseAccessory'; +import { configureHumiditySensor } from './TemperatureHumiditySensorAccessory/configureHumiditySensor'; +import { configureTemperatureSensor } from './TemperatureHumiditySensorAccessory/configureTemperatureSensor'; const SCHEMA_CODE = { SENSOR_STATUS: ['va_temperature', 'va_humidity', 'humidity_value'], @@ -13,54 +13,14 @@ export default class TemperatureHumiditySensorAccessory extends BaseAccessory { constructor(platform: TuyaPlatform, accessory: PlatformAccessory) { super(platform, accessory); - this.configureTemperatureSensor(); - this.configureHumiditySensor(); + configureTemperatureSensor(this); + configureHumiditySensor(this); } requiredSchema() { return [SCHEMA_CODE.SENSOR_STATUS]; } - configureTemperatureSensor() { - const schema = this.getSchema('va_temperature'); - if (!schema) { - this.log.warn('TemperatureSensor not supported.'); - return; - } - const service = this.accessory.getService(this.Service.TemperatureSensor) - || this.accessory.addService(this.Service.TemperatureSensor); - - const property = schema.property as TuyaDeviceSchemaIntegerProperty; - const multiple = Math.pow(10, property ? property.scale : 0); - service.getCharacteristic(this.Characteristic.CurrentTemperature) - .onGet(() => { - const status = this.getStatus(schema.code)!; - // this.log.debug('CurrentTemperature:', 'property =', property, 'multiple =', multiple, 'status =', status); - return limit(status.value as number / multiple, -270, 100); - }); - - } - - configureHumiditySensor() { - const schema = this.getSchema('va_humidity', 'humidity_value'); - if (!schema) { - this.log.warn('HumiditySensor not supported.'); - return; - } - - const service = this.accessory.getService(this.Service.HumiditySensor) - || this.accessory.addService(this.Service.HumiditySensor); - - const property = schema.property as TuyaDeviceSchemaIntegerProperty; - const multiple = Math.pow(10, property ? property.scale : 0); - service.getCharacteristic(this.Characteristic.CurrentRelativeHumidity) - .onGet(() => { - const status = this.getStatus(schema.code)!; - // this.log.debug('CurrentRelativeHumidity:', 'property =', property, 'multiple =', multiple, 'status =', status); - return limit(status.value as number / multiple, 0, 100); - }); - - } } diff --git a/src/accessory/TemperatureHumiditySensorAccessory/configureHumiditySensor.ts b/src/accessory/TemperatureHumiditySensorAccessory/configureHumiditySensor.ts new file mode 100644 index 00000000..22e68fdc --- /dev/null +++ b/src/accessory/TemperatureHumiditySensorAccessory/configureHumiditySensor.ts @@ -0,0 +1,24 @@ +import { TuyaDeviceSchemaIntegerProperty } from '../../device/TuyaDevice'; +import { limit } from '../../util/util'; +import BaseAccessory from '../BaseAccessory'; + +export function configureHumiditySensor(accessory: BaseAccessory) { + const schema = accessory.getSchema('va_humidity', 'humidity_value'); + if (!schema) { + accessory.log.warn('HumiditySensor not supported.'); + return; + } + + const service = accessory.accessory.getService(accessory.Service.HumiditySensor) + || accessory.accessory.addService(accessory.Service.HumiditySensor); + + const property = schema.property as TuyaDeviceSchemaIntegerProperty; + const multiple = Math.pow(10, property ? property.scale : 0); + service.getCharacteristic(accessory.Characteristic.CurrentRelativeHumidity) + .onGet(() => { + const status = accessory.getStatus(schema.code)!; + // this.log.debug('CurrentRelativeHumidity:', 'property =', property, 'multiple =', multiple, 'status =', status); + return limit(status.value as number / multiple, 0, 100); + }); + +} \ No newline at end of file diff --git a/src/accessory/TemperatureHumiditySensorAccessory/configureTemperatureSensor.ts b/src/accessory/TemperatureHumiditySensorAccessory/configureTemperatureSensor.ts new file mode 100644 index 00000000..8df8a8b8 --- /dev/null +++ b/src/accessory/TemperatureHumiditySensorAccessory/configureTemperatureSensor.ts @@ -0,0 +1,24 @@ +import { TuyaDeviceSchemaIntegerProperty } from '../../device/TuyaDevice'; +import { limit } from '../../util/util'; +import BaseAccessory from '../BaseAccessory'; + +export function configureTemperatureSensor(accessory: BaseAccessory) { + const schema = accessory.getSchema('va_temperature'); + if (!schema) { + accessory.log.warn('TemperatureSensor not supported.'); + return; + } + + const service = accessory.accessory.getService(accessory.Service.TemperatureSensor) + || accessory.accessory.addService(accessory.Service.TemperatureSensor); + + const property = schema.property as TuyaDeviceSchemaIntegerProperty; + const multiple = Math.pow(10, property ? property.scale : 0); + service.getCharacteristic(accessory.Characteristic.CurrentTemperature) + .onGet(() => { + const status = accessory.getStatus(schema.code)!; + // accessory.log.debug('CurrentTemperature:', 'property =', property, 'multiple =', multiple, 'status =', status); + return limit(status.value as number / multiple, -270, 100); + }); + +} \ No newline at end of file diff --git a/src/device/TuyaDeviceManager.ts b/src/device/TuyaDeviceManager.ts index fb02793d..ac7f9ade 100644 --- a/src/device/TuyaDeviceManager.ts +++ b/src/device/TuyaDeviceManager.ts @@ -2,9 +2,7 @@ import EventEmitter from 'events'; import TuyaOpenAPI from '../core/TuyaOpenAPI'; import TuyaOpenMQ from '../core/TuyaOpenMQ'; import Logger, { PrefixLogger } from '../util/Logger'; -import TuyaDevice, { - TuyaDeviceSchema, TuyaDeviceSchemaMode, TuyaDeviceSchemaProperty, TuyaDeviceSchemaType, TuyaDeviceStatus, -} from './TuyaDevice'; +import TuyaDevice, { TuyaDeviceSchema, TuyaDeviceSchemaMode, TuyaDeviceSchemaProperty, TuyaDeviceStatus } from './TuyaDevice'; enum Events { DEVICE_ADD = 'DEVICE_ADD', @@ -93,11 +91,10 @@ export default class TuyaDeviceManager extends EventEmitter { // Combine functions and status together, as it used to be. const schemas = new Map(); - for (const { code, type: rawType, values } of [...res.result.status, ...res.result.functions]) { + for (const { code, type, values } of [...res.result.status, ...res.result.functions]) { if (schemas[code]) { continue; } - const type = rawType.charAt(0).toUpperCase() + rawType.slice(1).toLowerCase(); const read = (res.result.status).find(schema => schema.code === code) !== undefined; const write = (res.result.functions).find(schema => schema.code === code) !== undefined; let mode = TuyaDeviceSchemaMode.UNKNOWN; @@ -110,11 +107,7 @@ export default class TuyaDeviceManager extends EventEmitter { } let property: TuyaDeviceSchemaProperty; try { - if (type === TuyaDeviceSchemaType.String) { - property = values; - } else { - property = JSON.parse(values); - } + property = JSON.parse(values); schemas[code] = { code, mode, type, property }; } catch (error) { this.log.error(error); @@ -132,7 +125,7 @@ export default class TuyaDeviceManager extends EventEmitter { async onMQTTMessage(topic: string, protocol: TuyaMQTTProtocol, message) { - switch (protocol) { + switch(protocol) { case TuyaMQTTProtocol.DEVICE_STATUS_UPDATE: { const { devId, status } = message; const device = this.getDevice(devId);