Koenkk / zigbee-herdsman-converters

Collection of device converters to be used with zigbee-herdsman
MIT License
882 stars 2.93k forks source link

Zigbee RC-RCBO (TZE200_hkdl5fmv) #2962

Closed kuneev closed 2 years ago

kuneev commented 3 years ago

Hello, i have new Zigbee RC-RCBO and last version z2mqtt. I write the converter and i can only on/off switch. I do not see info about energy, power, voltage (all null) and when i connect the consumer it get many errors. Help plz!

my converter:

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 reporting = require('zigbee-herdsman-converters/lib/reporting'); const extend = require('zigbee-herdsman-converters/lib/extend'); const e = exposes.presets; const ea = exposes.access;

const definition = { fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}], model: 'TS0601_din', vendor: 'TuYa', description: 'Zigbee smart energy meter', fromZigbee: [fz.tuya_dinrail_switch], toZigbee: [tz.tuya_switch_state], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']); }, exposes: [e.switch().setAccess('state', ea.STATE_SET), e.voltage(), e.power(), e.current(), e.energy()],

};

module.exports = definition;

danieledwardgeorgehitchcock commented 3 years ago

It looks like you haven't included any of the converters for energy / power / voltage. You would also need to bind the correct clusters for reporting too

kuneev commented 3 years ago

It looks like you haven't included any of the converters for energy / power / voltage. You would also need to bind the correct clusters for reporting too

Can you help me with this problem?

danieledwardgeorgehitchcock commented 3 years ago

Could you post the database.db entry you have for this devce? That will help me pinpoint the clusters and endpoints that you require..

kuneev commented 3 years ago

Could you post the database.db entry you have for this devce? That will help me pinpoint the clusters and endpoints that you require..

{"id":2,"type":"Router","ieeeAddr":"0x0c4314fffe1a58fb","nwkAddr":38356,"manufId":4098,"manufName":"_TZE200_hkdl5fmv","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,61184],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65503":"\u0000\u0000\u0000\u0000\u0005\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\u0004","65506":31,"65508":0,"modelId":"TS0601","manufacturerName":"_TZE200_hkdl5fmv","powerSource":1,"zclVersion":3,"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":""}},"genOnOff":{"attributes":{}},"seMetering":{"attributes":{"divisor":100,"multiplier":1}},"haElectricalMeasurement":{"attributes":{"acVoltageMultiplier":1,"acVoltageDivisor":1,"acCurrentMultiplier":1,"acCurrentDivisor":1000,"acPowerMultiplier":1,"acPowerDivisor":1}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x00124b00194af38c","endpointID":1},{"cluster":2820,"type":"endpoint","deviceIeeeAddress":"0x00124b00194af38c","endpointID":1},{"cluster":1794,"type":"endpoint","deviceIeeeAddress":"0x00124b00194af38c","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{"configured":1},"lastSeen":1630100101992}

danieledwardgeorgehitchcock commented 3 years ago

I am coding a bit blind without the device in front of me to debug, but could you give this a go?

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.onOff(endpoint);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;
kuneev commented 3 years ago

I am coding a bit blind without the device in front of me to debug, but could you give this a go?

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.onOff(endpoint);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

