-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Link
No official product page available. Device sold as "NovaDigital 8-gang Zigbee wall switch" (Brazil).
Database entry
{ "description": "8-gang wall switch (DP 1β6, 101, 102)", "exposes": [ { "description": "Light 1 (DP1)", "endpoint": "l1", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l1", "label": "State", "name": "state", "property": "state_l1", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 2 (DP2)", "endpoint": "l2", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l2", "label": "State", "name": "state", "property": "state_l2", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 3 (DP3)", "endpoint": "l3", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l3", "label": "State", "name": "state", "property": "state_l3", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 4 (DP4)", "endpoint": "l4", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l4", "label": "State", "name": "state", "property": "state_l4", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 5 (DP5)", "endpoint": "l5", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l5", "label": "State", "name": "state", "property": "state_l5", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 6 (DP6)", "endpoint": "l6", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l6", "label": "State", "name": "state", "property": "state_l6", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 7 (DP101)", "endpoint": "l7", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l7", "label": "State", "name": "state", "property": "state_l7", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "description": "Light 8 (DP102)", "endpoint": "l8", "features": [ { "access": 7, "description": "On/off state of the switch", "endpoint": "l8", "label": "State", "name": "state", "property": "state_l8", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" } ], "type": "switch" }, { "access": 1, "category": "diagnostic", "description": "Link quality (signal strength)", "label": "Linkquality", "name": "linkquality", "property": "linkquality", "type": "numeric", "unit": "lqi", "value_max": 255, "value_min": 0 } ], "model": "TS0601_novadigital_8gang_dp1_6_101_102", "options": [], "source": "external", "supports_ota": false, "vendor": "NovaDigital" }
Zigbee2MQTT version
2.7.2
External converter
/**
* NovaDigital 8-gang wall switch (Tuya TS0601)
*
* Fingerprint:
* - modelID: TS0601
* - manufacturerName: _TZE204_72bewjky
*
* DP layout (datatype=1 booleans):
* - l1..l6 -> DP 1..6
* - l7 -> DP 101
* - l8 -> DP 102
*
* Notes:
* - Some datapoints may arrive as datatype=2 "sync/noise" packets; these are ignored.
* - This converter supports 2-way feedback (physical -> HA/Z2M and UI -> relay).
*/
// Toggle verbose logs (default OFF for upstream submission)
const DEBUG = false;
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
// Endpoint -> DP mapping (your verified physical order)
const dpMap = {
l1: 1,
l2: 2,
l3: 3,
l4: 4,
l5: 5,
l6: 6,
l7: 101,
l8: 102,
};
// DP -> endpoint lookup for fast mapping
const dpToEndpoint = Object.fromEntries(
Object.entries(dpMap).map(([ep, dp]) => [String(dp), ep]),
);
function log(...args) {
if (DEBUG) console.log(...args);
}
// Extract first byte from: [1], Buffer, Uint8Array, {type:'Buffer', data:[1]}, etc.
function extractFirstByte(raw) {
if (raw == null) return null;
// raw might be: [1]
if (Array.isArray(raw)) return raw[0];
// raw might be: Buffer / Uint8Array (indexable)
if (typeof raw[0] === 'number') return raw[0];
// raw might be: {type:'Buffer', data:[1]}
if (raw && raw.data != null) {
const d = raw.data;
if (Array.isArray(d)) return d[0];
if (d && typeof d[0] === 'number') return d[0];
// sometimes nested again: {data:{data:[1]}}
if (d && d.data != null) {
const dd = d.data;
if (Array.isArray(dd)) return dd[0];
if (dd && typeof dd[0] === 'number') return dd[0];
}
}
return null;
}
const fzLocal = {
novadigital_8gang: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse'],
convert: (model, msg) => {
try {
const dpValues = msg?.data?.dpValues;
if (!Array.isArray(dpValues) || dpValues.length === 0) return {};
log(`\nβ¨ [8-GANG SWITCH] Incoming Tuya Report π₯`);
log(`β Raw dpValues: ${JSON.stringify(dpValues)}\n`);
const stateUpdate = {};
for (const dpValue of dpValues) {
const dp = dpValue.dp;
const datatype = dpValue.datatype;
// Only care about boolean relay reports
if (datatype !== 1) {
if (DEBUG) {
log(
`π DP Report β π DP=${dp} | π¦ datatype=${datatype} | (ignored non-bool)`,
);
}
continue;
}
const ep = dpToEndpoint[String(dp)];
if (!ep) {
log(`π DP Report β π DP=${dp} | π¦ datatype=${datatype} | (unknown DP)`);
continue;
}
const val = extractFirstByte(dpValue.data);
log(
`π DP Report β π DP=${dp} | π¦ datatype=${datatype} | π‘ val=${val} | π― ep=${ep}`,
);
if (val === null) continue;
const newState = val === 1 ? 'ON' : 'OFF';
stateUpdate[`state_${ep}`] = newState;
log(` β β
Matched ${ep.toUpperCase()} (DP ${dp}) β ${newState}`);
}
return stateUpdate;
} catch (err) {
console.log('π₯ Error in novadigital_8gang convert:', err);
return {};
}
},
},
};
const tzLocal = {
novadigital_8gang: {
key: ['state'],
convertSet: async (entity, key, value, meta) => {
const ep = meta?.endpoint_name;
if (!ep || !dpMap[ep]) return;
const upperVal = String(value).toUpperCase();
const dp = dpMap[ep];
const boolVal = upperVal === 'ON';
await tuya.sendDataPointBool(entity, dp, boolVal);
return { [`state_${ep}`]: upperVal };
},
},
};
module.exports = {
fingerprint: [{ modelID: 'TS0601', manufacturerName: '_TZE204_72bewjky' }],
model: 'TS0601_novadigital_8gang_dp1_6_101_102',
vendor: 'NovaDigital',
description: '8-gang wall switch (DP 1β6, 101, 102)',
fromZigbee: [fzLocal.novadigital_8gang],
toZigbee: [tzLocal.novadigital_8gang],
exposes: [
e.switch().withEndpoint('l1').withDescription('Light 1 (DP1)'),
e.switch().withEndpoint('l2').withDescription('Light 2 (DP2)'),
e.switch().withEndpoint('l3').withDescription('Light 3 (DP3)'),
e.switch().withEndpoint('l4').withDescription('Light 4 (DP4)'),
e.switch().withEndpoint('l5').withDescription('Light 5 (DP5)'),
e.switch().withEndpoint('l6').withDescription('Light 6 (DP6)'),
e.switch().withEndpoint('l7').withDescription('Light 7 (DP101)'),
e.switch().withEndpoint('l8').withDescription('Light 8 (DP102)'),
],
meta: { multiEndpoint: true },
endpoint: () => ({
l1: 1, l2: 1, l3: 1, l4: 1,
l5: 1, l6: 1, l7: 1, l8: 1,
}),
};What does/doesn't work with the external definition?
β What works
- All 8 physical buttons are exposed as independent switches (l1βl8)
- Full 2-way state feedback:
- Physical button presses update state in Zigbee2MQTT and Home Assistant
- UI toggles correctly control the physical relays
- Device acts as a Zigbee router
- Stable operation after reboot
- Works with multiEndpoint=true
- Device uses a non-standard Tuya DP layout:
- l1βl6 β DP 1β6
- l7 β DP 101
- l8 β DP 102
- Device also sends datatype=2 "noise/sync" datapoints (e.g. DP 7, 12) which must be ignored
- Using incorrect DP values (e.g. DP13) causes unintended behavior (multiple relays toggling)
β What does not apply
- No scene-only or action-only buttons on this variant
- All 8 buttons are true relays
Notes
Additional observations:
- Physical button layout does not strictly match DP numbering order
- Correct DP mapping was determined by observing raw Tuya datapoint reports
- Multiple devices tested with identical behavior
- Likely sold under different brand names but same _TZE204_72bewjky fingerprint
Happy to submit a PR once validated by maintainers.