Koenkk / zigbee2mqtt

Zigbee 🐝 to MQTT bridge 🌉, get rid of your proprietary Zigbee bridges 🔨
https://www.zigbee2mqtt.io
GNU General Public License v3.0
11.77k stars 1.64k forks source link

[New device support] ZBN-DJ63 - Smart Breaker with Energy Monitoring #23502

Open unwiredtech opened 1 month ago

unwiredtech commented 1 month ago

Link

https://www.amazon.com.au/Intelligent-Photovoltaic-Bidirectional-Automatic-Compatible/dp/B0CYPQHVYR

Database entry

{"id":3,"type":"Router","ieeeAddr":"0xa4c138fa6becd2bf","nwkAddr":22993,"manufId":4417,"manufName":"_TZE204_lb0fsvba","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1,242],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[4,5,61184,0],"outClusterList":[>

Comments

I tested this external definition but for some reason the Z2M Frontend could not see the Exposed sensors.

External definition

//Device type Router
//Zigbee Model - TS0601
//Zigbee Manufacturer - _TZE204_lb0fsvba

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

const definition = {
    // Identifies the device using fingerprint instead of zigbeeModel for Tuya devices
    fingerprint: [
        {
            modelID: 'TS0601',
            manufacturerName: '_TZE204_lb0fsvba',
        },
    ],
    model: 'ZBN-DJ-63',
    vendor: 'Tuya',
    description: 'Tuya Zigbee Smart Circuit Breaker with energy monitoring and protection settings',
    fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, tuya.fz.datapoints],
    toZigbee: [tz.on_off, tz.electrical_measurement, tz.metering, tuya.tz.datapoints],
    exposes: [
        e.switch().setAccess('state', ea.ALL).withDescription('Switch the circuit breaker on/off'),
        e.energy().withAccess(ea.STATE).withDescription('Energy usage in kWh'),
        e.power().withAccess(ea.STATE).withDescription('Power usage in W'),
        e.voltage().withAccess(ea.STATE).withDescription('Voltage in V'),
        e.current().withAccess(ea.STATE).withDescription('Current in A'),

        exposes.enum('fault', ea.STATE, ['clear', 'over_current', 'over_power', 'over_voltage', 'under_voltage', 'leakage'])
            .withDescription('Fault status (clear = no faults)'),

        exposes.numeric('temperature_threshold', ea.ALL)
            .withUnit('°C')
            .withDescription('Temperature threshold for triggering protection')
            .withValueMin(10)
            .withValueMax(85),

        exposes.numeric('power_threshold', ea.ALL)
            .withUnit('W')
            .withDescription('Power threshold for triggering protection')
            .withValueMin(0)
            .withValueMax(9999),

        exposes.numeric('over_voltage_threshold', ea.ALL)
            .withUnit('V')
            .withDescription('Over voltage threshold for protection')
            .withValueMin(120)
            .withValueMax(300),

        exposes.numeric('under_voltage_threshold', ea.ALL)
            .withUnit('V')
            .withDescription('Under voltage threshold for protection')
            .withValueMin(80)
            .withValueMax(210),

        exposes.numeric('over_current_threshold', ea.ALL)
            .withUnit('A')
            .withDescription('Over current threshold for protection')
            .withValueMin(1)
            .withValueMax(63),

        exposes.numeric('leakage_current_threshold', ea.ALL)
            .withUnit('mA')
            .withDescription('Leakage current threshold for protection')
            .withValueMin(10)
            .withValueMax(99),

        exposes.binary('power_outage_memory', ea.ALL, 'ON', 'OFF')
            .withDescription('Retain state after power outage (ON - remembers last state)'),

        exposes.enum('indicator_mode', ea.ALL, ['off', 'normal', 'inverse'])
            .withDescription('LED indicator mode'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'energy', tuya.valueConverter.divideBy100],
            [6, null, tuya.valueConverter.phaseVariant2], // Handles voltage, current, power
            [10, 'fault', tuya.valueConverterBasic.lookup({
                'clear': 0,
                'over_current': 1,
                'over_power': 2,
                'over_voltage': 4,
                'under_voltage': 9,
                'leakage': 10,
            })],
            [17, 'temperature_threshold', tuya.valueConverter.raw],
            [18, 'meter_id', tuya.valueConverter.raw],
            [19, 'power_threshold', tuya.valueConverter.divideBy10],
            [20, 'clear_fault', tuya.valueConverter.onOff],
            [21, 'leakage_current_threshold', tuya.valueConverter.divideBy100],
            [22, 'indicator_mode', tuya.valueConverterBasic.lookup({
                'off': 0,
                'normal': 1,
                'inverse': 2,
            })],
            [23, 'power_outage_memory', tuya.valueConverter.onOff],
        ],
    },
};

module.exports = definition;
unwiredtech commented 1 month ago