It doesn`t help me. Switch is working, but so many errors with voltage, power etc

danieledwardgeorgehitchcock commented 3 years ago

Can you try changing the exposed switch entity from e.switch() back to e.switch().setAccess('state', ea.STATE_SET) like in your example above?

Also, have removed your device, restarted Zigbee2MQTT, then re-added the device?

Can you do that (again) and post the log file (at debug level) from the interview onward?

kuneev commented 3 years ago

Can you try changing the exposed switch entity from e.switch() back to e.switch().setAccess('state', ea.STATE_SET) like in your example above?

Also, have removed your device, restarted Zigbee2MQTT, then re-added the device?

Can you do that (again) and post the log file (at debug level) from the interview onward?

Done.

Failed to configure '0x0c4314fffe1a58fb', attempt 3 (Error: ConfigureReporting 0x0c4314fffe1a58fb/1 genOnOff([{"attribute":"onOff","minimumReportInterval":0,"maximumReportInterval":3600,"reportableChange":0}], {"sendWhenActive":false,"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Timeout - 44903 - 1 - 15 - 6 - 7 after 10000ms) at Timeout._onTimeout (/app/node_modules/zigbee-herdsman/src/utils/waitress.ts:64:35) at listOnTimeout (internal/timers.js:557:17) at processTimers (internal/timers.js:500:7))

danieledwardgeorgehitchcock commented 3 years ago

Looking at the other device handlers in the Tuya file in Zigbee Herdsman Converters, I don't think you need the reporting binding for the switch.

I am also not too sure as to whether you need the tz.tuya_switch_state over the standard tz.on_off as your device isn't multi-endpoint.

Try this:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.on_off],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

Do you know if your device has power recovery states too? If so, this looks similar (almost identical now) to the TS011F device handler - you may just want to copy that code into your External Converter and see if you have any joy with that one..?

kuneev commented 3 years ago

Looking at the other device handlers in the Tuya file in Zigbee Herdsman Converters, I don't think you need the reporting binding for the switch.

I am also not too sure as to whether you need the tz.tuya_switch_state over the standard tz.on_off as your device isn't multi-endpoint.

Try this:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.on_off],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

Do you know if your device has power recovery states too? If so, this looks similar (almost identical now) to the TS011F device handler - you may just want to copy that code into your External Converter and see if you have any joy with that one..?

Do not work anything.

error Publish 'get' 'state' to '0x0c4314fffe1a58fb' failed: 'Error: Read 0x0c4314fffe1a58fb/1 genOnOff(["onOff"], {"sendWhenActive":false,"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Status 'UNSUPPORTED_ATTRIBUTE')' info MQTT publish: topic 'zigbee2mqtt/bridge/log', payload '{"message":"Publish 'get' 'state' to '0x0c4314fffe1a58fb' failed: 'Error: Read 0x0c4314fffe1a58fb/1 genOnOff([\"onOff\"], {\"sendWhenActive\":false,\"timeout\":10000,\"disableResponse\":false,\"disableRecovery\":false,\"disableDefaultResponse\":true,\"direction\":0,\"srcEndpoint\":null,\"reservedBits\":0,\"manufacturerCode\":null,\"transactionSequenceNumber\":null,\"writeUndiv\":false}) failed (Status 'UNSUPPORTED_ATTRIBUTE')'","meta":{"friendly_name":"0x0c4314fffe1a58fb"},"type":"zigbee_publish_error"}'

danieledwardgeorgehitchcock commented 3 years ago

What about with the TuYa converters?:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch().setAccess('state', ea.STATE_SET), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;
kuneev commented 3 years ago

What about with the TuYa converters?:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch().setAccess('state', ea.STATE_SET), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

Switch is working, other - not

info MQTT publish: topic 'zigbee2mqtt/0x0c4314fffe1a58fb', payload '{"current":null,"energy":null,"linkquality":78,"power":null,"state":"OFF","voltage":null}' info MQTT publish: topic 'zigbee2mqtt/0x0c4314fffe1a58fb', payload '{"current":null,"energy":null,"linkquality":78,"power":null,"state":"OFF","voltage":null}' warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #9 with data {"status":2,"transid":3,"dp":9,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,0]}} info MQTT publish: topic 'zigbee2mqtt/0x0c4314fffe1a58fb', payload '{"current":null,"energy":null,"linkquality":78,"power":null,"state":"ON","voltage":null}' info MQTT publish: topic 'zigbee2mqtt/0x0c4314fffe1a58fb', payload '{"current":null,"energy":null,"linkquality":78,"power":null,"state":"ON","voltage":null}' warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #9 with data {"status":2,"transid":3,"dp":9,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #101 with data {"status":2,"transid":3,"dp":101,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[8,63,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #102 with data {"status":2,"transid":3,"dp":102,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[0,31,88,0,0,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #103 with data {"status":2,"transid":3,"dp":103,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[0,66,43,0,66,43,0,0,0,0,0,0]}} info MQTT publish: topic 'zigbee2mqtt/0x0c4314fffe1a58fb', payload '{"current":null,"energy":null,"linkquality":73,"power":null,"state":"ON","voltage":null}' warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #101 with data {"status":2,"transid":3,"dp":101,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[8,66,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #102 with data {"status":2,"transid":3,"dp":102,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[0,30,248,0,0,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #103 with data {"status":2,"transid":3,"dp":103,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[0,65,121,0,65,121,0,0,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #104 with data {"status":2,"transid":3,"dp":104,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #105 with data {"status":2,"transid":3,"dp":105,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,38]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #106 with data {"status":2,"transid":3,"dp":106,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #113 with data {"status":2,"transid":3,"dp":113,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,11]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #117 with data {"status":2,"transid":3,"dp":117,"datatype":2,"fn":0,"data":{"type":"Buffer","data":[0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #101 with data {"status":2,"transid":3,"dp":101,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[8,139,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #102 with data {"status":2,"transid":3,"dp":102,"datatype":0,"fn":0,"data":{"type":"Buffer","data":[0,0,178,0,0,0,0,0,0]}} warning zigbee-herdsman-converters:TuyaDinRailSwitch: NOT RECOGNIZED DP #103 with data {"status":2,"transid":3,"dp":103,"datatype":0,"fn":0,"data":{"type":"Buffer","data":

danieledwardgeorgehitchcock commented 3 years ago

Looks like this may need a custom fromZigbee / toZigbee converter

danieledwardgeorgehitchcock commented 3 years ago

Could you try adding the ignore_basic _report converter?

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch().setAccess('state', ea.STATE_SET), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;
kuneev commented 3 years ago

Could you try adding the ignore_basic _report converter?

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch().setAccess('state', ea.STATE_SET), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

still errors

kuneev commented 3 years ago

Could you try adding the ignore_basic _report converter?

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fz.tuya_dinrail_switch, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
    toZigbee: [tz.tuya_switch_state],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
        await reporting.rmsVoltage(endpoint, {change: 5});
        await reporting.rmsCurrent(endpoint, {change: 50});
        await reporting.activePower(endpoint, {change: 10});
        await reporting.currentSummDelivered(endpoint);
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acVoltageMultiplier: 1, acVoltageDivisor: 1, acCurrentMultiplier: 1, acCurrentDivisor: 1000, acPowerMultiplier:1, acPowerDivisor: 1}); //Not Sure If This Is Needed
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1}); //Not Sure If This Is Needed
        device.save(); //Not Sure If This Is Needed
    },
    exposes: [e.switch().setAccess('state', ea.STATE_SET), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
};

module.exports = definition;

Hey, could you add this device to be supported by z2m if I send it to you? You'll get it as a gift afterwards. Shipping is on me.

danieledwardgeorgehitchcock commented 3 years ago

Sure!

danieledwardgeorgehitchcock commented 2 years ago

Hi,

I have been playing with the device and have managed to get the basics out of it (state, temperature, current, voltage, power and history) as well as some other bits.

Please try the below external converter:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const dataPointsLocal = {
    wdykState: 1,
    wdykCountdownTimer: 9,
    wdykFaultCode: 26,
    wdykRelayStatus: 27,
    wdykChildLock: 29,
    wdykVoltage: 101,
    wdykCurrent: 102,
    wdykActivePower: 103,
    wdykLeakageCurrent: 104,
    wdykTemperature: 105,
    wdykRemainingEnergy: 106,
    wdykRechargeEnergy: 107,
    wdykCostParameters: 108,
    wdykLeakageParameters: 109,
    wdykVoltageThreshold: 110,
    wdykCurrentThreshold: 111,
    wdykTemperatureThreshold: 112,
    wdykTotalActivePower: 113,
    wdykEquipmentNumberType: 114,
    wdykClearEnergy: 115,
    wdykLocking: 116,
    wdykTotalReverseActivePower: 117,
    wdykHistoricalVoltage: 118,
    wdykHistoricalCurrent: 119,
};

const tzLocal = {
    wdyk_din: {
        key: ['state',
            'child_lock',
            'countdown_timer'
        ],
        convertSet: async (entity, key, value, meta) => {
            if (key === 'state') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.wdykState, value === 'ON');
            } else if (key === 'child_lock') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.wdykChildLock, value === 'ON');
            } else if (key === 'countdown_timer') {
                await tuya.sendDataPointValue(entity, dataPointsLocal.wdykCountdownTimer, value);
            } else {
                throw new Error(`Not supported: '${key}'`);
            }
        },
    },
};

const fzLocal = {
    wdyk_din: {
        cluster: 'manuSpecificTuya',
        type: ['commandGetData', 'commandSetDataResponse'],
        convert: (model, msg, publish, options, meta) => {
            const dp = msg.data.dp;
            const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
            meta.logger.debug(`from wdyk_din, msg.data.dp=[${dp}], msg.data.datatype=[${msg.data.datatype}], value=[${value}]`);
            switch (dp) {
            case dataPointsLocal.wdykState:
                return {'state': value ? 'ON' : 'OFF'};
            case dataPointsLocal.wdykChildLock:
                return {'child_lock': value ? 'ON' : 'OFF'};
            case dataPointsLocal.wdykVoltage:
                return {'voltage': (value[1] | value[0] << 8) / 10};
            case dataPointsLocal.wdykHistoricalVoltage:
                return {'voltage_rms': (value[1] | value[0] << 8) / 10};
            case dataPointsLocal.wdykCurrent:
                return {'current': value[2] | value[1] << 8};
            case dataPointsLocal.wdykHistoricalCurrent:
                return {'current_rms': value[2] | value[1] << 8};
            case dataPointsLocal.wdykActivePower:
                return {'power': (value[2] | value[1] << 8) / 10};
            case dataPointsLocal.wdykLocking:
                return {'trip_test': value ? true : false};
            case dataPointsLocal.wdykCountdownTimer:
                return {'countdown_timer': value};
            case dataPointsLocal.wdykTemperature:
                return {'temperature': value};
            case dataPointsLocal.wdykRelayStatus:
                const lookup = {0: 'off', 1: 'on', 2: 'previous'};
                return {'power_on_behaviour': lookup[value]};
            default:
                meta.logger.debug(`zigbee-herdsman-converters:wdyk_din:` +
                    `NOT RECOGNIZED DP #${dp} with data ${JSON.stringify(msg.data)}`);
            }
        },
    },
};

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fzLocal.wdyk_din, fz.ignore_basic_report],
    toZigbee: [tzLocal.wdyk_din],
    exposes: [
        exposes.binary('state', ea.STATE_SET, 'ON', 'OFF'),
        exposes.binary('child_lock', ea.STATE_SET, 'ON', 'OFF'),
        exposes.numeric('countdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit('s'),
        exposes.enum('power_on_behaviour', ea.STATE, ['off', 'on', 'previous']),
        exposes.binary('trip_test', ea.STATE, true, false),
        exposes.numeric('voltage', ea.STATE).withUnit('V'),
        exposes.numeric('voltage_rms', ea.STATE).withUnit('V'),
        exposes.numeric('current', ea.STATE).withUnit('mA'),
        exposes.numeric('current_rms', ea.STATE).withUnit('mA'),
        exposes.numeric('power', ea.STATE).withUnit('W'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C')
    ],
};

module.exports = definition;

I will continue to work on this but thought it was important to get the basics up so that the device is at least relatively usable in Zigbee2MQTT

casadeivison commented 2 years ago

Thank you very much @danieledwardgeorgehitchcock now that I have consumption statistics I can do automations. Only here is the solution to add this device.

my model is this: https://i.imgur.com/toR7PlB.jpg

danieledwardgeorgehitchcock commented 2 years ago

Thank you very much @danieledwardgeorgehitchcock now that I have consumption statistics I can do automations. Only here is the solution to add this device.

my model is this: https://i.imgur.com/toR7PlB.jpg

I believe that the WDYK is actually a whitelabel of the HOCH so, the features should be compatible.

Could you send me your database.db entry for your device? and if you have used the tuya_data_point_dump converter, the tuya.dump.txt file would also be beneficial!

casadeivison commented 2 years ago

My database.db file looks like this, I don't know where to find the txt of tuya_data_point_dump

{"id":1,"type":"Coordinator","ieeeAddr":"0x00124b001cd4a0c8","nwkAddr":0,"manufId":0,"epList":[1,2,3,4,5,6,8,10,11,12,13,47,110,242],"endpoints":{"1":{"profId":260,"epId":1,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"2":{"profId":257,"epId":2,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"3":{"profId":260,"epId":3,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"4":{"profId":263,"epId":4,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"5":{"profId":264,"epId":5,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"6":{"profId":265,"epId":6,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"8":{"profId":260,"epId":8,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"10":{"profId":260,"epId":10,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"11":{"profId":260,"epId":11,"devId":1024,"inClusterList":[1281],"outClusterList":[1280,1282],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"12":{"profId":49246,"epId":12,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"13":{"profId":260,"epId":13,"devId":5,"inClusterList":[25],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"47":{"profId":260,"epId":47,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"110":{"profId":260,"epId":110,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"242":{"profId":41440,"epId":242,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}}},"interviewCompleted":true,"meta":{},"lastSeen":1631903123497} {"id":2,"type":"Router","ieeeAddr":"0x842e14fffe11b93c","nwkAddr":33216,"manufId":4098,"manufName":"_TZ3000_rdtixbnu","powerSource":"Mains (single phase)","modelId":"TS0121","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,6,1794,2820],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"modelId":"TS0121","manufacturerName":"_TZ3000_rdtixbnu","powerSource":1,"zclVersion":3,"appVersion":65,"stackVersion":0,"hwVersion":1,"dateCode":""}},"seMetering":{"attributes":{"divisor":100,"multiplier":1,"currentSummDelivered":[0,297]}},"haElectricalMeasurement":{"attributes":{"acVoltageMultiplier":1,"acVoltageDivisor":1,"acCurrentMultiplier":1,"acCurrentDivisor":1000,"acPowerMultiplier":1,"acPowerDivisor":1,"rmsVoltage":120,"rmsCurrent":0,"activePower":0}},"genOnOff":{"attributes":{"onOff":0,"onTime":0,"offWaitTime":0,"tuyaBacklightMode":1,"moesStartUpOnOff":0}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1},{"cluster":2820,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":65,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{"configured":1},"lastSeen":1633067039707} {"id":3,"type":"Router","ieeeAddr":"0x842e14fffe0e1df3","nwkAddr":43483,"manufId":4098,"manufName":"_TZ3000_rdtixbnu","powerSource":"Mains (single phase)","modelId":"TS0121","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,6,1794,2820],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"modelId":"TS0121","manufacturerName":"_TZ3000_rdtixbnu","powerSource":1,"zclVersion":3,"appVersion":65,"stackVersion":0,"hwVersion":1,"dateCode":""}},"seMetering":{"attributes":{"divisor":100,"multiplier":1,"currentSummDelivered":[0,373]}},"haElectricalMeasurement":{"attributes":{"acVoltageMultiplier":1,"acVoltageDivisor":1,"acCurrentMultiplier":1,"acCurrentDivisor":1000,"acPowerMultiplier":1,"acPowerDivisor":1,"rmsVoltage":119,"rmsCurrent":0,"activePower":0}},"genOnOff":{"attributes":{"onOff":0,"onTime":0,"offWaitTime":0,"tuyaBacklightMode":1,"moesStartUpOnOff":0}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1},{"cluster":2820,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":65,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{"configured":1},"lastSeen":1633067039477} {"id":4,"type":"Router","ieeeAddr":"0xcc86ecfffef08584","nwkAddr":3919,"manufId":4098,"manufName":"_TZE200_hkdl5fmv","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,61184],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65503":"\u0000\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\f","65506":31,"65508":0,"modelId":"TS0601","manufacturerName":"_TZE200_hkdl5fmv","powerSource":1,"zclVersion":3,"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":""}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1},{"cluster":2820,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1},{"cluster":1794,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{},"lastSeen":1633067072447} {"id":5,"type":"Router","ieeeAddr":"0xcc86ecfffedae76c","nwkAddr":57065,"manufId":4098,"manufName":"_TZE200_hkdl5fmv","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[0,4,5,61184],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65503":"\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0007","65506":31,"65508":0,"modelId":"TS0601","manufacturerName":"_TZE200_hkdl5fmv","powerSource":1,"zclVersion":3,"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":""}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x00124b001cd4a0c8","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":72,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{},"lastSeen":1633067096153}

danieledwardgeorgehitchcock commented 2 years ago

If your device is id5 (0xcc86ecfffedae76c), then yes - it would appear that my suspicions are correct and the WDYK is a whitelabel of the HOCH, and this external converter should work out of the box with your device.

danieledwardgeorgehitchcock commented 2 years ago

Hi all,

Todays efforts:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const dataPointsLocal = {
    hochState: 1,
    hochCountdownTimer: 9,
    hochFaultCode: 26,
    hochRelayStatus: 27,
    hochChildLock: 29,
    hochVoltage: 101,
    hochCurrent: 102,
    hochActivePower: 103,
    hochLeakageCurrent: 104,
    hochTemperature: 105,
    hochRemainingEnergy: 106,
    hochRechargeEnergy: 107,
    hochCostParameters: 108,
    hochLeakageParameters: 109,
    hochVoltageThreshold: 110,
    hochCurrentThreshold: 111,
    hochTemperatureThreshold: 112,
    hochTotalActivePower: 113,
    hochEquipmentNumberType: 114,
    hochClearEnergy: 115,
    hochLocking: 116,
    hochTotalReverseActivePower: 117,
    hochHistoricalVoltage: 118,
    hochHistoricalCurrent: 119,
};

const tzLocal = {
    hoch_din: {
        key: ['state',
            'child_lock',
            'countdown_timer',
            'power_on_behaviour',
            'trip_test',
            'clear_device_data'
        ],
        convertSet: async (entity, key, value, meta) => {
            if (key === 'state') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochState, value === 'ON');
            } else if (key === 'child_lock') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochChildLock, value === 'ON');
            } else if (key === 'countdown_timer') {
                await tuya.sendDataPointValue(entity, dataPointsLocal.hochCountdownTimer, value);
            } else if (key === 'power_on_behaviour') {
                const lookup = {'off': 0, 'on': 1, 'previous': 2};
                await tuya.sendDataPointEnum(entity, dataPointsLocal.hochRelayStatus, lookup[value], 'sendData');
            } else if (key === 'trip_test') {
                await tuya.sendDataPointRaw(entity, dataPointsLocal.hochLeakageParameters, [01,00,00,00,19,00,00,01], 'sendData');
                return {state: {trip_test_state: 'testing'}};
            } else if (key === 'clear_device_data') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochClearEnergy, true, 'sendData');
            } else {
                throw new Error(`Not supported: '${key}'`);
            }
        },
    },
};

const fzLocal = {
    hoch_din: {
        cluster: 'manuSpecificTuya',
        type: ['commandGetData', 'commandSetDataResponse'],
        convert: (model, msg, publish, options, meta) => {
            const dp = msg.data.dp;
            const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
            const result = {};
            meta.logger.debug(`from hoch_din, msg.data.dp=[${dp}], msg.data.datatype=[${msg.data.datatype}], value=[${value}]`);

            if (dp === dataPointsLocal.hochState) {
                result.state = value ? 'ON' : 'OFF';
                if (value) {
                    result.trip_test_state = 'clear';
                }
            }
            if (dp === dataPointsLocal.hochChildLock) {
                result.child_lock = value ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochVoltage) {
                result.voltage = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochHistoricalVoltage) {
                result.voltage_rms = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochCurrent) {
                result.current = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochHistoricalCurrent) {
                result.current_average = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochActivePower) {
                result.power = (value[2] | value[1] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochLocking) {
                result.trip_test_state = value ? 'testing' : 'clear';
            }
            if (dp === dataPointsLocal.hochCountdownTimer) {
                result.countdown_timer = value;
            }
            if (dp === dataPointsLocal.hochTemperature) {
                result.temperature = value;
            }
            if (dp === dataPointsLocal.hochRelayStatus) {
                const lookup = {
                    0: 'off',
                    1: 'on',
                    2: 'previous'
                };
                result.power_on_behaviour = lookup[value];
            }
            if (dp === dataPointsLocal.hochFaultCode) {
                const lookup = {
                    0: 'clear',
                    1: 'over voltage threshold',
                    2: 'under voltage threshold',
                    4: 'over current threshold',
                    8: 'over temperature threshold',
                    10: 'over leakage current threshold',
                    16: 'trip test'
                };
                result.alarm_state = lookup[value];
            }
            if (dp === dataPointsLocal.hochEquipmentNumberType) {
                result.meter_number = value;
            }
            return result;
        },
    },
};

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    whiteLabel: [
        {vendor: 'HOCH', model: 'ZJSBL7-100Z'},
        {vendor: 'WDYK', model: 'ZJSBL7-100Z'}
    ],
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fzLocal.hoch_din, fz.ignore_basic_report],
    toZigbee: [tzLocal.hoch_din],
    exposes: [
        exposes.binary('state', ea.STATE_SET, 'ON', 'OFF'),
        exposes.text('alarm_state', ea.STATE),
        exposes.binary('child_lock', ea.STATE_SET, 'ON', 'OFF'),
        exposes.numeric('countdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit('s'),
        exposes.enum('power_on_behaviour', ea.STATE_SET, ['off', 'on', 'previous']),
        exposes.enum('trip_test', ea.SET, ['test']),
        exposes.text('trip_test_state', ea.STATE),
        exposes.numeric('voltage', ea.STATE).withUnit('V'),
        exposes.numeric('voltage_rms', ea.STATE).withUnit('V'),
        exposes.numeric('current', ea.STATE).withUnit('mA'),
        exposes.numeric('current_average', ea.STATE).withUnit('mA'),
        exposes.numeric('power', ea.STATE).withUnit('W'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C'),
        exposes.enum('clear_device_data', ea.SET, ['clear']),
        exposes.text('meter_number', ea.STATE)
    ],
};

module.exports = definition;

I am thinking now that the basics are together (plus more), I will create a PR to get this merged?!

danieledwardgeorgehitchcock commented 2 years ago

More goodies today:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const dataPointsLocal = {
    hochState: 1,
    hochCountdownTimer: 9,
    hochFaultCode: 26,
    hochRelayStatus: 27,
    hochChildLock: 29,
    hochVoltage: 101,
    hochCurrent: 102,
    hochActivePower: 103,
    hochLeakageCurrent: 104,
    hochTemperature: 105,
    hochRemainingEnergy: 106,
    hochRechargeEnergy: 107,
    hochCostParameters: 108,
    hochLeakageParameters: 109,
    hochVoltageThreshold: 110,
    hochCurrentThreshold: 111,
    hochTemperatureThreshold: 112,
    hochTotalActivePower: 113,
    hochEquipmentNumberType: 114,
    hochClearEnergy: 115,
    hochLocking: 116,
    hochTotalReverseActivePower: 117,
    hochHistoricalVoltage: 118,
    hochHistoricalCurrent: 119,
};

const tzLocal = {
    hoch_din: {
        key: ['state',
            'child_lock',
            'countdown_timer',
            'power_on_behaviour',
            'trip_test',
            'clear_device_data'
        ],
        convertSet: async (entity, key, value, meta) => {
            if (key === 'state') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochState, value === 'ON');
            } else if (key === 'child_lock') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochChildLock, value === 'ON');
            } else if (key === 'countdown_timer') {
                await tuya.sendDataPointValue(entity, dataPointsLocal.hochCountdownTimer, value);
            } else if (key === 'power_on_behaviour') {
                const lookup = {'off': 0, 'on': 1, 'previous': 2};
                await tuya.sendDataPointEnum(entity, dataPointsLocal.hochRelayStatus, lookup[value], 'sendData');
            } else if (key === 'trip_test') {
                if (value === 'clear') {
                    await tuya.sendDataPointBool(entity, dataPointsLocal.hochLocking, true, 'sendData');
                } else {
                    return {state: {trip_test: 'clear'}};
                }
            } else if (key === 'clear_device_data') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochClearEnergy, true, 'sendData');
            } else {
                throw new Error(`Not supported: '${key}'`);
            }
        },
    },
};

const fzLocal = {
    hoch_din: {
        cluster: 'manuSpecificTuya',
        type: ['commandGetData', 'commandSetDataResponse'],
        convert: (model, msg, publish, options, meta) => {
            const dp = msg.data.dp;
            const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
            const result = {};
            meta.logger.debug(`from hoch_din, msg.data.dp=[${dp}], msg.data.datatype=[${msg.data.datatype}], value=[${value}]`);

            if (dp === dataPointsLocal.hochState) {
                result.state = value ? 'ON' : 'OFF';
                if (value) {
                    result.trip_test = 'clear';
                }
            }
            if (dp === dataPointsLocal.hochChildLock) {
                result.child_lock = value ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochVoltage) {
                result.voltage = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochHistoricalVoltage) {
                result.voltage_rms = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochCurrent) {
                result.current = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochHistoricalCurrent) {
                result.current_average = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochActivePower) {
                result.power = (value[2] | value[1] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochLocking) {
                result.trip_test = value ? 'test' : 'clear';
            }
            if (dp === dataPointsLocal.hochCountdownTimer) {
                result.countdown_timer = value;
            }
            if (dp === dataPointsLocal.hochTemperature) {
                result.temperature = value;
            }
            if (dp === dataPointsLocal.hochRelayStatus) {
                const lookup = {
                    0: 'off',
                    1: 'on',
                    2: 'previous'
                };
                result.power_on_behaviour = lookup[value];
            }
            if (dp === dataPointsLocal.hochFaultCode) {
                const lookup = {
                    0: 'clear',
                    1: 'over voltage threshold',
                    2: 'under voltage threshold',
                    4: 'over current threshold',
                    8: 'over temperature threshold',
                    10: 'over leakage current threshold',
                    16: 'trip test'
                };
                result.alarm = lookup[value];
            }
            if (dp === dataPointsLocal.hochEquipmentNumberType) {
                result.meter_number = value.trim();
            }
            if (dp === dataPointsLocal.hochVoltageThreshold) {
                 result.over_voltage_threshold = (value[1] | value[0] << 8) / 10;
                 result.over_voltage_trip = value[2] ? 'ON' : 'OFF';
                 result.over_voltage_alarm = value[3] ? 'ON' : 'OFF';
                 result.under_voltage_threshold = (value[5] | value[4] << 8) / 10;
                 result.under_voltage_trip = value[6] ? 'ON' : 'OFF';
                 result.under_voltage_alarm = value[7] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochCurrentThreshold) {
                let over_current_value = 0;
                for (let i = 0; i < 3; i++) {
                    over_current_value = over_current_value << 8;
                    over_current_value += value[i];
                }
                result.over_current_threshold = over_current_value;
                result.over_current_trip = value[3] ? 'ON' : 'OFF';
                result.over_current_alarm = value[4] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochTemperatureThreshold) {
                result.over_temperature_threshold = value[0];
                result.over_temperature_trip = value[1] ? 'ON' : 'OFF';
                result.over_temperature_alarm = value[2] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochLeakageParameters) {
                result.self_test_auto_days = value[0];
                result.self_test_auto_hours = value[1];
                result.self_test_auto = value[2] ? 'ON' : 'OFF';
                result.over_leakage_current_threshold = value[4] | value[3] << 8;
                result.over_leakage_current_trip = value[5] ? 'ON' : 'OFF';
                result.over_leakage_current_alarm = value[6] ? 'ON' : 'OFF';
                result.self_test = value[7] ? 'testing' : 'test';
            }
            return result;
        },
    },
};

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    whiteLabel: [
        {vendor: 'HOCH', model: 'ZJSBL7-100Z'},
        {vendor: 'WDYK', model: 'ZJSBL7-100Z'}
    ],
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fzLocal.hoch_din],
    toZigbee: [tzLocal.hoch_din],
    exposes: [
        exposes.text('meter_number', ea.STATE),
        exposes.binary('state', ea.STATE_SET, 'ON', 'OFF'),
        exposes.text('alarm', ea.STATE),
        exposes.binary('trip_test', ea.STATE_SET, 'test', 'clear'),
        exposes.binary('child_lock', ea.STATE_SET, 'ON', 'OFF'),
        exposes.enum('power_on_behaviour', ea.STATE_SET, ['off', 'on', 'previous']),
        exposes.numeric('countdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit('s'),
        exposes.numeric('voltage', ea.STATE).withUnit('V'),
        exposes.numeric('voltage_rms', ea.STATE).withUnit('V'),
        exposes.numeric('current', ea.STATE).withUnit('mA'),
        exposes.numeric('current_average', ea.STATE).withUnit('mA'),
        exposes.numeric('power', ea.STATE).withUnit('W'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C'),
        exposes.numeric('under_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('under_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('under_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('over_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_temperature_threshold', ea.STATE).withUnit('°C'),
        exposes.binary('over_temperature_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_temperature_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('self_test_auto_days', ea.STATE).withValueMin(1).withValueMax(28).withUnit('days'),
        exposes.numeric('self_test_auto_hours', ea.STATE).withValueMin(0).withValueMax(23).withUnit('hours'),
        exposes.binary('self_test_auto', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_leakage_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_leakage_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_leakage_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.binary('self_test', ea.STATE, 'testing', 'test'),
        exposes.enum('clear_device_data', ea.SET, ['clear'])
    ],
};

module.exports = definition;
casadeivison commented 2 years ago

More goodies today:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const dataPointsLocal = {
    hochState: 1,
    hochCountdownTimer: 9,
    hochFaultCode: 26,
    hochRelayStatus: 27,
    hochChildLock: 29,
    hochVoltage: 101,
    hochCurrent: 102,
    hochActivePower: 103,
    hochLeakageCurrent: 104,
    hochTemperature: 105,
    hochRemainingEnergy: 106,
    hochRechargeEnergy: 107,
    hochCostParameters: 108,
    hochLeakageParameters: 109,
    hochVoltageThreshold: 110,
    hochCurrentThreshold: 111,
    hochTemperatureThreshold: 112,
    hochTotalActivePower: 113,
    hochEquipmentNumberType: 114,
    hochClearEnergy: 115,
    hochLocking: 116,
    hochTotalReverseActivePower: 117,
    hochHistoricalVoltage: 118,
    hochHistoricalCurrent: 119,
};

const tzLocal = {
    hoch_din: {
        key: ['state',
            'child_lock',
            'countdown_timer',
            'power_on_behaviour',
            'trip_test',
            'clear_device_data'
        ],
        convertSet: async (entity, key, value, meta) => {
            if (key === 'state') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochState, value === 'ON');
            } else if (key === 'child_lock') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochChildLock, value === 'ON');
            } else if (key === 'countdown_timer') {
                await tuya.sendDataPointValue(entity, dataPointsLocal.hochCountdownTimer, value);
            } else if (key === 'power_on_behaviour') {
                const lookup = {'off': 0, 'on': 1, 'previous': 2};
                await tuya.sendDataPointEnum(entity, dataPointsLocal.hochRelayStatus, lookup[value], 'sendData');
            } else if (key === 'trip_test') {
                if (value === 'clear') {
                    await tuya.sendDataPointBool(entity, dataPointsLocal.hochLocking, true, 'sendData');
                } else {
                    return {state: {trip_test: 'clear'}};
                }
            } else if (key === 'clear_device_data') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochClearEnergy, true, 'sendData');
            } else {
                throw new Error(`Not supported: '${key}'`);
            }
        },
    },
};

