Skip to content

Commit

Permalink
Improve support for the SUTON STB3L-125-ZJ DIN rail RCBO (TZE204_wbha…
Browse files Browse the repository at this point in the history
…espm)

Signed-off-by: Ondrej Pecta <opecta@gmail.com>
  • Loading branch information
octa22 committed Sep 23, 2024
1 parent 952b08d commit ea216ea
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/devices/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5567,6 +5567,69 @@ const definitions: DefinitionWithExtend[] = [
tuya.exposes.currentWithPhase('c'),
e.temperature(),
e.binary('leakage_test', ea.STATE_SET, 'ON', 'OFF').withDescription('Turn ON to perform a leagage test'),
e
.binary('over_current_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('over_current_threshold', ea.STATE_SET)
.withUnit('A')
.withDescription('Setup the value on the device')
.withValueMax(1)
.withValueMin(63),
e
.binary('over_voltage_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('over_voltage_threshold', ea.STATE_SET)
.withUnit('V')
.withDescription('Setup value on the device')
.withValueMax(250)
.withValueMin(300),
e
.binary('under_voltage_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('under_voltage_threshold', ea.STATE_SET)
.withUnit('V')
.withDescription('Setup value on the device')
.withValueMax(150)
.withValueMin(200),
e
.binary('insufficient_balance_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('insufficient_balance_threshold', ea.STATE_SET)
.withUnit('kWh')
.withDescription('Setup value on the device')
.withValueMax(1)
.withValueMin(65535),
e
.binary('overload_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('overload_threshold', ea.STATE_SET)
.withUnit('kW')
.withDescription('Setup value on the device')
.withValueMax(1)
.withValueMin(25),
e
.binary('leakage_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('leakage_threshold', ea.STATE_SET)
.withUnit('mA')
.withDescription('Setup value on the device')
.withValueMax(10)
.withValueMin(90),
e
.binary('high_temperature_breaker', ea.STATE_SET, 'ON', 'OFF')
.withDescription('OFF - alarm only, ON - relay will turn off when threshold reached'),
e
.numeric('high_temperature_threshold', ea.STATE_SET)
.withUnit('°C')
.withDescription('Setup value on the device')
.withValueMax(40)
.withValueMin(100),
],
meta: {
tuyaDatapoints: [
Expand Down Expand Up @@ -5599,6 +5662,22 @@ const definitions: DefinitionWithExtend[] = [
}),
],
[16, 'state', tuya.valueConverter.onOff],
[17, null, tuya.valueConverter.threshold_2],
[17, 'overload_breaker', tuya.valueConverter.threshold_2],
[17, 'overload_threshold', tuya.valueConverter.threshold_2],
[17, 'leakage_threshold', tuya.valueConverter.threshold_2],
[17, 'leakage_breaker', tuya.valueConverter.threshold_2],
[17, 'high_temperature_threshold', tuya.valueConverter.threshold_2],
[17, 'high_temperature_breaker', tuya.valueConverter.threshold_2],
[18, null, tuya.valueConverter.threshold_3],
[18, 'over_current_threshold', tuya.valueConverter.threshold_3],
[18, 'over_current_breaker', tuya.valueConverter.threshold_3],
[18, 'over_voltage_threshold', tuya.valueConverter.threshold_3],
[18, 'over_voltage_breaker', tuya.valueConverter.threshold_3],
[18, 'under_voltage_threshold', tuya.valueConverter.threshold_3],
[18, 'under_voltage_breaker', tuya.valueConverter.threshold_3],
[18, 'insufficient_balance_threshold', tuya.valueConverter.threshold_3],
[18, 'insufficient_balance_breaker', tuya.valueConverter.threshold_3],
[21, 'leakage_test', tuya.valueConverter.onOff], // Leakage test
[102, 'temperature', tuya.valueConverter.divideBy10],
// Ignored for now; we don't know what the values mean
Expand Down
164 changes: 164 additions & 0 deletions src/lib/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,170 @@ export const valueConverter = {
};
},
},
threshold_2: {
to: async (v: number, meta: Tz.Meta) => {
const entity = meta.device.endpoints[0];
const onOffLookup = {on: 1, off: 0};
const sendCommand = utils.getMetaValue(entity, meta.mapped, 'tuyaSendCommand', undefined, 'dataRequest');

if (meta.message.overload_breaker) {
const threshold = meta.state['overload_threshold'];
const buf = Buffer.from([
3,
utils.getFromLookup(meta.message.overload_breaker, onOffLookup),
0,
utils.toNumber(threshold, 'overload_threshold'),
]);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
} else if (meta.message.overload_threshold) {
const state = meta.state['overload_breaker'];
const buf = Buffer.from([
3,
utils.getFromLookup(state, onOffLookup),
0,
utils.toNumber(meta.message.overload_threshold, 'overload_threshold'),
]);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
} else if (meta.message.leakage_threshold) {
const state = meta.state['leakage_breaker'];
const buf = Buffer.alloc(8);
buf.writeUInt8(4, 4);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 5);
buf.writeUInt16BE(utils.toNumber(meta.message.leakage_threshold, 'leakage_threshold'), 6);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
} else if (meta.message.leakage_breaker) {
const threshold = meta.state['leakage_threshold'];
const buf = Buffer.alloc(8);
buf.writeUInt8(4, 4);
buf.writeUInt8(utils.getFromLookup(meta.message.leakage_breaker, onOffLookup), 5);
buf.writeUInt16BE(utils.toNumber(threshold, 'leakage_threshold'), 6);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
} else if (meta.message.high_temperature_threshold) {
const state = meta.state['high_temperature_breaker'];
const buf = Buffer.alloc(12);
buf.writeUInt8(5, 8);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 9);
buf.writeUInt16BE(utils.toNumber(meta.message.high_temperature_threshold, 'high_temperature_threshold'), 10);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
} else if (meta.message.high_temperature_breaker) {
const threshold = meta.state['high_temperature_threshold'];
const buf = Buffer.alloc(12);
buf.writeUInt8(5, 8);
buf.writeUInt8(utils.getFromLookup(meta.message.high_temperature_breaker, onOffLookup), 9);
buf.writeUInt16BE(utils.toNumber(threshold, 'high_temperature_threshold'), 10);
await sendDataPointRaw(entity, 17, Array.from(buf), sendCommand, 1);
}
},
from: (v: string) => {
const data = Buffer.from(v, 'base64');
const result: KeyValue = {};
const lookup: KeyValue = {0: 'OFF', 1: 'ON'};
const alarmLookup: KeyValue = {3: 'overload', 4: 'leakage', 5: 'high_temperature'};

const len = data.length;
let i = 0;
while (i < len) {
if (Object.prototype.hasOwnProperty.call(alarmLookup, data[i])) {
const alarm = alarmLookup[data[i]];
const state = lookup[data[i + 1]];
const threshold = data[i + 3] | (data[i + 2] << 8);
result[`${alarm}_breaker`] = state;
result[`${alarm}_threshold`] = threshold;
}
i += 4;
}
return result;
},
},
threshold_3: {
to: async (v: number, meta: Tz.Meta) => {
const entity = meta.device.endpoints[0];
const onOffLookup = {on: 1, off: 0};
const sendCommand = utils.getMetaValue(entity, meta.mapped, 'tuyaSendCommand', undefined, 'dataRequest');

if (meta.message.over_current_threshold) {
const state = meta.state['over_current_breaker'];
const buf = Buffer.from([
1,
utils.getFromLookup(state, onOffLookup),
0,
utils.toNumber(meta.message.over_current_threshold, 'over_current_threshold'),
]);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.over_current_breaker) {
const threshold = meta.state['over_current_threshold'];
const buf = Buffer.from([
1,
utils.getFromLookup(meta.message.over_current_breaker, onOffLookup),
0,
utils.toNumber(threshold, 'over_current_threshold'),
]);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.over_voltage_threshold) {
const state = meta.state['over_voltage_breaker'];
const buf = Buffer.alloc(8);
buf.writeUInt8(3, 4);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 5);
buf.writeUInt16BE(utils.toNumber(meta.message.over_voltage_threshold, 'over_voltage_threshold'), 6);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.over_voltage_breaker) {
const threshold = meta.state['over_voltage_threshold'];
const buf = Buffer.alloc(8);
buf.writeUInt8(3, 4);
buf.writeUInt8(utils.getFromLookup(meta.message.over_voltage_breaker, onOffLookup), 5);
buf.writeUInt16BE(utils.toNumber(threshold, 'over_voltage_threshold'), 6);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.under_voltage_threshold) {
const state = meta.state['under_voltage_breaker'];
const buf = Buffer.alloc(12);
buf.writeUInt8(4, 8);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 9);
buf.writeUInt16BE(utils.toNumber(meta.message.under_voltage_threshold, 'under_voltage_threshold'), 10);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.under_voltage_breaker) {
const threshold = meta.state['under_voltage_threshold'];
const buf = Buffer.alloc(12);
buf.writeUInt8(4, 8);
buf.writeUInt8(utils.getFromLookup(meta.message.under_voltage_breaker, onOffLookup), 9);
buf.writeUInt16BE(utils.toNumber(threshold, 'under_voltage_threshold'), 10);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.insufficient_balance_threshold) {
const state = meta.state['insufficient_balance_breaker'];
const buf = Buffer.alloc(16);
buf.writeUInt8(8, 12);
buf.writeUInt8(utils.getFromLookup(state, onOffLookup), 13);
buf.writeUInt16BE(utils.toNumber(meta.message.insufficient_balance_threshold, 'insufficient_balance_threshold'), 14);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
} else if (meta.message.insufficient_balance_breaker) {
const threshold = meta.state['insufficient_balance_threshold'];
const buf = Buffer.alloc(16);
buf.writeUInt8(8, 12);
buf.writeUInt8(utils.getFromLookup(meta.message.insufficient_balance_breaker, onOffLookup), 13);
buf.writeUInt16BE(utils.toNumber(threshold, 'insufficient_balance_threshold'), 14);
await sendDataPointRaw(entity, 18, Array.from(buf), sendCommand, 1);
}
},
from: (v: string) => {
const data = Buffer.from(v, 'base64');
const result: KeyValue = {};
const lookup: KeyValue = {0: 'OFF', 1: 'ON'};
const alarmLookup: KeyValue = {1: 'over_current', 3: 'over_voltage', 4: 'under_voltage', 8: 'insufficient_balance'};

const len = data.length;
let i = 0;
while (i < len) {
if (Object.prototype.hasOwnProperty.call(alarmLookup, data[i])) {
const alarm = alarmLookup[data[i]];
const state = lookup[data[i + 1]];
const threshold = data[i + 3] | (data[i + 2] << 8);
result[`${alarm}_breaker`] = state;
result[`${alarm}_threshold`] = threshold;
}
i += 4;
}
return result;
},
},
selfTestResult: valueConverterBasic.lookup({checking: 0, success: 1, failure: 2, others: 3}),
lockUnlock: valueConverterBasic.lookup({LOCK: true, UNLOCK: false}),
localTempCalibration1: {
Expand Down

0 comments on commit ea216ea

Please sign in to comment.