diff --git a/drivers/radarLuminanceSensor/assets/distance.svg b/drivers/radarLuminanceSensor/assets/distance.svg new file mode 100644 index 0000000000..d277aa97d6 --- /dev/null +++ b/drivers/radarLuminanceSensor/assets/distance.svg @@ -0,0 +1,9 @@ + + + + no.tjweb.opengarage/capability/distance + Created with Sketch. + + + + diff --git a/drivers/radarLuminanceSensor/assets/icon.svg b/drivers/radarLuminanceSensor/assets/icon.svg new file mode 100644 index 0000000000..21dca2e848 --- /dev/null +++ b/drivers/radarLuminanceSensor/assets/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/drivers/radarLuminanceSensor/assets/images/large.png b/drivers/radarLuminanceSensor/assets/images/large.png new file mode 100644 index 0000000000..f185dd8f6c Binary files /dev/null and b/drivers/radarLuminanceSensor/assets/images/large.png differ diff --git a/drivers/radarLuminanceSensor/assets/images/small.png b/drivers/radarLuminanceSensor/assets/images/small.png new file mode 100644 index 0000000000..3d0416bdcb Binary files /dev/null and b/drivers/radarLuminanceSensor/assets/images/small.png differ diff --git a/drivers/radarLuminanceSensor/device.js b/drivers/radarLuminanceSensor/device.js new file mode 100644 index 0000000000..f8e2645ab4 --- /dev/null +++ b/drivers/radarLuminanceSensor/device.js @@ -0,0 +1,120 @@ +'use strict'; + +const { ZigBeeDevice } = require('homey-zigbeedriver'); +const { CLUSTER, Cluster, ZCLDataTypes, debug } = require('zigbee-clusters'); +const TuyaSpecificCluster = require('../../lib/TuyaSpecificCluster'); +const TuyaSpecificClusterDevice = require('../../lib/TuyaSpecificClusterDevice'); + +Cluster.addCluster(TuyaSpecificCluster); + +const dataPoints = { + tshpsPresenceState: 1, // OK + tshpscSensitivity: 2, // not sure + tshpsMinimumRange: 3, // might be correct + tshpsMaximumRange: 4, // might be correct + tshpsFadingTime: 102, // OK + tshpsIlluminanceLux: 106, // Works but is also reported according Zigbee standard + tshpsBatteryPercentage: 110 // Works but is also reported according Zigbee standard +} + +const dataTypes = { + raw: 0, // [ bytes ] + bool: 1, // [0/1] + value: 2, // [ 4 byte value ] + string: 3, // [ N byte string ] + enum: 4, // [ 0-255 ] + bitmap: 5, // [ 1,2,4 bytes ] as bits +}; + +const convertMultiByteNumberPayloadToSingleDecimalNumber = (chunks) => { + let value = 0; + + for (let i = 0; i < chunks.length; i++) { + value = value << 8; + value += chunks[i]; + } + + return value; +}; + +const getDataValue = (dpValue) => { + switch (dpValue.datatype) { + case dataTypes.raw: + return dpValue.data; + case dataTypes.bool: + return dpValue.data[0] === 1; + case dataTypes.value: + return convertMultiByteNumberPayloadToSingleDecimalNumber(dpValue.data); + case dataTypes.string: + let dataString = ''; + for (let i = 0; i < dpValue.data.length; ++i) { + dataString += String.fromCharCode(dpValue.data[i]); + } + return dataString; + case dataTypes.enum: + return dpValue.data[0]; + case dataTypes.bitmap: + return convertMultiByteNumberPayloadToSingleDecimalNumber(dpValue.data); + } +} + +class radarLuminanceSensor extends TuyaSpecificClusterDevice { + async onNodeInit({zclNode}) { + this.printNode(); + + // Standaard capabilities + this.registerCapability('measure_luminance', CLUSTER.ILLUMINANCE_MEASUREMENT); + this.registerCapability('measure_battery', CLUSTER.POWER_CONFIGURATION); + // Tuya specific datapoint handling + zclNode.endpoints[1].clusters.tuya.on("response", value => this.updatePosition(value)); + } + + async updatePosition(data) { + const dp = data.dp; + const value = getDataValue(data); + + switch (dp) { + case dataPoints.tshpsPresenceState: + this.log("presence state: "+ value) + this.setCapabilityValue('alarm_motion', Boolean(value)) + break; + case dataPoints.tshpscSensitivity: + this.log("sensitivity state: "+ value) + break; + + default: + this.log('dp value', dp, value) + } + } + + onDeleted() { + this.log("Sensor removed") + } + + onIASZoneStatusChangeNotification({zoneStatus, extendedStatus, zoneId, delay,}) { + this.log('IASZoneStatusChangeNotification received:', zoneStatus, extendedStatus, zoneId, delay); + this.setCapabilityValue('alarm_motion', zoneStatus.alarm1); + } + + async onSettings({newSettings, changedKeys}) { + if (changedKeys.includes('radar_sensitivity')) { + this.writeData32(dataPoints.tshpscSensitivity, newSettings['radar_sensitivity']) + } + + if (changedKeys.includes('minimum_range')) { + this.writeData32(dataPoints.tshpsMinimumRange, newSettings['minimum_range']*100) + } + + if (changedKeys.includes('maximum_range')) { + this.writeData32(dataPoints.tshpsMaximumRange, newSettings['maximum_range']*100) + } + + if (changedKeys.includes('fading_time')) { + this.writeData32(dataPoints.tshpsFadingTime, newSettings['fading_time']) + } + + } + +} + +module.exports = radarLuminanceSensor; diff --git a/drivers/radarLuminanceSensor/driver.compose.json b/drivers/radarLuminanceSensor/driver.compose.json new file mode 100644 index 0000000000..1ff4ebf0e3 --- /dev/null +++ b/drivers/radarLuminanceSensor/driver.compose.json @@ -0,0 +1,45 @@ +{ + "id": "radarLiminanceSensor", + "name": { + "en": "Human Motion & Luminance Sensor" + }, + "class": "sensor", + "platforms": ["local"], + "connectivity": ["zigbee"], + "capabilities": [ + "measure_luminance", + "measure_battery", + "alarm_motion" + ], + + "energy": { + "batteries": ["AAA", "AAA"] + }, + + "images": { + "large": "{{driverAssetsPath}}/images/large.png", + "small": "{{driverAssetsPath}}/images/small.png" + }, + + "zigbee": { + "manufacturerName": [ + "_TZE200_y8jijhba" + ], + "productId": [ + "TS0601" + ], + "endpoints": { + "1": { + "clusters": [0, 1, 3, 1024, 1280, 61184], + "bindings": [] + } + } + }, + + "learnmode": { + "instruction": { + "en": "Insert pin into hole for 5 seconds until light blinks" + } + } + } + \ No newline at end of file diff --git a/drivers/radarLuminanceSensor/driver.settings.compose.json b/drivers/radarLuminanceSensor/driver.settings.compose.json new file mode 100644 index 0000000000..12d389962b --- /dev/null +++ b/drivers/radarLuminanceSensor/driver.settings.compose.json @@ -0,0 +1,61 @@ +[ + { + "id": "radar_sensitivity", + "type": "number", + "label": { + "en": "Radar sensitivity", + "nl": "Radar sensitiviteit" + }, + "value": 12, + "min": 1, + "max": 15, + "step": 1 + }, + { + "id": "minimum_range", + "type": "number", + "label": { + "en": "Minimum range", + "nl": "Minimale bereik" + }, + "value": 0, + "min": 0, + "max": 9.5, + "step": 0.5, + "units": { + "en": "meters", + "nl": "meters" + } + }, + { + "id": "maximum_range", + "type": "number", + "label": { + "en": "Maximum range", + "nl": "Maximale bereik" + }, + "value": 9.5, + "min": 0, + "max": 9.5, + "step": 0.5, + "units": { + "en": "meters", + "nl": "meters" + } + }, + { + "id": "fading_time", + "type": "number", + "label": { + "en": "Fading time", + "nl": "Reset tijd" + }, + "value": 30, + "min": 0, + "max": 1500, + "units": { + "en": "seconds", + "nl": "seconden" + } + } +]