Skip to content

Commit b468525

Browse files
committed
Update "Support new TuYa devices" to new TuYa format.
1 parent 9ff2ff5 commit b468525

File tree

1 file changed

+47
-141
lines changed

1 file changed

+47
-141
lines changed
Lines changed: 47 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Support new Tuya devices
2-
Tuya devices use a custom `manuSpecificTuya` cluster, the instructions below will help you understand it better and provide some tools to ease discovery of their functions
1+
# Support new TuYa devices
2+
TuYa devices use a custom `manuSpecificTuya` cluster, the instructions below will help you understand it better and provide some tools to ease discovery of their functions
33

44
## Instructions
55
### 1. Standard part of the setup
@@ -16,192 +16,98 @@ const reporting = require('zigbee-herdsman-converters/lib/reporting');
1616
const extend = require('zigbee-herdsman-converters/lib/extend');
1717
const e = exposes.presets;
1818
const ea = exposes.access;
19-
const tuya = require("zigbee-herdsman-converters/lib/tuya");
19+
const tuya = require('zigbee-herdsman-converters/lib/tuya');
2020

2121
const definition = {
22-
// Since a lot of Tuya devices use the same modelID, but use different data points
23-
// it's usually necessary to provide a fingerprint instead of a zigbeeModel
22+
// Since a lot of TuYa devices use the same modelID, but use different datapoints
23+
// it's necessary to provide a fingerprint instead of a zigbeeModel
2424
fingerprint: [
2525
{
2626
// The model ID from: Device with modelID 'TS0601' is not supported
2727
// You may need to add \u0000 at the end of the name in some cases
2828
modelID: 'TS0601',
2929
// The manufacturer name from: Device with modelID 'TS0601' is not supported.
30-
manufacturerName: '_TZE200_c88teujp'
30+
manufacturerName: '_TZE200_d0yu2xgi',
3131
},
3232
],
33-
model: 'SEA802-Zigbee',
34-
vendor: 'Saswell',
35-
description: 'Thermostatic radiator valve',
36-
fromZigbee: [
37-
fz.ignore_basic_report, // Add this if you are getting no converter for 'genBasic'
38-
fz.tuya_data_point_dump, // This is a debug converter, it will be described in the next part
39-
],
40-
toZigbee: [
41-
tz.tuya_data_point_test, // Another debug converter
42-
],
33+
model: 'TS0601_new',
34+
vendor: 'TuYa',
35+
description: 'Fill in a description of the device here',
36+
fromZigbee: [tuya.fz.datapoints],
37+
toZigbee: [tuya.tz.datapoints],
4338
onEvent: tuya.onEventSetTime, // Add this if you are getting no converter for 'commandMcuSyncTime'
44-
configure: async (device, coordinatorEndpoint, logger) => {
45-
const endpoint = device.getEndpoint(1);
46-
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
47-
},
39+
configure: tuya.configureMagicPacket,
4840
exposes: [
4941
// Here you should put all functionality that your device exposes
5042
],
43+
meta: {
44+
// All datapoints go in here
45+
tuyaDatapoints: [
46+
],
47+
},
5148
};
5249

