Open aatifk opened 1 year ago
This device is rather different than the rest of the presence sensors based on the Tuya platform. It uses the standard ZCL cluster 0x0400 for illuminance reporting and the IAS cluster 0x0500 for occupancy reporting. It also uses a manufacturer-specific cluster 0xE002 for the configurable parameters and for reporting.
ah, I see. I should probably just return this device, then.
Amazon reviews are good, I would wait some more days or weeks, it will be surely supported in Z2M sooner or later ...
The form factor of this device is the same as the Xiaomi Mi-Home Bluetooth presence detector, and Xiaomi devices are typically of a much better quality than most of the similar things coming from AliExpress.
It would be great to see this one work! Would this method still work to find the Tuya Data Points? https://www.zigbee2mqtt.io/advanced/support-new-devices/03_find_tuya_data_points.html
Not sure if this information will help, but I can't get very far with an external converter.
Here's the illuminance cluster when my office light is off:
2023-09-06 17:37:35Received Zigbee message from '0xb43a31fffe265417', type 'raw', cluster 'msIlluminanceMeasurement', data '{"data":[8,90,10,0,0,33,1,0,0,0],"type":"Buffer"}' from endpoint 1 with groupID 0
Here's the illuminance cluster when my office light is turned on:
2023-09-06 17:43:17Received Zigbee message from '0xb43a31fffe265417', type 'raw', cluster 'msIlluminanceMeasurement', data '{"data":[8,89,10,0,0,33,134,111,0,0],"type":"Buffer"}' from endpoint 1 with groupID 0
And here is the manuSpecificTuya_2 cluster. It's at a distance and the value (shown as 214 below) goes down as i get closer to the device. Thinking distance?
2023-09-06 17:39:12Received Zigbee message from '0xb43a31fffe265417', type 'attributeReport', cluster 'manuSpecificTuya_2', data '{"57354":214}' from endpoint 1 with groupID 0
When I get really close to it, the cluster changes like this, the 57354 changing to 57345 and the 214 number jumping way up. It's like the distance measurement jumps to smaller units?
2023-09-06 17:50:48Received Zigbee message from '0xb43a31fffe265417', type 'attributeReport', cluster 'manuSpecificTuya_2', data '{"57345":4260}' from endpoint 1
And here's the IasZone cluster:
2023-09-06 17:43:49Received Zigbee message from '0xb43a31fffe265417', type 'commandStatusChangeNotification', cluster 'ssIasZone', data '{"extendedstatus":0,"zonestatus":1}' from endpoint 1 with groupID 0
I also get this genTime cluster, not sure what that does:
2023-09-06 17:44:17Received Zigbee message from '0xb43a31fffe265417', type 'read', cluster 'genTime', data '["localTime"]' from endpoint 1 with groupID 0
There's also a genBasic cluster that only shows up sometimes.
2023-09-06 17:54:55Received Zigbee message from '0xb43a31fffe265417', type 'attributeReport', cluster 'genBasic', data '{"65508":0,"appVersion":65}' from endpoint 1 with groupID 0
I just need to understand how these work rather than the typical Tuya "data points".
Greetings! Acquired a rebranding from MOES with the same designation.
Let's start simple, does battery and occupancy work with this? https://gist.github.com/Koenkk/2e438754fac949869e5c2cf5219382aa
configuration.yaml
as ext_converter.js
configuration.yaml
:
external_converters:
- ext_converter.js
I had returned this because I assumed it won't work. Let me try getting a hold of this again and try the external converter.
- ext_converter.js
Greetings, Koenkk! I checked this converter. For my sensor, everything works out - detects the presence. The sensor is not on batteries - it is on Type - With USB. Here are photos of the packaging and sensor, as well as the Myhome interface of the bluetooth analog Lamptech ES1, which I also have in stock. The settings of the analogue in MiHome are visible. I also attached analogs of sensor data files and logs.
external_converters: - ext_converter.js
I've tried the external converter. Same as @VikeDragon, I get Occupancy, Battery, and Linkquality. Occupancy and Linkquality seem to work, but Battery is "Null" since it is USB powered.
This device also exposes the illuminance via the standard ZCL cluster 0x0400
Added illuminance, removed battery: https://gist.github.com/Koenkk/2e438754fac949869e5c2cf5219382aa
Added illuminance, removed battery: https://gist.github.com/Koenkk/2e438754fac949869e5c2cf5219382aa
Getting an error with the illuminance:
Error 2023-09-11 19:19:38Failed to configure '0xb43a31fffe265417', attempt 3 (Error: ConfigureReporting 0xb43a31fffe265417/1 msIlluminanceMeasurement([{"attribute":"measuredValue","minimumReportInterval":10,"maximumReportInterval":3600,"reportableChange":5}], {"sendWhen":"immediate","timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Timeout - 52598 - 1 - 6 - 1024 - 7 after 10000ms) at Timeout._onTimeout (/app/node_modules/zigbee-herdsman/src/utils/waitress.ts:64:35) at listOnTimeout (node:internal/timers:559:17) at processTimers (node:internal/timers:502:7))
Try just binding the illuminance cluster without configuring the reporting. Also, send the Tuya BlackMagic packet during the pairing, although I don't know if it has any effect or not.
This is a rather weird device... Not typical Tuya data points implementation. It uses cluster 0xE002 for configuring the parameters: Cluster 0xE002, attribute 0xE00B - maximum detection distance, min:75, max:600, step:75, rw Cluster 0xE002, attribute 0xE004 - 'Large motion detection sensitivity', range 0 to 5, rw Cluster 0xE002, attribute 0xE005 - 'Small motion detection sensitivity', range 0 to 5, rw Cluster 0xE002, attribute 0xE00A - the measured distance to the moving object, ro Cluster 0xE002, attribute 0xE001 - 'existence time' (tuyaVersion 1.0.1 - in seconds, tuyaVersion 1.0.5 - in minutes), ro
Tuya cluster 0xEF00, data point 101 - the 'fading time', range 10..10000, rw
Added illuminance, removed battery: https://gist.github.com/Koenkk/2e438754fac949869e5c2cf5219382aa
I also just got the MOES Human Presence Sensor and tried this ext converter and Lux is NULL
FYI - This is the correct image for the MOES Plug https://moeshouse.com/cdn/shop/products/moes-zigbee-human-presence-sensor-detector-radar-wave-detection-sensor-for-home-security-596265.png?v=1692258238&width=600
Does the MOES sensor have exactly the same fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']) as the Linptech?
Does the MOES sensor have exactly the same fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']) as the Linptech?
Yes looks like it
Try just binding the illuminance cluster without configuring the reporting. Also, send the Tuya BlackMagic packet during the pairing, although I don't know if it has any effect or not.
Still showing Illuminance as Null, but, the error has gone away. Sending configure: tuya.configureMagicPacket
didn't seem to make a difference either unfortunately.
I've sent an email to Linptech to see if they can help out.
Does the MOES sensor have exactly the same fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']) as the Linptech?
Yes looks like it
Same thing with MOES sensor.
Does the MOES sensor have exactly the same fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']) as the Linptech?
Yes looks like it
Same thing with MOES sensor.
This is a screencap for the MOES version
with
The MOES model number is:
ZSS-LP-HP02 CB03
Any update on the the Moes wwmave human presence sensor? Mine also shows as _TZ3218_awarhusb TS0225. What is the latest and best so far converter that exist? thanks
Here are some screenshots from the Smart Home app. It is pretty basic sensor. IT shows only 4 variables.
This is everything that can be changed, only 4 settings.
It shows the following:
and
Some inside details π
Some inside details π
Wow, so many of these devices have that same sensor inside! I'm testing a bunch of these and I'm finding that! Hopefully we can get this one working with Z2M as well!
Anything new on the subject? How can we use this mmwave sensor with Zigbee2MQTT?
Still not able to figure out these messages:
Debug 2023-09-18 19:56:17No converter available for 'ZG-205ZL' with cluster 'manuSpecificTuya_2' and type 'attributeReport' and data '{"57354":287}' Debug 2023-09-18 19:56:19No converter available for 'ZG-205ZL' with cluster 'manuSpecificTuya_2' and type 'attributeReport' and data '{"57354":121}'
I've tried adding fzLocal and tzLocal to the converter file to help describe the messages, which I believe is a target distance. Here's my converter:
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
const result: KeyValue = {};
if (msg.data.hasOwnProperty('57354')) {
result.target_distance = msg.data['57354'];
}
return result;
},
} as Fz.Converter,
};
const tzLocal = {
target_distance: {
key: ['target_distance'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'target_distance': {
utils.assertString(value, 'target_distance');
await entity.write('manuSpecificTuya_2', {'57354': {value});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
} as Tz.Converter,
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fz.illuminance, fzLocal.target_distance],
toZigbee: [tzLocal.target_distance],
configure: tuya.configureMagicPacket,
exposes: [e.occupancy(), e.illuminance_lux(), e.target_distance()],
// configure: async (device, coordinatorEndpoint, logger) => {
// const endpoint = device.getEndpoint(1);
// await reporting.bind(endpoint, coordinatorEndpoint, ['msIlluminanceMeasurement']);
// await reporting.illuminance(endpoint);
// },
};
module.exports = definition;
But I'm getting an error:
[19:58:41] INFO: Preparing to start... [19:58:42] INFO: Socat not enabled [19:58:43] INFO: Starting Zigbee2MQTT... /app/data/extension/externally-loaded.js:20 const result: KeyValue = {}; ^^^^^^ SyntaxError: Missing initializer in const declaration at new Script (node:vm:100:7) at createScript (node:vm:265:10) at Object.runInNewContext (node:vm:306:10) at loadModuleFromText (/app/lib/util/utils.ts:152:8) at loadModuleFromFile (/app/lib/util/utils.ts:159:12) at Object.getExternalConvertersDefinitions (/app/lib/util/utils.ts:169:25) at getExternalConvertersDefinitions.next (<anonymous>) at new ExternalConverters (/app/lib/extension/externalConverters.ts:12:20) at new Controller (/app/lib/controller.ts:84:58) at start (/app/index.js:106:18)
I just don't know enough about this stuff to do much more. Any help would be appreciated.
Ok, I'm getting somewhere! I have the target distance working (sort of).
Here's my latest converter.
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
// type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57354')) {
result['target_distance'] = msg.data['57354'];
}
// if (msg.data.hasOwnProperty('57345')) {
// result['target_distance'] = msg.data['57345'];
// }
return result;
},
},
};
const tzLocal = {
target_distance: {
key: ['target_distance'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'target_distance': {
utils.assertString(value, 'target_distance');
await entity.write('manuSpecificTuya_2', {'57354': {value}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
// fromZigbee: [fz.ias_occupancy_alarm_1, fz.illuminance, fzLocal.target_distance],
fromZigbee: [fz.ias_occupancy_alarm_1, fz.illuminance, fzLocal.target_distance],
toZigbee: [tzLocal.target_distance, tzLocal.target_distance],
configure: tuya.configureMagicPacket,
exposes: [e.occupancy(),
e.illuminance_lux(),
e.numeric('target_distance', ea.STATE).withDescription('Distance to target').withUnit('cm'),
e.numeric('radar_sensitivity',ea.STATE_SET).withValueMin(1).withValueMax(5).withValueStep(1)
.withDescription('sensitivity of the radar')],
// configure: async (device, coordinatorEndpoint, logger) => {
// const endpoint = device.getEndpoint(1);
// await reporting.bind(endpoint, coordinatorEndpoint, ['msIlluminanceMeasurement']);
// await reporting.illuminance(endpoint);
// },
};
module.exports = definition;
My biggest issue right now is figuring out the difference between these two messages:
Debug 2023-09-06 17:32:52No converter available for 'TS0225' with cluster 'manuSpecificTuya_2' and type 'attributeReport' and data '{"57345":3180}'
Debug 2023-09-06 17:32:54No converter available for 'TS0225' with cluster 'manuSpecificTuya_2' and type 'attributeReport' and data '{"57354":221}'
It uses the standard ZCL cluster 0x0400 for illuminance reporting and the IAS cluster 0x0500 for occupancy reporting. It also uses a manufacturer-specific cluster 0xE002 for the configurable parameters and for reporting.
So this comment has prompted me to read up on ZCL clusters. I'm literally over my head here, but it looks like the standard Illuminance Measurement cluster (0x0400) has only 5 attributes, while the one reported here seems to have 10:
Debug 2023-09-19 06:22:36No converter available for 'TS0225' with cluster 'msIlluminanceMeasurement' and type 'raw' and data '{"data":[8,59,10,0,0,33,134,23,0,0],"type":"Buffer"}'
Does this indicate that the cluster is non-standard, so we kinda have to guess at what the attributes are?
If we number the attribute positions in the array like this: [1,2,3,4,5,6,7,8,9,10]
, then positions 1,3,4,5,6,9,10 don't seem to change when I change the light level.
Soon @blakadder may have some input :-D
Does this indicate that the cluster is non-standard, so we kinda have to guess at what the attributes are?
Yes π
Ok, I've gotten a little further based on work by @kkossev for Hubitat, but now I'm stuck! https://github.com/kkossev/Hubitat/blob/main/Drivers/Tuya%20Multi%20Sensor%204%20In%201/Tuya%20Multi%20Sensor%204%20In%201.groovy
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57354')) {
result['target_distance'] = msg.data['57354'];
}
return result;
},
},
motion_detection_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57355')) {
result['motion_detection_distance'] = msg.data['57355'];
}
return result;
},
},
motion_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57348')) {
result['motion_detection_sensitivity'] = msg.data['57348'];
}
return result;
},
},
static_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57349')) {
result['static_detection_sensitivity'] = msg.data['57349'];
}
return result;
},
},
};
const tzLocal = {
target_distance: {
key: ['target_distance'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'target_distance': {
utils.assertNumber(value, 'target_distance');
await entity.write('manuSpecificTuya_2', {'57354': {value}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_distance': {
utils.assertNumber(value, 'motion_detection_distance');
await entity.write('manuSpecificTuya_2', {'57355': {value}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
motion_detection_sensitivity: {
key: ['motion_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_sensitivity': {
utils.assertNumber(value, 'motion_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {'57348': {value}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
static_detection_sensitivity: {
key: ['static_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'static_detection_sensitivity': {
utils.assertNumber(value, 'static_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {'57349': {value}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fzLocal.target_distance,fzLocal.motion_detection_distance,fzLocal.motion_detection_sensitivity,fzLocal.static_detection_sensitivity],
toZigbee: [tzLocal.target_distance,tzLocal.motion_detection_distance,tzLocal.motion_detection_sensitivity,tzLocal.static_detection_sensitivity],
configure: tuya.configureMagicPacket,
exposes: [
e.occupancy().withDescription('Presence state'),
e.illuminance_lux(),
e.numeric('target_distance', ea.STATE).withDescription('Distance to target').withUnit('cm'),
e.numeric('motion_detection_distance',ea.STATE_SET).withValueMin(75).withValueMax(600).withValueStep(75).withDescription('Motion detection distance').withUnit('m'),
e.numeric('keep_time',ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Presence keep time'),
e.numeric('motion_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Motion detection sensitivity'),
e.numeric('static_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Static detection sensitivity'),
e.numeric('leave_time', ea.STATE).withValueMin(0).withValueMax(9999).withValueStep(1).withUnit('min').withDescription('Shows the duration of the absence in minutes')
],
meta: {
tuyaDatapoints: [
[1, 'presence', tuya.valueConverter.trueFalse1],
[4, 'motion_detection_distance', tuya.valueConverter.raw],
[12, 'keep_time', tuya.valueConverter.raw],
[15, 'motion_detection_sensitivity', tuya.valueConverter.raw],
[16, 'static_detection_sensitivity', tuya.valueConverter.raw],
[19, 'target_distance', tuya.valueConverter.raw],
[20, 'illuminance_lux', tuya.valueConverter.raw],
[101, 'leave_time', tuya.valueConverter.raw],
],
},
};
module.exports = definition;
When trying to adjust "motion_detection_sensitivity", I got this error:
2023-09-22 17:32:19Publish 'set' 'motion_detection_sensitivity' to 'Linptech ES1 Presence Sensor' failed: 'Error: Write 0xb43a31fffe265417/1 manuSpecificTuya_2({"57348":{"value":2}}, {"sendWhen":"immediate","timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Write for 'BUFFER' not available)'
Not sure what that means, but I was not able to figure out how to send data to the manuSpecificTuya_2 cluster. I think I've reached my limit here, so I'm going to wait on others to help. Linptech really couldn't give much technical help or documentation - they're just rebranding I think.
@makeitworktech we need to know the data type of motion_detection_sensitivity, can you provide the herdsman debug log when the device reports this?
See https://www.zigbee2mqtt.io/guide/usage/debug.html on how to enable the herdsman debug logging. Note that this is only logged to STDOUT and not to log files.
Data type that worked on the other platform is 0x20 ( UINT8 )
Then try:
await entity.write('manuSpecificTuya_2', {57348 {value, type: 0x20}});
Then try:
await entity.write('manuSpecificTuya_2', {57348 {value, type: 0x20}});
@Koenkk This worked great!
motion_detection_sensitivity: {
key: ['motion_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_sensitivity': {
utils.assertNumber(value, 'motion_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57348: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
I now have motion and static detection sensitivity working (I think). I will test to see if they have an effect, but they are not giving an error. I tried to adjust motion_detection_distance, but it gave me a range error, like got "300", range only allowed 0 to 255. That was with this config:
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
let payload = null;
switch (key) {
case 'motion_detection_distance': {
utils.assertNumber(value, 'motion_detection_distance');
await entity.write('manuSpecificTuya_2', {57355: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
So I tried to map values like below, but it only writes a '0' for motion_detection_distance. I don't get an error, just always a 0. Any tips on mapping number ranges?
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
let payload = null;
switch (key) {
case 'motion_detection_distance': {
payload = utils.mapNumberRange(utils.toNumber(value, 'motion_detection_distance'), 0, 255, 75, 600);
await entity.write('manuSpecificTuya_2', {57355: {payload, type: 0x21}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
@makeitworktech try changing the data type for the motion_detection_distance to 0x21 (UINT16) or 0x23 (UINT32).
@makeitworktech try changing the data type for the motion_detection_distance to 0x21 (UINT16) or 0x23 (UINT32).
@kkossev 0x21 works, but the value of motion_detection_distance stays at 0 and never updates. 0x23 gives a data type error. It seems like the data type 0x21 is correct, but the mapping of 0 thru 255 to 75 to 600 is not functioning properly. A syntax issue is my guess?
Got it! Confirmed motion_detection_distance works! Below is the converter I have so far. I'm trying to get msIlluminanceMeasurement next.
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
// illuminance: {
// cluster: 'msIlluminanceMeasurement',
// type: ['raw'],
// convert: (model, msg, publish, options, meta) => {
// const result = {};
// if (msg.data.hasOwnProperty('data')) {
// result['illuminance'] = msg.data['data'];
// }
// return result;
// },
// },
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57354')) {
result['target_distance'] = msg.data['57354'];
}
return result;
},
},
motion_detection_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57355')) {
result['motion_detection_distance'] = msg.data['57355'];
}
return result;
},
},
motion_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57348')) {
result['motion_detection_sensitivity'] = msg.data['57348'];
}
return result;
},
},
static_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57349')) {
result['static_detection_sensitivity'] = msg.data['57349'];
}
return result;
},
},
};
const tzLocal = {
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
let newDist = null;
switch (key) {
case 'motion_detection_distance': {
utils.assertNumber(value, 'motion_detection_distance');
await entity.write('manuSpecificTuya_2', {57355: {value, type: 0x21}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
motion_detection_sensitivity: {
key: ['motion_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_sensitivity': {
utils.assertNumber(value, 'motion_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57348: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
static_detection_sensitivity: {
key: ['static_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'static_detection_sensitivity': {
utils.assertNumber(value, 'static_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57349: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fzLocal.target_distance,fzLocal.motion_detection_distance,fzLocal.motion_detection_sensitivity,fzLocal.static_detection_sensitivity,fz.illuminance],
toZigbee: [tzLocal.motion_detection_distance,tzLocal.motion_detection_sensitivity,tzLocal.static_detection_sensitivity],
configure: tuya.configureMagicPacket,
exposes: [
e.occupancy().withDescription('Presence state'),
e.illuminance(),
e.numeric('target_distance', ea.STATE).withDescription('Distance to target').withUnit('cm'),
e.numeric('motion_detection_distance',ea.STATE_SET).withValueMin(75).withValueMax(600).withValueStep(75).withDescription('Motion detection distance').withUnit('cm'),
e.numeric('keep_time',ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Presence keep time'),
e.numeric('motion_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Motion detection sensitivity'),
e.numeric('static_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Static detection sensitivity'),
e.numeric('leave_time', ea.STATE).withValueMin(0).withValueMax(9999).withValueStep(1).withUnit('min').withDescription('Shows the duration of the absence in minutes')
],
meta: {
tuyaDatapoints: [
[1, 'presence', tuya.valueConverter.trueFalse1],
[4, 'motion_detection_distance', tuya.valueConverter.raw],
[12, 'keep_time', tuya.valueConverter.raw],
[15, 'motion_detection_sensitivity', tuya.valueConverter.raw],
[16, 'static_detection_sensitivity', tuya.valueConverter.raw],
[19, 'target_distance', tuya.valueConverter.raw],
[20, 'illuminance_lux', tuya.valueConverter.raw],
[101, 'leave_time', tuya.valueConverter.raw],
],
},
};
module.exports = definition;
I have everything working now except "Leave time"!
Setting up illuminance is pretty janky, but here was my method. I'm ignoring all of the values in the illuminance buffer object except for position 7. For reference, here are the position numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]. In position 7 there is a number that increases with more light, and decreases with less light. I used a handheld lux meter shown below to record actual lux measurements vs the number that shows up in position 7. https://www.amazon.com/gp/product/B075DC6X25/
I plotted the corresponding values, and got an exponential curve shown below. I used that equation to convert the values in position 7 to "actual Lux values.
Anyway, here's my converter so far. If I shouldn't keep posting every time I make progress, let me know and I'll reduce how often I post updates.
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
illuminance: {
cluster: 'msIlluminanceMeasurement',
type: 'raw',
convert: (model, msg, publish, options, meta) => {
const result = {};
const buffer = msg.data;
result['illuminance'] = Math.round(0.0001 * Math.pow(Number(buffer[7]), 3.413));
return result;
},
},
// below is good
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57354')) {
result['target_distance'] = msg.data['57354'];
}
return result;
},
},
motion_detection_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57355')) {
result['motion_detection_distance'] = msg.data['57355'];
}
return result;
},
},
motion_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57348')) {
result['motion_detection_sensitivity'] = msg.data['57348'];
}
return result;
},
},
static_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57349')) {
result['static_detection_sensitivity'] = msg.data['57349'];
}
return result;
},
},
// Presence Keep Time: Updates every 40 seconds
presence_keep_time: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57345')) {
result['presence_keep_time'] = msg.data['57345'];
}
return result;
},
},
};
const tzLocal = {
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
let newDist = null;
switch (key) {
case 'motion_detection_distance': {
utils.assertNumber(value, 'motion_detection_distance');
await entity.write('manuSpecificTuya_2', {57355: {value, type: 0x21}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
motion_detection_sensitivity: {
key: ['motion_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_sensitivity': {
utils.assertNumber(value, 'motion_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57348: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
static_detection_sensitivity: {
key: ['static_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'static_detection_sensitivity': {
utils.assertNumber(value, 'static_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57349: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fzLocal.target_distance,fzLocal.motion_detection_distance,fzLocal.motion_detection_sensitivity,fzLocal.static_detection_sensitivity,fzLocal.illuminance,fzLocal.presence_keep_time],
toZigbee: [tzLocal.motion_detection_distance,tzLocal.motion_detection_sensitivity,tzLocal.static_detection_sensitivity],
configure: tuya.configureMagicPacket,
exposes: [
e.occupancy().withDescription('Presence state'),
e.numeric('illuminance', ea.STATE).withDescription('Illuminance in lux').withUnit('lx'),
e.numeric('target_distance', ea.STATE).withDescription('Distance to target').withUnit('cm'),
e.numeric('motion_detection_distance',ea.STATE_SET).withValueMin(75).withValueMax(600).withValueStep(75).withDescription('Motion detection distance').withUnit('cm'),
e.numeric('presence_keep_time',ea.STATE).withDescription('Presence keep time').withUnit('s'),
e.numeric('motion_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Motion detection sensitivity'),
e.numeric('static_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Static detection sensitivity'),
e.numeric('leave_time', ea.STATE).withValueMin(0).withValueMax(9999).withValueStep(1).withUnit('min').withDescription('Shows the duration of the absence in minutes')
],
meta: {
tuyaDatapoints: [
[1, 'presence', tuya.valueConverter.trueFalse1],
[4, 'motion_detection_distance', tuya.valueConverter.raw],
[12, 'keep_time', tuya.valueConverter.raw],
[15, 'motion_detection_sensitivity', tuya.valueConverter.raw],
[16, 'static_detection_sensitivity', tuya.valueConverter.raw],
[19, 'target_distance', tuya.valueConverter.raw],
[20, 'localilluminance', tuya.valueConverter.raw],
[101, 'leave_time', tuya.valueConverter.raw],
],
},
};
module.exports = definition;
Thanks for the great work. Keep posting your updates. I am testing them on the MOES version, and all working apart from the leave time.
I tried adding mine to my MOES Tuya hub but it was not working. After speaking to MOES support, they stated my Hub was too old to support and too old to do an update (2 years old), so I am waiting for a new Hub to arrive to test as well.
I haven't been able to see any messages from the device that relate to "Leave time" or "fading time", so I'm not really sure how to proceed. The target distance is decently accurate (from some of my tests so far), and setting the motion detection distance does seem to work.
I hope that next week my Moes sensor will arrive and I will be able to sniff the command sent by Smart Life app.
I don't know if you know or if this information helps anything, but the mmw sensor is the LD2410B from Hi-Link.
Anyone have an issue where the occupancy sensor gets stuck in ON state and never clears? Iβm connected to z2m and have re-paired it a few times but always stays in occupied state I am running the latest converter code I have tried adjusting sensitivities, but still stays ON
@makeitworktech Could my sensor be defective or do you have any ideas I could try to get the occupancy working?
@makeitworktech - the fadingTime ('nobody time') is configured via Tuya DP 101
You can remove in the convertor all the tuyaDatapoints except dp 101 and probably rename it to 'Fading Time' (or whatever other label is already in use in Z2M) - this is the delay in seconds, after which the device will send a no-presence report via the IAS cluster.
The 'leave_time' (the duration of the absence in minutes) is not reported for this type of radar.
@kkossev , ok thanks, I've updated the converter. I have to wait until my kids are asleep so there's no presence and I can test the time. @alexvaltchev mentioned that the Tuya app shows 10-10000sec for this one. 10000 sec is 2.8 hours, seems extreme! I put mine at 10 sec and I'll test it out there. Here's the latest:
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const {KeyValue, Definition, Tz, Fz, Expose, KeyValueAny, KeyValueNumberString, KeyValueString} = require('zigbee-herdsman-converters/lib/types');
const fzLocal = {
illuminance: {
cluster: 'msIlluminanceMeasurement',
type: 'raw',
convert: (model, msg, publish, options, meta) => {
const result = {};
const buffer = msg.data;
//result['illuminance'] = Number(buffer[8]) * 4.7419 * Math.exp(0.0522);
result['illuminance'] = Math.round(0.0001 * Math.pow(Number(buffer[7]), 3.413));
return result;
},
},
// below is good
target_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57354')) {
result['target_distance'] = msg.data['57354'];
}
return result;
},
},
motion_detection_distance: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57355')) {
result['motion_detection_distance'] = msg.data['57355'];
}
return result;
},
},
motion_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57348')) {
result['motion_detection_sensitivity'] = msg.data['57348'];
}
return result;
},
},
static_detection_sensitivity: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57349')) {
result['static_detection_sensitivity'] = msg.data['57349'];
}
return result;
},
},
// Presence Keep Time: Updates every 40 seconds
presence_keep_time: {
cluster: 'manuSpecificTuya_2',
type: ['attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = {};
if (msg.data.hasOwnProperty('57345')) {
result['presence_keep_time'] = msg.data['57345'];
}
return result;
},
},
};
const tzLocal = {
motion_detection_distance: {
key: ['motion_detection_distance'],
convertSet: async (entity, key, value, meta) => {
let newDist = null;
switch (key) {
case 'motion_detection_distance': {
utils.assertNumber(value, 'motion_detection_distance');
await entity.write('manuSpecificTuya_2', {57355: {value, type: 0x21}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
motion_detection_sensitivity: {
key: ['motion_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'motion_detection_sensitivity': {
utils.assertNumber(value, 'motion_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57348: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
static_detection_sensitivity: {
key: ['static_detection_sensitivity'],
convertSet: async (entity, key, value, meta) => {
switch (key) {
case 'static_detection_sensitivity': {
utils.assertNumber(value, 'static_detection_sensitivity');
await entity.write('manuSpecificTuya_2', {57349: {value, type: 0x20}});
break;
}
default: // Unknown key
meta.logger.warn(`Unhandled key ${key}`);
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0225', ['_TZ3218_awarhusb']),
model: 'TS0225',
vendor: 'TuYa',
description: 'Presence sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fzLocal.target_distance,fzLocal.motion_detection_distance,fzLocal.motion_detection_sensitivity,fzLocal.static_detection_sensitivity,fzLocal.illuminance,fzLocal.presence_keep_time, tuya.fz.datapoints],
toZigbee: [tzLocal.motion_detection_distance,tzLocal.motion_detection_sensitivity,tzLocal.static_detection_sensitivity, tuya.tz.datapoints],
configure: tuya.configureMagicPacket,
exposes: [
e.occupancy().withDescription('Presence state'),
e.numeric('illuminance', ea.STATE).withDescription('Illuminance in lux').withUnit('lx'),
e.numeric('target_distance', ea.STATE).withDescription('Distance to target').withUnit('cm'),
e.numeric('motion_detection_distance',ea.STATE_SET).withValueMin(75).withValueMax(600).withValueStep(75).withDescription('Motion detection distance').withUnit('cm'),
e.numeric('presence_keep_time',ea.STATE).withDescription('Presence keep time').withUnit('s'),
e.numeric('motion_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Motion detection sensitivity'),
e.numeric('static_detection_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(5).withValueStep(1).withDescription('Static detection sensitivity'),
e.numeric('fading_time', ea.STATE_SET).withValueMin(10).withValueMax(10000).withValueStep(1).withUnit('sec').withDescription('Time after which the device will check again for presence')
],
meta: {
tuyaDatapoints: [
[101, 'fading_time', tuya.valueConverter.raw],
],
},
};
module.exports = definition;
Just received the Linptech today, using your latest external .js ... looks great so far!
Anyone have an issue where the occupancy sensor gets stuck in ON state and never clears?
I haven't had this issue. I'd say get a replacement and try that.
The unit is CRAZY sensitive. I had to set the motion and static sensitivities all the way down, and set the range to just what I need, which is around 300 cm. Try that first before returning. If it's set too high, ANYTHING can set it off. Also it needs to mounted in a SOLID way. If someone walks heavy in another room, that can cause a micro vibration that it will pick up if set too high.
@makeitworktech @Scope666 thanks for the tips. I set the sensitivity all the way down and still the same result. Itβs weird because the blue light comes on when I come in the room (indicating that the hardware seems to detect presence), but the sensor never changes. Also, the other sensors work fine (specifically target distance, so I know it detects me). Iβll try a few more things, and if nothing works, Iβll order a new one
Link
https://www.amazon.com/dp/B0C7C6L66J?ref=ppx_yo2ov_dt_b_product_details&th=1
Database entry
{"id":29,"type":"Router","ieeeAddr":"0xb43a31fffe265666","nwkAddr":29864,"manufId":4098,"manufName":"_TZ3218_awarhusb","powerSource":"Mains (single phase)","modelId":"TS0225","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":1026,"inClusterList":[0,3,4,5,57346,16384,61184,1280],"outClusterList":[10,25],"clusters":{"genBasic":{"attributes":{"modelId":"TS0225","manufacturerName":"_TZ3218_awarhusb","powerSource":1,"zclVersion":3,"appVersion":65,"stackVersion":1,"hwVersion":1,"dateCode":""}},"ssIasZone":{"attributes":{"iasCieAddr":"0x00124b0026b884c4","zoneState":0}}},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":65,"stackVersion":1,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{},"lastSeen":1692243468779,"defaultSendRequestWhen":"immediate"}
Comments
I see another thread requesting support for TS0225 but the manufacturer and the product pages seem to be different for this one.
External converter
No response
Supported color modes
No response
Color temperature range
No response