Black-Smart-Meter Product Image

unwiredtech commented 1 month ago

Product Spec:

droserHA commented 1 month ago

This is what I sketched. partially working

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

const definition = {

    fingerprint: tuya.fingerprint('TS0601', ['_TZE204_lb0fsvba']),
    model: 'TS0601_din_2',
    vendor: 'TuYa',
    description: 'Zigbee DIN energy meter',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    configure: tuya.configureMagicPacket,
    whiteLabel: [{vendor: 'XOCA', model: 'DAC2161C'}],
    exposes: [tuya.exposes.switch(), e.energy(), e.power(), e.voltage(), e.current(),
        exposes.enum('fault', ea.STATE, ['clear', 'over_current_threshold', 'over_power_threshold',
            'over_voltage threshold', 'wrong_frequency_threshold']).withDescription('Fault status of the device (clear = nothing)'),
        exposes.enum('threshold_1', ea.STATE, ['not_set', 'over_current_threshold', 'over_voltage_threshold'])
            .withDescription('State of threshold_1'),
        exposes.binary('threshold_1_protection', ea.STATE_SET, 'ON', 'OFF')
            .withDescription('OFF - alarm only, ON - relay will be off when threshold reached'),
        exposes.numeric('threshold_1_value', ea.STATE_SET)
            .withDescription('Can be in Volt or Ampere depending on threshold setting. Setup the value on the device'),
        exposes.enum('threshold_2', ea.STATE, ['not_set', 'over_current_threshold', 'over_voltage_threshold'])
            .withDescription('State of threshold_2'),
        exposes.binary('threshold_2_protection', ea.STATE, 'ON', 'OFF')
            .withDescription('OFF - alarm only, ON - relay will be off when threshold reached'),
        exposes.numeric('threshold_2_value', ea.STATE)
            .withDescription('Setup value on the device'),
        exposes.numeric('reverse_energy', ea.STATE).withUnit('kWh')
            .withDescription('Reverse Energy Total'),
        exposes.numeric('temperature', ea.STATE).withUnit('°C')
            .withDescription('Temperature'),
        exposes.binary('clear_fault', ea.STATE_SET, 'ON', 'OFF')
            .withDescription('Turn ON to clear last the fault'),
        exposes.text('meter_id', ea.STATE).withDescription('Meter ID (ID of device)'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'energy', tuya.valueConverter.divideBy100],
            [3, null, null], // Monthly, but sends data only after request
            [4, null, null], // Dayly, but sends data only after request
            [6, null, tuya.valueConverter.phaseVariant2], // voltage and current
            [9, 'fault', tuya.valueConverterBasic.lookup({'clear': 0, 'over_current_threshold': 1,
                'over_power_threshold': 2, 'over_voltage_threshold': 4, 'wrong_frequency_threshold': 8})],
            [11, null, null], // Frozen - strange function, in native app - nothing is clear
            [16, 'state', tuya.valueConverter.onOff],
            [17, null, tuya.valueConverter.threshold], // It's settable, but can't write converter
            [103, 'temperature', tuya.valueConverter.raw],
            [20, 'clear_fault', tuya.valueConverter.onOff], // Clear fault
            [13, null, null], // Balance energy
            [110, 'reverse_energy', tuya.valueConverter.divideBy100], // Reverse Energy Total
            [23, null, null], // Forward Energy T3 - don't know what this
            [24, null, null], // Forward Energy T4 - don't know what this
        ],
    },

};

module.exports = definition;

unwiredtech commented 1 month ago

Apologies for late reply.

I tested the definition and seems to work, but as you said some features are not working but this is better than before.

Thanks! ![Uploading zbn-dj-63.png…]()

slayer commented 1 month ago

Hey, thanks for sketch, I have the same device

I've tried it, but my circuit breaker fails with wrong_frequency_threshold error (power is off), and I don't know how to change this threshold (or even is it real wrong_frequency_threshold error, because multimeter says frequency in socket is 50.00 Hz)

image

image

git-greatguy commented 1 month ago

Hi, i'm interested in tring this device to get "negative" apparent power injected to the grid from my solar setup. Is it working well / stable enough for this purpose ? thanks !

slayer commented 1 month ago

@git-greatguy do you want to measure DC or AC? I believe this module is able to measure AC only. for DC there are other devices

git-greatguy commented 1 month ago

Sure, it's for measurin AC flow between grid and my inverter. 👍 my current zigbee module (TO-Q-SY1-JZT), send accurate values but values are not "signed". It's a bit annoying to know if i inject or pull from the grid ! This device looks promising to clear this issue.

slayer commented 1 month ago

@git-greatguy I would recommend for this another device, it works good with in/out measurement

slayer commented 3 weeks ago

Any ideas how to fix

I've tried it, but my circuit breaker fails with wrong_frequency_threshold

?