Skip to content

Commit

Permalink
Improve tuya_data_point_dump: Log decoded DPs
Browse files Browse the repository at this point in the history
Up to now, `tuya_data_point_dump` dumped the DP values in machine readable
format, necessitating the use of the Python script `tuya_data_point_dump.py`
to decode it.  Additionally, the list of data point IDs in that script is
not complete (actually, it is rather specific for Saswell devices).

`zigbee-herdsman-converters` actually has the most up-to-date list of DP
values built-in.  And it comes with DP value converters for the DP data
types.  We can use this to log incoming DP values in a human readable format
containing the DP ID, data type, decoded value and the already known uses of
the DP IP:

```
zigbee-herdsman-converters:tuya_data_point_dump: Received DP Koenkk#1 from 0x845134eaae1d0412 with raw data '{"dp":1,"datatype":4,"data":{"type":"Buffer","data":[1]}}': type='commandDataResponse', datatype='enum', value='1', known DP# usage: ["state","moesSsystemMode","moes105DimmerState1","trsPresenceState","haozeeSystemMode","nousTemperature","wlsWaterLeak"]
zigbee-herdsman-converters:tuya_data_point_dump: Received DP Koenkk#4 from 0x845134eaae1d0412 with raw data '{"dp":4,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,86]}}': type='commandDataResponse', datatype='value', value='86', known DP# usage: ["mode","moesSboostHeating","haozeeBoostHeating","nousBattery","wlsBatteryPercentage"]
```

In general, this output should be sufficient to enable new Tuya devices
(However, this won't decode more complex data structures for Saswell devices
(like tuya_data_point_dump.py does for schedules)).
  • Loading branch information
gmbnomis committed Jan 16, 2022
1 parent fba22a5 commit a16f833
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
13 changes: 13 additions & 0 deletions converters/fromZigbee.js
Original file line number Diff line number Diff line change
Expand Up @@ -4362,6 +4362,14 @@ const converters = {
convert: (model, msg, publis, options, meta) => {
// Don't use in production!
// Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
const getType = (datatype) => {
const entry = Object.entries(tuya.dataTypes).find(([typeName, typeId]) => typeId === datatype);
return (entry ? entry[0] : 'unknown');
};
const getAllDpIds = (dp) => {
const entries = Object.entries(tuya.dataPoints).filter(([dpName, dpId]) => dpId === dp);
return entries.map(([dpName, dpId]) => dpName);
};
const getHex = (value) => {
let hex = value.toString(16);
if (hex.length < 2) {
Expand All @@ -4372,6 +4380,11 @@ const converters = {
const now = Date.now().toString();
let dataStr = '';
for (const [i, dpValue] of msg.data.dpValues.entries()) {
const value = tuya.getDataValue(dpValue);
meta.logger.info(`zigbee-herdsman-converters:tuya_data_point_dump: Received DP #${
dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
getType(dpValue.datatype)}', value='${value}', known DP# usage: ${JSON.stringify(getAllDpIds(dpValue.dp))}`);

dataStr +=
now + ' ' +
meta.device.ieeeAddr + ' ' +
Expand Down
37 changes: 34 additions & 3 deletions test/fromZigbee.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const fz = require('../converters/fromZigbee');
const tuya = require('../lib/tuya');

jest.mock('fs');
const fs = require('fs');

describe('converters/fromZigbee', () => {
describe('tuya', () => {
const meta = { logger: { warn: jest.fn()}}
const meta = {logger: {warn: jest.fn(), info: jest.fn()}, device: {ieeeAddr: "0x123456789abcdef"}};
describe('wls100z_water_leak', () => {
it.each([
[
Expand Down Expand Up @@ -34,7 +37,7 @@ describe('converters/fromZigbee', () => {
],
])
("Receives '%s' indication", (_name, dpValues, result) => {
expect(fz.wls100z_water_leak.convert(null, { data: {dpValues}}, null, null, meta)).toEqual(result);
expect(fz.wls100z_water_leak.convert(null, {data: {dpValues}}, null, null, meta)).toEqual(result);
});
});
describe('tuya_smart_vibration_sensor', () => {
Expand All @@ -60,7 +63,35 @@ describe('converters/fromZigbee', () => {
],
])
("Receives '%s' indication", (_name, dpValues, result) => {
expect(fz.tuya_smart_vibration_sensor.convert(null, { data: {dpValues}}, null, null, meta)).toEqual(result);
expect(fz.tuya_smart_vibration_sensor.convert(null, {data: {dpValues}}, null, null, meta)).toEqual(result);
});
});
describe('tuya_data_point_dump', () => {
beforeEach(() => {
meta.logger.info.mockClear();
});
it('Logs all received DPs', () => {
const msg = {
type: 'commandDataResponse',
data: {
seq: 1,
dpValues: [
tuya.dpValueFromRaw(tuya.dataPoints.state, [0, 1]),
tuya.dpValueFromBool(tuya.dataPoints.heatingSetpoint, true),
tuya.dpValueFromIntValue(tuya.dataPoints.occupancy, 97),
tuya.dpValueFromStringBuffer(tuya.dataPoints.mode, [102, 111, 111]),
tuya.dpValueFromEnum(tuya.dataPoints.config, 1),
tuya.dpValueFromBitmap(tuya.dataPoints.childLock, [1, 2]),
],
},
};
expect(fz.tuya_data_point_dump.convert(null, msg, null, null, meta)).toEqual(undefined);
expect(meta.logger.info).nthCalledWith(1, expect.stringMatching(/Received DP #1 from 0x123456789abcdef with raw data '\{"dp":1,"datatype":0,"data":\[0,1\]\}': type='commandDataResponse', datatype='raw', value='0,1', known DP# usage: \[.*"state"/));
expect(meta.logger.info).nthCalledWith(2, expect.stringMatching(/Received DP #2 from 0x123456789abcdef with raw data '\{"dp":2,"datatype":1,"data":\[1\]\}': type='commandDataResponse', datatype='bool', value='true', known DP# usage: \[.*"heatingSetpoint"/));
expect(meta.logger.info).nthCalledWith(3, expect.stringMatching(/Received DP #3 from 0x123456789abcdef with raw data '\{"dp":3,"datatype":2,"data":\[0,0,0,97\]\}': type='commandDataResponse', datatype='value', value='97', known DP# usage: \[.*"occupancy"/));
expect(meta.logger.info).nthCalledWith(4, expect.stringMatching(/Received DP #4 from 0x123456789abcdef with raw data '\{"dp":4,"datatype":3,"data":\[102,111,111\]\}': type='commandDataResponse', datatype='string', value='foo', known DP# usage: \[.*"mode"/));
expect(meta.logger.info).nthCalledWith(5, expect.stringMatching(/Received DP #5 from 0x123456789abcdef with raw data '\{"dp":5,"datatype":4,"data":\[1\]\}': type='commandDataResponse', datatype='enum', value='1', known DP# usage: \[.*"config"/));
expect(meta.logger.info).nthCalledWith(6, expect.stringMatching(/Received DP #7 from 0x123456789abcdef with raw data '\{"dp":7,"datatype":5,"data":\[1,2\]\}': type='commandDataResponse', datatype='bitmap', value='258', known DP# usage: \[.*"childLock"/));
});
});
});
Expand Down

0 comments on commit a16f833

Please sign in to comment.