diff --git a/src/devices/ikea.ts b/src/devices/ikea.ts index b91b07a64176b..ffd1a14a50ff0 100644 --- a/src/devices/ikea.ts +++ b/src/devices/ikea.ts @@ -1,10 +1,10 @@ +import {Zcl} from 'zigbee-herdsman'; import {Definition} from '../lib/types'; -import dataType from 'zigbee-herdsman/dist/zcl/definition/dataType'; import { onOff, battery, iasZoneAlarm, identify, forcePowerSource, temperature, humidity, occupancy, illuminance, windowCovering, commandsOnOff, commandsLevelCtrl, commandsWindowCovering, pm25, - linkQuality, deviceEndpoints, bindCluster, + linkQuality, deviceEndpoints, deviceAddCustomCluster, bindCluster, } from '../lib/modernExtend'; import { ikeaConfigureRemote, ikeaLight, ikeaOta, @@ -940,13 +940,20 @@ const definitions: Definition[] = [ vendor: 'IKEA', description: 'VINDSTYRKA air quality and humidity sensor', extend: [ + deviceAddCustomCluster( + 'pm25Measurement', + { + ID: 0x042a, + attributes: { + measuredValue: {ID: 0x0000, type: Zcl.DataType.singlePrec}, + }, + commands: {}, + commandsResponse: {}, + }, + ), temperature(), humidity(), - pm25({ - // IKEA used conflicting date type on a standart attribute - attribute: {ID: 0x0000, type: dataType.singlePrec}, - reporting: {min: '1_MINUTE', max: '2_MINUTES', change: 2}, - }), + pm25({reporting: {min: '1_MINUTE', max: '2_MINUTES', change: 2}}), ikeaVoc(), identify(), ikeaOta(), diff --git a/src/devices/sonoff.ts b/src/devices/sonoff.ts index a5b8d228487d7..acd9ceed7d4da 100644 --- a/src/devices/sonoff.ts +++ b/src/devices/sonoff.ts @@ -4,7 +4,10 @@ import fz from '../converters/fromZigbee'; import tz from '../converters/toZigbee'; import * as constants from '../lib/constants'; import * as reporting from '../lib/reporting'; -import {binary, enumLookup, forcePowerSource, numeric, onOff, customTimeResponse, battery, ota} from '../lib/modernExtend'; +import { + binary, enumLookup, forcePowerSource, numeric, onOff, + customTimeResponse, battery, ota, deviceAddCustomCluster, +} from '../lib/modernExtend'; import {Definition, Fz, KeyValue, KeyValueAny, ModernExtend, Tz} from '../lib/types'; import * as utils from '../lib/utils'; import {logger} from '../lib/logger'; @@ -803,6 +806,28 @@ const definitions: Definition[] = [ tz.thermostat_running_state, ], extend: [ + deviceAddCustomCluster( + 'customSonoffTrvzb', + { + ID: 0xfc11, + attributes: { + childLock: {ID: 0x0000, type: Zcl.DataType.boolean}, + tamper: {ID: 0x2000, type: Zcl.DataType.uint8}, + illumination: {ID: 0x2001, type: Zcl.DataType.uint8}, + openWindow: {ID: 0x6000, type: Zcl.DataType.boolean}, + frostProtectionTemperature: {ID: 0x6002, type: Zcl.DataType.int16}, + idleSteps: {ID: 0x6003, type: Zcl.DataType.uint16}, + closingSteps: {ID: 0x6004, type: Zcl.DataType.uint16}, + valveOpeningLimitVoltage: {ID: 0x6005, type: Zcl.DataType.uint16}, + valveClosingLimitVoltage: {ID: 0x6006, type: Zcl.DataType.uint16}, + valveMotorRunningVoltage: {ID: 0x6007, type: Zcl.DataType.uint16}, + valveOpeningDegree: {ID: 0x600B, type: Zcl.DataType.uint8}, + valveClosingDegree: {ID: 0x600C, type: Zcl.DataType.uint8}, + }, + commands: {}, + commandsResponse: {}, + }, + ), binary({ name: 'child_lock', cluster: 'customSonoffTrvzb', @@ -910,30 +935,6 @@ const definitions: Definition[] = [ await endpoint.read('hvacThermostat', ['localTemperatureCalibration']); await endpoint.read(0xFC11, [0x0000, 0x6000, 0x6002, 0x6003, 0x6004, 0x6005, 0x6006, 0x6007]); }, - onEvent: async (type, data, device, settings, state) => { - const name = 'customSonoffTrvzb'; - if (!device.customClusters[name]) { - device.addCustomCluster(name, { - ID: 0xfc11, - attributes: { - childLock: {ID: 0x0000, type: Zcl.DataType.boolean}, - tamper: {ID: 0x2000, type: Zcl.DataType.uint8}, - illumination: {ID: 0x2001, type: Zcl.DataType.uint8}, - openWindow: {ID: 0x6000, type: Zcl.DataType.boolean}, - frostProtectionTemperature: {ID: 0x6002, type: Zcl.DataType.int16}, - idleSteps: {ID: 0x6003, type: Zcl.DataType.uint16}, - closingSteps: {ID: 0x6004, type: Zcl.DataType.uint16}, - valveOpeningLimitVoltage: {ID: 0x6005, type: Zcl.DataType.uint16}, - valveClosingLimitVoltage: {ID: 0x6006, type: Zcl.DataType.uint16}, - valveMotorRunningVoltage: {ID: 0x6007, type: Zcl.DataType.uint16}, - valveOpeningDegree: {ID: 0x600B, type: Zcl.DataType.uint8}, - valveClosingDegree: {ID: 0x600C, type: Zcl.DataType.uint8}, - }, - commands: {}, - commandsResponse: {}, - }); - } - }, }, { zigbeeModel: ['S60ZBTPF'], diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index cce904b7c8048..25d703c0c358d 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -1,4 +1,5 @@ import {Zcl} from 'zigbee-herdsman'; +import {ClusterDefinition} from 'zigbee-herdsman/dist/zcl/definition/tstype'; import tz from '../converters/toZigbee'; import fz from '../converters/fromZigbee'; import * as globalLegacy from '../lib/legacy'; @@ -1669,6 +1670,16 @@ export function deviceEndpoints(args: {endpoints: {[n: string]: number}, multiEn return result; } +export function deviceAddCustomCluster(clusterName: string, clusterDefinition: ClusterDefinition): ModernExtend { + const onEvent: OnEvent = async (type, data, device, options, state: KeyValue) => { + if (!device.customClusters[clusterName]) { + device.addCustomCluster(clusterName, clusterDefinition); + } + }; + + return {onEvent, isModernExtend: true}; +} + export function ignoreClusterReport(args: {cluster: string | number}): ModernExtend { const fromZigbee: Fz.Converter[] = [{ cluster: args.cluster.toString(),