5350
module.exports = definition;
5451
```
5552

56-
Once finished, restart Zigbee2MQTT and trigger some actions on the device.
57-
58-
### 3. Understanding Tuya data points
59-
The `dataReport`and `dataResponse` types of the `manuSpecificTuya` cluster have their own format:
53+
### 3. Understanding TuYa datapoints
54+
The `dataReport`and `dataResponse` types of the `manuSpecificTuYa` cluster have their own format:
6055

6156
```js
6257
{name: 'seq', type: DataType.uint16},
6358
{name: 'dpValues', type: BuffaloZclDataType.LIST_TUYA_DATAPOINT_VALUES},
6459
```
6560

66-
`seq` is the transaction number of the payload. `dpValues` is an array of "Data Points" (type: `TuyaDataPointValue`). Such a data point value consists of:
61+
`seq` is the transaction number of the payload. `dpValues` is an array of "Data Points" (type: `TuYaDataPointValue`). Such a datapoint value consists of:
6762

6863
```js
6964
dp: DataType.uint8;
7065
datatype: DataType.uint8;
7166
data: Buffer;
7267
```
7368

74-
- `dp` is so called "Data Point ID" which is at the core of Tuya devices. From the point of view of a device the DPIDs are the functions that the device provides.
69+
- `dp` is so called "Data Point ID" which is at the core of TuYa devices. From the point of view of a device the DPIDs are the functions that the device provides.
7570
- `datatype` is the type of data contained in the `data` field, see `dataTypes` in `node_modules/zigbee-herdsman-converters/lib/tuya.js`
7671

77-
Some data points are 'report only' (they report changes that happen within the device) others are 'issue and report' (they can report by themselves, but also respond with a report when set). The list of currently known data points can be found in `dataPoints` in [node_modules/zigbee-herdsman-converters/lib/tuya.js](https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/lib/tuya.js). Data point IDs may be device dependent, they are not unified across all Tuya devices.
78-
79-
For example on Saswell thermostat data point number `103` is heating setpoint, it has `value` (i.e. integer) type and is 'issue and report', we will use that information later in examples.
72+
Some datapoints are 'report only' (they report changes that happen within the device) others are 'issue and report' (they can report by themselves, but also respond with a report when set). Data points are not unified across all TuYa devices so they can differ per device.
8073

81-
If you have a Tuya gateway, you can find what the function is of data point number by following [this how-to guide](./03_find_tuya_data_points.md)
74+
### 4. Mapping the datapoints
75+
Now we have to map the datapoints in `tuyaDatapoints`. Start Zigbee2MQTT with [debug logging](../../guide/usage/debug.md) enabled and trigger some actions on the device. You will now see logging like:
8276

83-
### 4. Deciphering the data points
84-
By adding the two debug converters mentioned earlier, we have the tools to decipher Tuya data points.
85-
86-
#### fz.tuya_data_point_dump
87-
This converter will log a message for each data point value received in a Tuya specific message from the device. For the "heating setpoint" example with data point number `103`, this could look like:
88-
89-
```
90-
zigbee-herdsman-converters:tuya_data_point_dump: Received DP #103 from 0x123456789abcdef with raw data '{"dp":103,"datatype":2,"data":[0,0,0,215]}': type='commandDataResponse', datatype='value', value='215', known DP# usage: ["maxTemp","moesSboostHeatingCountdownTimeSet","neoDuration","hyExternalTemp","trsIlluminanceLux","msVacancyDelay","hochActivePower"]
9177
```
92-
93-
The log message contains the data point number, the raw and the decoded data, and the list of symbolic names which are already known for this data point number (from the `dataPoints` definition in `node_modules/zigbee-herdsman-converters/lib/tuya.js`).
94-
95-
In addition to the log entry, the converter will append a line to the file `data/tuya.dump.txt` (which can be used for test scripts). For each data point value received format of line is:
96-
97-
```txt
98-
current_time device_ieee_address seq dpv_number dp datatype data_as_hex_octets
78+
Zigbee2MQTT:debug 2022-11-30 18:29:19: Datapoint '106' with value '77' not defined for '_TZE200_d0yu2xgi'
9979
```
10080

101-
A `commandDataReport` (corresponding to the `dataReport` type) and `commandDataResponse` (corresponding to `dataResponse`) message may contain multiple data point values. `dpv_number` is the index of the data point value in the payload (0 being the first).
81+
Next we have to find out what this datapoint means (`106` in this example), there are different ways to do this:
82+
- [Find TuYa datapoint using the TuYa gateway](./03_find_tuya_data_points.md) (easiest but requires TuYa gateway)
83+
- Check if an already supported TuYa device has this datapoint mapped ([search](https://github.com/Koenkk/zigbee-herdsman-converters/search?q=tuyaDatapoints))
84+
- Guess based on the value
10285

103-
The example python script [read_tuya_dump.py](https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/scripts/read_tuya_dump.py) is able to parse this file. It's pre-filled with Saswell data points, but should be easy to modify it to work with your device if needed. On a linux computer/Raspberry Pi you can do `tail -f -n +0 data/tuya.dump.txt | read_tuya_dump.py` to get real time view of what your device is sending.
86+
For this device we know that datapoint `106` is the humidity, we can now update the `exposes` and `tuyaDatapoints` section of the external converter:
10487

105-
#### tz.tuya_data_point_test
106-
This converter will allow you to send arbitrary data point to Tuya device, you only need to publish a message in the format `datatype,dp,data` to `zigbee2mqtt/{device_friendly_name}/set/tuya_data_point_test` MQTT topic
107-
108-
### 5. Adding your first data point
109-
Let's assume we want to add the heating setpoint of the Saswell thermostat first.
110-
111-
As the log message for the data point did not contain a suitable existing definition, first add the `saswellHeatingSetpoint` data point to `dataPoints` in `node_modules/zigbee-herdsman-converters/lib/tuya.js` with value `103`.
112-
113-
Then add to `node_modules/zigbee-herdsman-converters/converters/fromZigbee.js`:
114-
```js
115-
saswell_thermostat: {
116-
cluster: 'manuSpecificTuya',
117-
type: ['commandDataResponse', 'commandDataReport'],
118-
convert: (model, msg, publish, options, meta) => {
119-
const result = {};
120-
for (const dpValue of msg.data.dpValues) {
121-
const dp = dpValue.dp; // First we get the data point ID
122-
const value = tuya.getDataValue(dpValue); // This function will take care of converting the data to proper JS type
123-
switch (dp) {
124-
case tuya.dataPoints.saswellHeatingSetpoint: // DPID that we added to common
125-
result.current_heating_setpoint = (value / 10).toFixed(1); // value is already converted to a number in JS, and we deduced that it needs to be divided by 10
126-
break;
127-
default:
128-
meta.logger.warn(`zigbee-herdsman-converters:SaswellThermostat: NOT RECOGNIZED DP #${
129-
dp} with data ${JSON.stringify(dpValue)}`); // This will cause zigbee2mqtt to print similar data to what is dumped in tuya.dump.txt
130-
}
131-
}
132-
return result;
133-
},
134-
},
135-
```
136-
137-
Then add to `node_modules/zigbee-herdsman-converters/converters/toZigbee.js`
13888
```js
139-
saswell_thermostat_current_heating_setpoint: {
140-
key: ['current_heating_setpoint'],
141-
convertSet: async (entity, key, value, meta) => {
142-
const temp = Math.round(value * 10);
143-
await tuya.sendDataPointValue(entity, tuya.dataPoints.saswellHeatingSetpoint, temp); // tuya.sendDataPoint* functions take care of converting the data to proper format
144-
},
145-
},
146-
```
147-
148-
The `tuya.sendDataPoint*` functions send a single data point value. In case you
149-
want to send multiple data points at once, you can use the `tuya.sendDataPoints`
150-
function like this:
151-
152-
```
153-
await tuya.sendDataPoints(
154-
entity,
155-
[
156-
tuya.dpValueFromBool(first_dp_id, first_dp_value),
157-
tuya.dpValueFromEnum(second_dp_id, second_dp_value),
158-
],
159-
);
160-
```
161-
162-
Now update your external converter:
163-
```js
164-
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
165-
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
166-
const exposes = require('zigbee-herdsman-converters/lib/exposes');
167-
const reporting = require('zigbee-herdsman-converters/lib/reporting');
168-
const extend = require('zigbee-herdsman-converters/lib/extend');
169-
const e = exposes.presets;
170-
const ea = exposes.access;
171-
172-
const definition = {
173-
fingerprint: [
174-
{modelID: 'TS0601', manufacturerName: '_TZE200_c88teujp'},
175-
],
176-
model: 'SEA802-Zigbee',
177-
vendor: 'Saswell',
178-
description: 'Thermostatic radiator valve',
179-
fromZigbee: [
180-
fz.ignore_basic_report,
181-
fz.tuya_data_point_dump,
182-
fz.saswell_thermostat,
183-
],
184-
toZigbee: [
185-
tz.tuya_data_point_test,
186-
tz.saswell_thermostat_current_heating_setpoint,
187-
],
188-
onEvent: tuya.onEventSetTime,
189-
configure: async (device, coordinatorEndpoint, logger) => {
190-
const endpoint = device.getEndpoint(1);
191-
await bind(endpoint, coordinatorEndpoint, ['genBasic']);
192-
},
19389
exposes: [
194-
// Here you should put all functionality that your device exposes
90+
e.humidity(), // <- added the humdity expose
19591
],
196-
};
197-
198-
module.exports = definition;
92+
meta: {
93+
tuyaDatapoints: [
94+
[8, 'humidity', tuya.valueConverter.raw], // <- mapped the datapoint
95+
],
96+
},
19997
```
20098

201-
Repeat for all data points.
99+
The values in the mapped datapoint are as follows:
100+
1. The datapoint (`8` in this example)
101+
2. The key under which this value should be published in the state (`humidity` in this example)
102+
3. The value converter, this converts the received value before publishing it (`tuya.valueConverter.raw` in this example). There are more value converters available, examples:
103+
- If the value needs to be divided by 10 you can use `tuya.valueConverter.divideBy10`
104+
- If the value needs to be mapped to a string you can use `tuya.valueConverterBasic.lookup({'single': 0, 'double': 1, 'hold': 2})`
105+
- For more examples search for `tuyaDatapoints` in [`tuya.js`](https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/devices/tuya.js).
106+
107+
Repeat this for all datapoints.
202108

203109
### 6. BONUS: Contacting the manufacturer
204-
When contacting a manufacturer of Tuya compatible device DO NOT ask for Zigbee protocol of the device, they usually have no idea how the Tuya radio that they bought communicates over Zigbee. Instead ask for the UART protocol for their device, this should give you a better cooperation. You can also ask them about DPIDs and data formats for their functions.
110+
When contacting a manufacturer of TuYa compatible device DO NOT ask for Zigbee protocol of the device, they usually have no idea how the TuYa radio that they bought communicates over Zigbee. Instead ask for the UART protocol for their device, this should give you a better cooperation. You can also ask them about DPIDs and data formats for their functions.
205111

206112
### 7. BONUS 2: Further reading
207-
You can read more about how the device communicates with Tuya Zigbee radio module [here](https://developer.tuya.com/en/docs/iot/device-development/access-mode-mcu/zigbee-general-solution/tuya-zigbee-module-uart-communication-protocol/tuya-zigbee-module-uart-communication-protocol?id=K9ear5khsqoty)
113+
You can read more about how the device communicates with TuYa Zigbee radio module [here](https://developer.tuya.com/en/docs/iot/device-development/access-mode-mcu/zigbee-general-solution/tuya-zigbee-module-uart-communication-protocol/tuya-zigbee-module-uart-communication-protocol?id=K9ear5khsqoty)

0 commit comments

Comments
 (0)