Skip to content

Instantly share code, notes, and snippets.

@muxa
Created July 16, 2022 08:25
Show Gist options
  • Save muxa/94e29b8896c89da910e4e4a80fc44894 to your computer and use it in GitHub Desktop.
Save muxa/94e29b8896c89da910e4e4a80fc44894 to your computer and use it in GitHub Desktop.
Moes 3 Gang Light Dimmer Switch ZS-USD3-WH-MS (Tuya "_TZE200_vm1gyrso", "TS0601")
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 utils = require('zigbee-herdsman-converters/lib/utils');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;
const fzLocal = {
parse: {
cluster: 'manuSpecificTuya',
type: ['commandDataResponse', 'commandDataReport'],
convert: async (model, msg, publish, options, meta) => {
const result = {};
meta.logger.debug(`MOES FZ msg.data=${JSON.stringify(msg.data)} meta.state=${JSON.stringify(meta.state)}`);
for (const dpValue of msg.data.dpValues) {
const dp = dpValue.dp; // First we get the data point ID
const value = tuya.getDataValue(dpValue); // This function will take care of converting the data to proper JS type
switch (dp) {
case 1:
// {"seq":52224,"dpValues":[{"dp":1,"datatype":1,"data":{"type":"Buffer","data":[1]}}]}
result.state_l1 = value ? "ON" : "OFF"; // value is already converted
// meta.logger.debug(`MOES FZ Button 1: state=${value}`);
// if (value && meta.state[`brightness_l1`]) {
// const brightness = utils.mapNumberRange(meta.state[`brightness_l1`], 0, 254, 0, 1000);
// meta.logger.debug(`MOES FZ Brightness 1: brightness=${brightness}`);
// await tuya.sendDataPointValue(entity, dp+1, brightness, 'dataRequest', 1);
// }
break;
case 2:
// {"dp":2,"datatype":2,"data":{"type":"Buffer","data":[0,0,1,64]}}
// max: 1000 [0,0,3,197]
// min: 10 [0,0,0,10]
result.brightness_l1 = utils.mapNumberRange(value, 0, 1000, 0, 254);
//meta.logger.debug(`MOES FZ Button 1: brightesss=${value}`);
break;
case 7:
result.state_l2 = value ? "ON" : "OFF"; // value is already converted
//meta.logger.debug(`MOES FZ Button 2: state=${value}`);
break;
case 8:
// {"dp":8,"datatype":2,"data":{"type":"Buffer","data":[0,0,3,102]}}
result.brightness_l2 = utils.mapNumberRange(value, 0, 1000, 0, 254);
//meta.logger.debug(`MOES FZ Button 2: brightesss=${value}`);
break;
case 15:
result.state_l3 = value ? "ON" : "OFF"; // value is already converted
//meta.logger.debug(`MOES FZ Button 3: state=${value}`);
break;
case 16:
// {"dp":16,"datatype":2,"data":{"type":"Buffer","data":[0,0,3,102]}}
result.brightness_l3 = utils.mapNumberRange(value, 0, 1000, 0, 254);
//meta.logger.debug(`MOES FZ Button 3: brightesss=${value}`);
break;
default:
meta.logger.warn(`zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #${
dp} with data ${JSON.stringify(dpValue)}`); // This will cause zigbee2mqtt to print similar data to what is dumped in tuya.dump.txt
}
}
return result;
},
}
}
const tzLocal = {
tuya_switch_state: {
key: ['state'],
convertSet: async (entity, key, value, meta) => {
meta.logger.debug(`MOES TZ key=${key} value=${value} meta.endpoint_name=${meta.endpoint_name} meta.state=${JSON.stringify(meta.state)}`);
// key=state value=OFF
const lookup = {l1: 1, l2: 7, l3: 15};
const dp = lookup[meta.endpoint_name];
// if (value === 'ON' && meta.state[`brightness_${meta.endpoint_name}`]) {
// const brightness = utils.mapNumberRange(meta.state[`brightness_${meta.endpoint_name}`], 0, 254, 0, 1000);
// meta.logger.debug(`MOES FZ ${meta.endpoint_name}: brightness=${brightness}`);
// await tuya.sendDataPoints(entity, [
// tuya.dpValueFromBool(dp, value === 'ON'),
// tuya.dpValueFromIntValue(dp+1, brightness),
// ], 'dataRequest', 1);
// } else {
await tuya.sendDataPointBool(entity, dp, value === 'ON');
// }
},
},
tuya_dimmer_level: {
key: ['brightness_min', 'min_brightness', 'max_brightness', 'brightness', 'brightness_percent', 'level'],
convertSet: async (entity, key, value, meta) => {
//meta.logger.debug(`MOES TZ key=${key} value=${value} meta.endpoint_name=${meta.endpoint_name} meta.state=${JSON.stringify(meta.state)}`);
// key=brightness value=128
const lookup = {l1: 2, l2: 8, l3: 16};
const dp = lookup[meta.endpoint_name];
if (key == "brightness") {
// upscale to 1000
if (value >= 0 && value <= 254) {
newValue = utils.mapNumberRange(value, 0, 254, 0, 1000);
// Always use same transid as tuya_dimmer_state (https://github.com/Koenkk/zigbee2mqtt/issues/6366)
await tuya.sendDataPointValue(entity, dp, newValue, 'dataRequest', 1);
} else {
throw new Error('Dimmer brightness is out of range 0..254');
}
} else {
meta.logger.warn(`MOES TZ unsupported key=${key} value=${value}`);
}
},
},
}
const definition = {
zigbeeModel: ['TS0601'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
model: 'ZS-USD3-WH-MS', // Vendor model number, look on the device for a model number
vendor: '_TZE200_vm1gyrso', // Vendor of the device (only used for documentation and startup logging)
description: 'Moes 3 Gang Light Dimmer Switch', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
fromZigbee: [/*fz.tuya_dimmer,*/
fz.ignore_basic_report,
//fz.tuya_data_point_dump, // // This is a debug converter, it will be described in the next part
fzLocal.parse,
],
toZigbee: [
//tz.tuya_data_point_test, // Another debug converter
tzLocal.tuya_switch_state,
tzLocal.tuya_dimmer_level,
],
onEvent: tuya.onEventSetTime,
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
},
exposes: [
e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).withEndpoint('l1'),
e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).withEndpoint('l2'),
e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).withEndpoint('l3'),
],
endpoint: (device) => {
return {'l1': 1, 'l2': 1, 'l3': 1};
},
};
// data types: https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/lib/tuya.js
// Status report:
// Received Zigbee message from 'Moes 3 Gang Dimmer', type 'attributeReport', cluster 'genBasic', data '{"65506":32,"65508":0,"appVersion":64}' from endpoint 1 with groupID 0
// Button 1
// ON:
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":1}],"seq":44288}' from endpoint 1 with groupID 0
// Received Tuya DataPoint #1 from 0xa4c1387aacc2a6d1 with raw data '{"dp":1,"datatype":1,"data":{"type":"Buffer","data":[1]}}': type='commandDataResponse', datatype='bool', value='true', known DP# usage: ["state","moesSsystemMode","tuyaSabCOalarm","moes105DimmerState1","trsPresenceState","trsfPresenceState","haozeeSystemMode","nousTemperature","wlsWaterLeak","AM02Control","garageDoorTrigger","connecteState","tshpsPresenceState","lmsState","alectoSmokeState"]
// OFF
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":1}],"seq":44544}' from endpoint 1 with groupID 0
// Dimming
// Received Tuya DataPoint #2 from 0xa4c1387aacc2a6d1 with raw data '{"dp":2,"datatype":2,"data":{"type":"Buffer","data":[0,0,2,238]}}': type='commandDataResponse', datatype='value', value='750', known DP# usage: ["heatingSetpoint","coverPosition","eardaDimmerLevel","moesHold","moesSheatingSetpoint","silvercrestChangeMode","tuyaSabCO2","tuyaSahkMP25","tuyaSabCO","moes105DimmerLevel1","trsSensitivity","trsfSensitivity","tvMode","haozeeHeatingSetpoint","nousHumidity","tIlluminanceLux","evanellMode","AM02PercentControl","connecteMode","tshpscSensitivity","alectoSmokeValue"]
// Button 2
// ON:
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":7}],"seq":43776}' from endpoint 1 with groupID 0
// OFF:
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":7}],"seq":45056}' from endpoint 1 with groupID 0
// Button 3:
// ON:
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":15}],"seq":45312}' from endpoint 1 with groupID 0
// OFF:
// type 'commandDataResponse', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":15}],"seq":45568}' from endpoint 1 with groupID 0
// Button 2:
// Received unexpected Tuya DataPoint #7 from 0xa4c1387aacc2a6d1 with raw data '{"dp":7,"datatype":1,"data":{"type":"Buffer","data":[0]}}': type='commandDataResponse', datatype='bool', value='false', known DP# usage: ["childLock","coverChange","moesSreset","moesCoverBacklight","neoAODuration","moes105DimmerState2","haozeeWindowState","thitIlluminanceLux","AM02WorkState"]
// Button 3:
// Received unexpected Tuya DataPoint #15 from 0xa4c1387aacc2a6d1 with raw data '{"dp":15,"datatype":1,"data":{"type":"Buffer","data":[1]}}': type='commandDataResponse', datatype='bool', value='true', known DP# usage: ["neoAOBattPerc","haozeeMinTemp","nousHumiAlarm","moesSwitchIndicateLight","alectoBatteryPercentage"]
module.exports = definition;
/*
dimmerMinLevel: 3, = 10
dimmerMaxLevel: 5 = 1000
silvercrestSetEffect: 6, = 0
mode: 4, = 0
dimmerMaxLevel 11 = 1000
dimmerMinLevel 9 = 10
dimmerMaxLevel 19 = 1000
dimmerMinLevel 17 = 10
moesSwitchPowerOnBehavior: 14, = 0
arning 2022-07-16 19:12:45zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #5 with data {"dp":5,"datatype":2,"data":{"type":"Buffer","data":[0,0,3,232]}}
Warning 2022-07-16 19:12:45zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #3 with data {"dp":3,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,10]}}
Warning 2022-07-16 19:12:45zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #6 with data {"dp":6,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,0]}}
Warning 2022-07-16 19:12:45zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #4 with data {"dp":4,"datatype":4,"data":{"type":"Buffer","data":[0]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #11 with data {"dp":11,"datatype":2,"data":{"type":"Buffer","data":[0,0,3,232]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #9 with data {"dp":9,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,10]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #12 with data {"dp":12,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,0]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #10 with data {"dp":10,"datatype":4,"data":{"type":"Buffer","data":[0]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #19 with data {"dp":19,"datatype":2,"data":{"type":"Buffer","data":[0,0,3,232]}}
Warning 2022-07-16 19:12:46zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #17 with data {"dp":17,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,10]}}
Warning 2022-07-16 19:12:47zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #20 with data {"dp":20,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,0]}}
Warning 2022-07-16 19:12:47zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #20 with data {"dp":20,"datatype":2,"data":{"type":"Buffer","data":[0,0,0,0]}}
Warning 2022-07-16 19:12:47zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #18 with data {"dp":18,"datatype":4,"data":{"type":"Buffer","data":[0]}}
Warning 2022-07-16 19:12:47zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #21 with data {"dp":21,"datatype":4,"data":{"type":"Buffer","data":[1]}}
Warning 2022-07-16 19:12:47zigbee-herdsman-converters:MOES: NOT RECOGNIZED DP #14 with data {"dp":14,"datatype":4,"data":{"type":"Buffer","data":[0]}}
*/
@elliottmarter
Copy link

THANK YOU for this.

Got this dimmer working in Z2M!

Might you know why I cannot send "brightness" data to this light via an HA service call?

I can do a normal light.turn_on however if I attempt to add brightness (or any data) it fails to turn on.

@muxa
Copy link
Author

muxa commented Oct 9, 2022

Does the dimmer work after you turn it on @elliottmarter? It does more me. I have not had a change to improve this.
I also found this that might help find solution to the problems in my code: Koenkk/zigbee2mqtt#12328 (comment)

@elliottmarter
Copy link

I managed to get it working with an mqtt publish, as per this guide for the 2 gang dimmer.

https://www.zigbee2mqtt.io/devices/ZS-EUD.html

Thanks for replying! I will take a look at the cleaned up converter file now, thanks again :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment