diff --git a/drivers/lcd_th_sensor/assets/icon.svg b/drivers/lcd_th_sensor/assets/icon.svg new file mode 100644 index 00000000..fc596475 --- /dev/null +++ b/drivers/lcd_th_sensor/assets/icon.svg @@ -0,0 +1,479 @@ + +image/svg+xml + + + + diff --git a/drivers/lcd_th_sensor/assets/images/large.png b/drivers/lcd_th_sensor/assets/images/large.png new file mode 100644 index 00000000..1ab356f8 Binary files /dev/null and b/drivers/lcd_th_sensor/assets/images/large.png differ diff --git a/drivers/lcd_th_sensor/assets/images/small.png b/drivers/lcd_th_sensor/assets/images/small.png new file mode 100644 index 00000000..ae468ad2 Binary files /dev/null and b/drivers/lcd_th_sensor/assets/images/small.png differ diff --git a/drivers/lcd_th_sensor/device.js b/drivers/lcd_th_sensor/device.js new file mode 100644 index 00000000..8117383b --- /dev/null +++ b/drivers/lcd_th_sensor/device.js @@ -0,0 +1,413 @@ +'use strict'; + +const TuyaSpecificCluster = require('../../lib/TuyaSpecificCluster'); +const TuyaSpecificClusterDevice = require('../../lib/TuyaSpecificClusterDevice'); +const {getDataValue} = require("./helpers"); +const { Cluster} = require('zigbee-clusters'); + + + +Cluster.addCluster(TuyaSpecificCluster); +/* {"1":"Temperature","2":"Humidity","4":"Battery level","9":"Unit convert","10":"Set maxtemp","11":"Set minitemp","12":"Set maxhum","13":"Set minihum","14":"Temp alarm","15":"Humidity alarm","17":"Temperature report","18":"Humidity report","19":"Temp sensitivity","20":"Humidity sensitivity"} */ +const dataPoints = { + currentTemperature: 1, + currentHumidity: 2, + batteryLevel: 4, + unit_convert: 9, + maxtemp: 10, + mintemp: 11, + maxhum: 12, + minhum: 13, + tempalarm: 14, + humalarm: 15, + tempreport: 17, + humreport: 18, + tempsens: 19, + humsens:20 +} + +class lcdThSensor extends TuyaSpecificClusterDevice { + async onNodeInit({ zclNode }) { + this.printNode(); + this.enableDebug(); + + this.registerCapabilityListener("measure_temperature", async (currentTemperature) => { + this.log('current temperature received', currentTemperature) + }) + this.registerCapabilityListener("measure_humidity", async (currentHumidity) => { + this.log('current humidity received', currentHumidity) + }) + this.registerCapabilityListener("measure_battery", async (batteryLevel) => { + this.log('current battery level received', batteryLevel) + }) + + zclNode.endpoints[1].clusters.tuya.on("response", value => this.processResponse(value)); + zclNode.endpoints[1].clusters.tuya.on("reporting", value => this.processResponse(value)); + zclNode.endpoints[1].clusters.tuya.on("datapoint", value => this.processResponse(value)); + + await zclNode.endpoints[1].clusters.basic.readAttributes('manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 'attributeReportingStatus') + .catch(err => { + this.error('Error when reading device attributes ', err); + }); + } + + + async processResponse(data) { + const dp = data.dp; + const measuredValue = getDataValue(data); + + let parsedValue = 0; + + switch (dp) { + case dataPoints.batteryLevel: + parsedValue = measuredValue; + this.log("measure_battery | powerConfiguration - batteryPercentageRemaining (%): ", parsedValue); + + try { + this.setCapabilityValue('measure_battery', parsedValue); + } catch (e) { + this.log("Failed to set battery level", e); + } + break; + + case dataPoints.currentHumidity: + parsedValue = measuredValue; + this.log('measure_humidity | relativeHumidity - measuredValue (humidity):', parsedValue); + + try { + this.setCapabilityValue('measure_humidity', parsedValue); + } catch (e) { + this.log("Failed to set current humidity", e); + } + break; + + case dataPoints.currentTemperature: + parsedValue = measuredValue/10; + this.log('measure_temperature | temperatureMeasurement - measuredValue (temperature):', parsedValue); + + try { + this.setCapabilityValue('measure_temperature', parsedValue); + } catch (e) { + this.log("Failed to set current temperature", e); + } + break; + default: + console.log('\x1b[91m%s\x1b[0m', "DP VALUE:" + dp + " MEASUREMENT:" + measuredValue); + } + } + + onDeleted() { + this.log("LCD T&H sensor removed") + } + async onSettings({newSettings, changedKeys}) { + if (changedKeys.includes('temperature_sensitivity')) { + this.writeData32(dataPoints.tempsens, newSettings['temperature_sensitivity']) + } + if (changedKeys.includes('temp_periodic_report')) { + this.writeData32(dataPoints.tempreport, newSettings['temp_periodic_report']) + } + if (changedKeys.includes('humidity_sensitivity')) { + this.writeData32(dataPoints.humsens, newSettings['humidity_sensitivity']) + } + if (changedKeys.includes('hum_periodic_report')) { + this.writeData32(dataPoints.humreport, newSettings['hum_periodic_report']) + } + if (changedKeys.includes('temp_unit_convert')) { + this.writeString(dataPoints.unit_convert, newSettings['temp_unit_convert']) + console.log('\x1b[91m%s\x1b[0m', "TRIGGERED"); + } + } +} + +module.exports = lcdThSensor; + +/* +{ + "ids": { + "modelId": "TS0601", + "manufacturerName": "_TZE200_locansqn" + }, + "endpoints": { + "ieeeAddress": "a4:c1:38:70:91:12:fd:3a", + "networkAddress": 27549, + "modelId": "TS0601", + "manufacturerName": "_TZE200_locansqn", + "endpointDescriptors": [ + { + "status": "SUCCESS", + "nwkAddrOfInterest": 27549, + "_reserved": 20, + "endpointId": 1, + "applicationProfileId": 260, + "applicationDeviceId": 81, + "applicationDeviceVersion": 0, + "_reserved1": 1, + "inputClusters": [ + 4, + 5, + 61184, + 0 + ], + "outputClusters": [ + 25, + 10 + ] + } + ], + "deviceType": "enddevice", + "receiveWhenIdle": false, + "capabilities": { + "alternatePANCoordinator": false, + "deviceType": false, + "powerSourceMains": false, + "receiveWhenIdle": false, + "security": false, + "allocateAddress": true + }, + "extendedEndpointDescriptors": { + "1": { + "clusters": { + "groups": { + "attributes": [ + { + "acl": [ + "readable", + "reportable" + ], + "id": 0, + "name": "nameSupport", + "value": { + "type": "Buffer", + "data": [ + 0 + ] + }, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65533, + "name": "clusterRevision", + "value": 2, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + } + ] + }, + "scenes": { + "attributes": [ + { + "acl": [ + "readable", + "reportable" + ], + "id": 0, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 1, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 2, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 3, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 4, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65533, + "name": "clusterRevision", + "value": 2, + "reportingConfiguration": { + "status": "NOT_FOUND", + "direction": "reported" + } + } + ] + }, + "basic": { + "attributes": [ + { + "acl": [ + "readable", + "reportable" + ], + "id": 0, + "name": "zclVersion", + "value": 3 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 1, + "name": "appVersion", + "value": 72 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 2, + "name": "stackVersion", + "value": 0 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 3, + "name": "hwVersion", + "value": 1 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 4, + "name": "manufacturerName", + "value": "_TZE200_locansqn" + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 5, + "name": "modelId", + "value": "TS0601" + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 6, + "name": "dateCode", + "value": "" + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 7, + "name": "powerSource", + "value": "battery" + }, + { + "acl": [ + "readable", + "writable", + "reportable" + ], + "id": 65502 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65533, + "name": "clusterRevision", + "value": 2 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65534, + "name": "attributeReportingStatus", + "value": "PENDING" + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65506 + }, + { + "acl": [ + "readable", + "reportable" + ], + "id": 65507 + } + ] + } + }, + "bindings": { + "ota": {}, + "time": { + "attributes": [ + { + "acl": [ + "readable" + ], + "id": 65533, + "name": "clusterRevision", + "value": 1 + } + ] + } + } + } + } + } +} + */ diff --git a/drivers/lcd_th_sensor/driver.compose.json b/drivers/lcd_th_sensor/driver.compose.json new file mode 100644 index 00000000..1d950331 --- /dev/null +++ b/drivers/lcd_th_sensor/driver.compose.json @@ -0,0 +1,55 @@ +{ + "id": "lcd_th_sensor", + "name": { + "en": "LCD T&H Sensor" + }, + "class": "sensor", + "platforms": ["local"], + "connectivity": ["zigbee"], + "capabilities": [ + "measure_temperature", + "measure_humidity", + "measure_battery" + ], + "energy": { + "batteries": [ + "AAA", "AAA", "AAA" + ] + }, + "images": { + "large": "{{driverAssetsPath}}/images/large.png", + "small": "{{driverAssetsPath}}/images/small.png" + }, + "zigbee": { + "manufacturerName": [ + "_TZE200_locansqn" + ], + "productId": [ + "TS0601" + ], + "endpoints": { + "1": { + "clusters": [ + 0, + 4, + 5, + 10, + 25, + 61184 + ], + "bindings": [ + 4, + 5, + 10, + 25, + 61184 + ] + } + }, + "learnmode": { + "instruction": { + "en": "Press the button on the side of the unit for 5 seconds." + } + } + } +} \ No newline at end of file diff --git a/drivers/lcd_th_sensor/driver.settings.compose.json b/drivers/lcd_th_sensor/driver.settings.compose.json new file mode 100644 index 00000000..0ff16e17 --- /dev/null +++ b/drivers/lcd_th_sensor/driver.settings.compose.json @@ -0,0 +1,81 @@ +[ + { + "id": "temperature_sensitivity", + "type": "number", + "label": { + "en": "Temperature sensitivity (0.X°C)" + }, + "hint": { + "en": "Set temperature sensitivity. step size decimal [°C]" + }, + "value": 3, + "attr": { + "min": 3, + "max": 10, + "step": 1 + } + }, + { + "id": "temp_periodic_report", + "type": "number", + "label": { + "en": "Temperature reporting interval in minutes" + }, + "value": 1, + "attr": { + "min": 1, + "max": 120, + "step": 1 + } + }, + { + "id": "humidity_sensitivity", + "type": "number", + "label": { + "en": "Humidity sensitivity" + }, + "hint": { + "en": "Set humidity sensitivity. default [6%]" + }, + "value": 6, + "attr": { + "min": 3, + "max": 10, + "step": 1 + }, + "units": { + "en": "%" + } + }, + { + "id": "hum_periodic_report", + "type": "number", + "label": { + "en": "Humidity reporting interval in minutes" + }, + "value": 1, + "attr": { + "min": 1, + "max": 120, + "step": 1 + } + }, + { + "id": "temp_unit_convert", + "type": "dropdown", + "value": "c", + "label": { + "en": "Celsius / Fahrenheit" + }, + "values": [ + { + "id": "c", + "label": { "en": "Celsius" } + }, + { + "id": "f", + "label": { "en": "Fahrenheit" } + } + ] + } + ] \ No newline at end of file diff --git a/drivers/lcd_th_sensor/helpers.js b/drivers/lcd_th_sensor/helpers.js new file mode 100644 index 00000000..6c3378db --- /dev/null +++ b/drivers/lcd_th_sensor/helpers.js @@ -0,0 +1,42 @@ +const getDataValue = (dpValue) => { + const convertMultiByteNumberPayloadToSingleDecimalNumber = (chunks) => { + let value = 0; + + for (let i = 0; i < chunks.length; i++) { + value = value << 8; + value += chunks[i]; + } + + return value; + }; + + 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); + } +} + +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 +}; + +module.exports = { getDataValue } \ No newline at end of file diff --git a/drivers/lcdtemphumidsensor_3/driver.compose.json b/drivers/lcdtemphumidsensor_3/driver.compose.json index 8c104954..d74a37ee 100644 --- a/drivers/lcdtemphumidsensor_3/driver.compose.json +++ b/drivers/lcdtemphumidsensor_3/driver.compose.json @@ -24,8 +24,7 @@ "zigbee": { "manufacturerName": [ "_TZE200_bjawzodf", - "_TZE200_zl1kmjqx", - "_TZE200_locansqn" + "_TZE200_zl1kmjqx" ], "productId": [ "TS0601"