const fzLocal = {
    hoch_din: {
        cluster: 'manuSpecificTuya',
        type: ['commandGetData', 'commandSetDataResponse'],
        convert: (model, msg, publish, options, meta) => {
            const dp = msg.data.dp;
            const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
            const result = {};
            meta.logger.debug(`from hoch_din, msg.data.dp=[${dp}], msg.data.datatype=[${msg.data.datatype}], value=[${value}]`);

            if (dp === dataPointsLocal.hochState) {
                result.state = value ? 'ON' : 'OFF';
                if (value) {
                    result.trip_test = 'clear';
                }
            }
            if (dp === dataPointsLocal.hochChildLock) {
                result.child_lock = value ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochVoltage) {
                result.voltage = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochHistoricalVoltage) {
                result.voltage_rms = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochCurrent) {
                result.current = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochHistoricalCurrent) {
                result.current_average = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochActivePower) {
                result.power = (value[2] | value[1] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochLocking) {
                result.trip_test = value ? 'test' : 'clear';
            }
            if (dp === dataPointsLocal.hochCountdownTimer) {
                result.countdown_timer = value;
            }
            if (dp === dataPointsLocal.hochTemperature) {
                result.temperature = value;
            }
            if (dp === dataPointsLocal.hochRelayStatus) {
                const lookup = {
                    0: 'off',
                    1: 'on',
                    2: 'previous'
                };
                result.power_on_behaviour = lookup[value];
            }
            if (dp === dataPointsLocal.hochFaultCode) {
                const lookup = {
                    0: 'clear',
                    1: 'over voltage threshold',
                    2: 'under voltage threshold',
                    4: 'over current threshold',
                    8: 'over temperature threshold',
                    10: 'over leakage current threshold',
                    16: 'trip test'
                };
                result.alarm = lookup[value];
            }
            if (dp === dataPointsLocal.hochEquipmentNumberType) {
                result.meter_number = value.trim();
            }
            if (dp === dataPointsLocal.hochVoltageThreshold) {
                 result.over_voltage_threshold = (value[1] | value[0] << 8) / 10;
                 result.over_voltage_trip = value[2] ? 'ON' : 'OFF';
                 result.over_voltage_alarm = value[3] ? 'ON' : 'OFF';
                 result.under_voltage_threshold = (value[5] | value[4] << 8) / 10;
                 result.under_voltage_trip = value[6] ? 'ON' : 'OFF';
                 result.under_voltage_alarm = value[7] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochCurrentThreshold) {
                let over_current_value = 0;
                for (let i = 0; i < 3; i++) {
                    over_current_value = over_current_value << 8;
                    over_current_value += value[i];
                }
                result.over_current_threshold = over_current_value;
                result.over_current_trip = value[3] ? 'ON' : 'OFF';
                result.over_current_alarm = value[4] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochTemperatureThreshold) {
                result.over_temperature_threshold = value[0];
                result.over_temperature_trip = value[1] ? 'ON' : 'OFF';
                result.over_temperature_alarm = value[2] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochLeakageParameters) {
                result.self_test_auto_days = value[0];
                result.self_test_auto_hours = value[1];
                result.self_test_auto = value[2] ? 'ON' : 'OFF';
                result.over_leakage_current_threshold = value[4] | value[3] << 8;
                result.over_leakage_current_trip = value[5] ? 'ON' : 'OFF';
                result.over_leakage_current_alarm = value[6] ? 'ON' : 'OFF';
                result.self_test = value[7] ? 'testing' : 'test';
            }
            return result;
        },
    },
};

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    whiteLabel: [
        {vendor: 'HOCH', model: 'ZJSBL7-100Z'},
        {vendor: 'WDYK', model: 'ZJSBL7-100Z'}
    ],
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fzLocal.hoch_din],
    toZigbee: [tzLocal.hoch_din],
    exposes: [
        exposes.text('meter_number', ea.STATE),
        exposes.binary('state', ea.STATE_SET, 'ON', 'OFF'),
        exposes.text('alarm', ea.STATE),
        exposes.binary('trip_test', ea.STATE_SET, 'test', 'clear'),
        exposes.binary('child_lock', ea.STATE_SET, 'ON', 'OFF'),
        exposes.enum('power_on_behaviour', ea.STATE_SET, ['off', 'on', 'previous']),
        exposes.numeric('countdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit('s'),
        exposes.numeric('voltage', ea.STATE).withUnit('V'),
        exposes.numeric('voltage_rms', ea.STATE).withUnit('V'),
        exposes.numeric('current', ea.STATE).withUnit('mA'),
        exposes.numeric('current_average', ea.STATE).withUnit('mA'),
        exposes.numeric('power', ea.STATE).withUnit('W'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C'),
        exposes.numeric('under_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('under_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('under_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('over_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_temperature_threshold', ea.STATE).withUnit('°C'),
        exposes.binary('over_temperature_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_temperature_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('self_test_auto_days', ea.STATE).withValueMin(1).withValueMax(28).withUnit('days'),
        exposes.numeric('self_test_auto_hours', ea.STATE).withValueMin(0).withValueMax(23).withUnit('hours'),
        exposes.binary('self_test_auto', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_leakage_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_leakage_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_leakage_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.binary('self_test', ea.STATE, 'testing', 'test'),
        exposes.enum('clear_device_data', ea.SET, ['clear'])
    ],
};

module.exports = definition;

Does not work, "not_supported"

danieledwardgeorgehitchcock commented 2 years ago

Sorry.. Try this one:

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 reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const dataPointsLocal = {
    hochState: 1,
    hochCountdownTimer: 9,
    hochFaultCode: 26,
    hochRelayStatus: 27,
    hochChildLock: 29,
    hochVoltage: 101,
    hochCurrent: 102,
    hochActivePower: 103,
    hochLeakageCurrent: 104,
    hochTemperature: 105,
    hochRemainingEnergy: 106,
    hochRechargeEnergy: 107,
    hochCostParameters: 108,
    hochLeakageParameters: 109,
    hochVoltageThreshold: 110,
    hochCurrentThreshold: 111,
    hochTemperatureThreshold: 112,
    hochTotalActivePower: 113,
    hochEquipmentNumberType: 114,
    hochClearEnergy: 115,
    hochLocking: 116,
    hochTotalReverseActivePower: 117,
    hochHistoricalVoltage: 118,
    hochHistoricalCurrent: 119,
};

const tzLocal = {
    hoch_din: {
        key: ['state',
            'child_lock',
            'countdown_timer',
            'power_on_behaviour',
            'trip_test',
            'clear_device_data'
        ],
        convertSet: async (entity, key, value, meta) => {
            if (key === 'state') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochState, value === 'ON');
            } else if (key === 'child_lock') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochChildLock, value === 'ON');
            } else if (key === 'countdown_timer') {
                await tuya.sendDataPointValue(entity, dataPointsLocal.hochCountdownTimer, value);
            } else if (key === 'power_on_behaviour') {
                const lookup = {'off': 0, 'on': 1, 'previous': 2};
                await tuya.sendDataPointEnum(entity, dataPointsLocal.hochRelayStatus, lookup[value], 'sendData');
            } else if (key === 'trip_test') {
                if (value === 'clear') {
                    await tuya.sendDataPointBool(entity, dataPointsLocal.hochLocking, true, 'sendData');
                } else {
                    return {state: {trip_test: 'clear'}};
                }
            } else if (key === 'clear_device_data') {
                await tuya.sendDataPointBool(entity, dataPointsLocal.hochClearEnergy, true, 'sendData');
            } else {
                throw new Error(`Not supported: '${key}'`);
            }
        },
    },
};

const fzLocal = {
    hoch_din: {
        cluster: 'manuSpecificTuya',
        type: ['commandGetData', 'commandSetDataResponse'],
        convert: (model, msg, publish, options, meta) => {
            const dp = msg.data.dp;
            const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
            const result = {};
            meta.logger.debug(`from hoch_din, msg.data.dp=[${dp}], msg.data.datatype=[${msg.data.datatype}], value=[${value}]`);

            if (dp === dataPointsLocal.hochState) {
                result.state = value ? 'ON' : 'OFF';
                if (value) {
                    result.trip_test = 'clear';
                }
            }
            if (dp === dataPointsLocal.hochChildLock) {
                result.child_lock = value ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochVoltage) {
                result.voltage = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochHistoricalVoltage) {
                result.voltage_rms = (value[1] | value[0] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochCurrent) {
                result.current = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochHistoricalCurrent) {
                result.current_average = value[2] | value[1] << 8;
            }
            if (dp === dataPointsLocal.hochActivePower) {
                result.power = (value[2] | value[1] << 8) / 10;
            }
            if (dp === dataPointsLocal.hochLocking) {
                result.trip_test = value ? 'test' : 'clear';
            }
            if (dp === dataPointsLocal.hochCountdownTimer) {
                result.countdown_timer = value;
            }
            if (dp === dataPointsLocal.hochTemperature) {
                result.temperature = value;
            }
            if (dp === dataPointsLocal.hochRelayStatus) {
                const lookup = {
                    0: 'off',
                    1: 'on',
                    2: 'previous'
                };
                result.power_on_behaviour = lookup[value];
            }
            if (dp === dataPointsLocal.hochFaultCode) {
                const lookup = {
                    0: 'clear',
                    1: 'over voltage threshold',
                    2: 'under voltage threshold',
                    4: 'over current threshold',
                    8: 'over temperature threshold',
                    10: 'over leakage current threshold',
                    16: 'trip test',
                    128: 'safety lock'
                };
                result.alarm = lookup[value];
            }
            if (dp === dataPointsLocal.hochEquipmentNumberType) {
                result.meter_number = value.trim();
            }
            if (dp === dataPointsLocal.hochVoltageThreshold) {
                 result.over_voltage_threshold = (value[1] | value[0] << 8) / 10;
                 result.over_voltage_trip = value[2] ? 'ON' : 'OFF';
                 result.over_voltage_alarm = value[3] ? 'ON' : 'OFF';
                 result.under_voltage_threshold = (value[5] | value[4] << 8) / 10;
                 result.under_voltage_trip = value[6] ? 'ON' : 'OFF';
                 result.under_voltage_alarm = value[7] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochCurrentThreshold) {
                let over_current_value = 0;
                for (let i = 0; i < 3; i++) {
                    over_current_value = over_current_value << 8;
                    over_current_value += value[i];
                }
                result.over_current_threshold = over_current_value;
                result.over_current_trip = value[3] ? 'ON' : 'OFF';
                result.over_current_alarm = value[4] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochTemperatureThreshold) {
                result.over_temperature_threshold = value[0];
                result.over_temperature_trip = value[1] ? 'ON' : 'OFF';
                result.over_temperature_alarm = value[2] ? 'ON' : 'OFF';
            }
            if (dp === dataPointsLocal.hochLeakageParameters) {
                result.self_test_auto_days = value[0];
                result.self_test_auto_hours = value[1];
                result.self_test_auto = value[2] ? 'ON' : 'OFF';
                result.over_leakage_current_threshold = value[4] | value[3] << 8;
                result.over_leakage_current_trip = value[5] ? 'ON' : 'OFF';
                result.over_leakage_current_alarm = value[6] ? 'ON' : 'OFF';
                result.self_test = value[7] ? 'testing' : 'test';
            }
            return result;
        },
    },
};

const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_hkdl5fmv'}],
    model: 'TS0601_din',
    vendor: 'TuYa',
    whiteLabel: [
        {vendor: 'HOCH', model: 'ZJSBL7-100Z'},
        {vendor: 'WDYK', model: 'ZJSBL7-100Z'}
    ],
    description: 'DIN mount RCBO with smart energy metering',
    fromZigbee: [fzLocal.hoch_din],
    toZigbee: [tzLocal.hoch_din],
    exposes: [
        exposes.text('meter_number', ea.STATE),
        exposes.binary('state', ea.STATE_SET, 'ON', 'OFF'),
        exposes.text('alarm', ea.STATE),
        exposes.binary('trip_test', ea.STATE_SET, 'test', 'clear'),
        exposes.binary('child_lock', ea.STATE_SET, 'ON', 'OFF'),
        exposes.enum('power_on_behaviour', ea.STATE_SET, ['off', 'on', 'previous']),
        exposes.numeric('countdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(86400).withUnit('s'),
        exposes.numeric('voltage', ea.STATE).withUnit('V'),
        exposes.numeric('voltage_rms', ea.STATE).withUnit('V'),
        exposes.numeric('current', ea.STATE).withUnit('mA'),
        exposes.numeric('current_average', ea.STATE).withUnit('mA'),
        exposes.numeric('power', ea.STATE).withUnit('W'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C'),
        exposes.numeric('under_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('under_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('under_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_voltage_threshold', ea.STATE).withUnit('V'),
        exposes.binary('over_voltage_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_voltage_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_temperature_threshold', ea.STATE).withUnit('°C'),
        exposes.binary('over_temperature_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_temperature_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('self_test_auto_days', ea.STATE).withValueMin(1).withValueMax(28).withUnit('days'),
        exposes.numeric('self_test_auto_hours', ea.STATE).withValueMin(0).withValueMax(23).withUnit('hours'),
        exposes.binary('self_test_auto', ea.STATE, 'ON', 'OFF'),
        exposes.numeric('over_leakage_current_threshold', ea.STATE).withUnit('mA'),
        exposes.binary('over_leakage_current_trip', ea.STATE, 'ON', 'OFF'),
        exposes.binary('over_leakage_current_alarm', ea.STATE, 'ON', 'OFF'),
        exposes.binary('self_test', ea.STATE, 'testing', 'test'),
        exposes.enum('clear_device_data', ea.SET, ['clear'])
    ],
};

module.exports = definition;
casadeivison commented 2 years ago

I don't know what I'm doing wrong now it always appears unsupported.

not

{ "current": 0, "linkquality": 39, "power": 0, "state": "ON", "temperature": 41, "trip_test": "clear", "trip_test_state": "clear", "voltage": 208.4, "alarm": null, "child_lock": null, "countdown_timer": null, "current_average": null, "meter_number": null, "over_current_alarm": null, "over_current_threshold": null, "over_current_trip": null, "over_leakage_current_alarm": null, "over_leakage_current_threshold": null, "over_leakage_current_trip": null, "over_temperature_alarm": null, "over_temperature_threshold": null, "over_temperature_trip": null, "over_voltage_alarm": null, "over_voltage_threshold": null, "over_voltage_trip": null, "power_on_behaviour": null, "self_test": null, "self_test_auto": null, "self_test_auto_days": null, "self_test_auto_hours": null, "under_voltage_alarm": null, "under_voltage_threshold": null, "under_voltage_trip": null, "voltage_rms": null }

danieledwardgeorgehitchcock commented 2 years ago

Hmm.. interesting!

a few questions:

What version of Zigbee2MQTT are you running?

Did you remove the device from your network, restart Zigbee2MQTT, then re-add it when testing the above external converter?

Any messages or errors in your debug logs?

dudu631 commented 2 years ago

Any progress on this?

danieledwardgeorgehitchcock commented 2 years ago

Yes - I’m just putting the final touches on the converter before I put in a PR to get it merged

dudu631 commented 2 years ago

That's awesome, good work man! Just bought this circuit breaker, awesome add here.

danieledwardgeorgehitchcock commented 2 years ago

Hi all,

My initial converter for this device has now been merged into the dev / edge branch (details on how to switch to this are on the main site)

I’ll be adding more (such as alarm thresholds) when I can.

Enjoy!

kuneev commented 2 years ago

Thank you. I will try it later - there is no way yet

чт, 21 окт. 2021 г., 19:24 danieledwardgeorgehitchcock < @.***>:

Hi all,

My initial converter for this device has now been merged into the dev / edge branch (details on how to switch to this are on the main site)

I’ll be adding more (such as alarm thresholds) when I can.

Enjoy!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Koenkk/zigbee-herdsman-converters/issues/2962#issuecomment-948776968, or unsubscribe https://github.com/notifications/unsubscribe-auth/ASYOQK32KBVE2OVXVRWIJOTUIA5D5ANCNFSM5C4E5FQQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

danieledwardgeorgehitchcock commented 2 years ago

Hi all,

This has now been merged into production. I have tested this morning, and all is working well.

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days

kuneev commented 2 years ago

Hi all,

Plz help. Can i change parameters like over_temperature_threshold and over_voltage_threshold in Home Assistant? And how?

elektrinis commented 1 year ago

Hi. as noted above on #1856 I have this RCBO, but in three phase version without leakage detection. However it reports the same model and manufacturer. I do get readings from one phase.

How do I add support for my version of the RCBO? I'm new to z2m and will need some spoonfeeding :|

197378795-204a0481-f35e-4d0b-8466-aa9e89d86565 1

Electry commented 1 year ago

Hey guys, it seems like the current converter was never really finished. Other than not being able to configure the protection values, power measurements above >= 6,5kW are clipped, where any larger power draw will roll over back to 0W.

I recently bought this device (4P RCBO variant) and figured out that it does in fact send power/current/voltage measurements for each of the phases separately.

image

Here is a custom converter: https://gist.github.com/Electry/edc5e22f4f7a1a7bb82476f03b2be869

I would create an official PR, but I have no idea what values does the 1P/2P variant send, so it might not work for those. The power measurement issue is fixed, you should be able self-test the device remotely, and configure the over-current/voltage/temperature & leakage current values as well. The groundwork for the configuration options was already done by @danieledwardgeorgehitchcock, only toZigbee converters were missing.

MarkusThur commented 1 year ago

@Electry

Can you please explain the conversion that is done there to extract the values.. I think I understand it, but I am not 100% sure

        if (dp === tuya.dataPoints.hochVoltage) {
            result.voltage_l1 = (value[1] | value[0] << 8) / 10;
            result.voltage_l2 = (value[3] | value[2] << 8) / 10;
            result.voltage_l3 = (value[5] | value[4] << 8) / 10;
            result.voltage = result.voltage_l1;
        }

I did see till now, that more or less gets missinterpretet and a wired ASCII or UTF8 interpration is followed by the parser.

If I do understand your code right you swap the bytes in it (I asume value[0] represents the first transfered byte) So you swap the order by this code and then divide the resulting unsigned iteger by 10 as the value represents the 1/10V. ???

I am a bit confused :-)

Electry commented 1 year ago

It's nothing special really, here is an example from the hochVoltage dp.

from hoch_din, dp=[101], datatype=[0], value=[{"type":"Buffer","data":[9,63,9,83,9,81]}]

in hex thats [0x09, 0x3F, 0x09, 0x53, 0x09, 0x51]

I just extract uint16 value (two bytes, big-endian) from the data for each of the phases by byte-shifting the first byte (0x09) to the left by 8 (which then becomes 0x0900), and ORing it with the second byte (e.g. 0x3F | 0x0900 = 0x093F), and then I divide the value by 10. P1 would be 0x093F = 2367 => 236.7 V, P2 = 0x0953 = 2387 => 238.7 V, etc.

jeffrey-zammit commented 9 months ago

Can these convertors be used for the WIFI model? If so, how can it be done? Thanks.

berezhinskiy commented 7 months ago

@jeffrey-zammit Hello, did you manage to make it work with the WiFi model? I received the following data from my RC-RCBO 3-phase device:

{
    "code": "Voltage",
    "value": "CXYJkgmN"
},
{
    "code": "Current",
    "value": "AAMlAAJXAARo"
},
{
    "code": "ActivePower",
    "value": "AA8zAAYnAAMUAAX4"
}

@Electry I was wondering if you could lend a hand in decoding the values from my RC-RCBO device. Your help would be greatly appreciated!

jeffrey-zammit commented 7 months ago

@jeffrey-zammit Hello, did you manage to make it work with the WiFi model? I received the following data from my RC-RCBO 3-phase device:

{
    "code": "Voltage",
    "value": "CXYJkgmN"
},
{
    "code": "Current",
    "value": "AAMlAAJXAARo"
},
{
    "code": "ActivePower",
    "value": "AA8zAAYnAAMUAAX4"
}

@Electry I was wondering if you could lend a hand in decoding the values from my RC-RCBO device. Your help would be greatly appreciated!

@berezhinskiy - Unfortunately not, but using Local Tuya, I managed to get the 'Total Forward Active Energy' which is enough for the Energy Monitoring. image

just needed to customise the sensor to add the "total_increasing" state_class

sensor.total_forward_active_energy: state_class: "total_increasing"