Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New device support]: EMIZB-141 Power Meter #19042

Closed
lSh4dowl opened this issue Sep 21, 2023 · 115 comments · Fixed by Koenkk/zigbee-herdsman-converters#8044
Closed

[New device support]: EMIZB-141 Power Meter #19042

lSh4dowl opened this issue Sep 21, 2023 · 115 comments · Fixed by Koenkk/zigbee-herdsman-converters#8044
Labels
new device support New device support request

Comments

@lSh4dowl
Copy link

Link

https://www.amazon.de/Electricity-Zählerauslesung-Energieverbrauchsüberwachung-LED-Impulsen-funktioniert/dp/B0CGVB6LGC

Database entry

{"id":54,"type":"EndDevice","ieeeAddr":"0x0015bc001b100a56","nwkAddr":51420,"manufId":4117,"manufName":"frient A/S","powerSource":"Battery","modelId":"EMIZB-141","epList":[1,2],"endpoints":{"1":{"profId":49353,"epId":1,"devId":1,"inClusterList":[5,6],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"2":{"profId":260,"epId":2,"devId":83,"inClusterList":[0,1,3,32,1794,2817,2821],"outClusterList":[3,10,25],"clusters":{"genBasic":{"attributes":{}},"genPollCtrl":{"attributes":{"checkinInterval":14400}},"seMetering":{"attributes":{"currentSummDelivered":[0],"instantaneousDemand":354,"multiplier":1,"divisor":1000,"develcoPulseConfiguration":10000,"develcoInterfaceMode":0}}},"binds":[{"cluster":32,"type":"endpoint","deviceIeeeAddress":"0x00124b0024c2ad1c","endpointID":1},{"cluster":1794,"type":"endpoint","deviceIeeeAddress":"0x00124b0024c2ad1c","endpointID":1}],"configuredReportings":[{"cluster":1794,"attrId":1024,"minRepIntval":5,"maxRepIntval":3600,"repChange":1}],"meta":{}}},"dateCode":"2023-09-06 11:54","zclVersion":7,"interviewCompleted":true,"meta":{"configured":-570313272},"lastSeen":1695324832904,"defaultSendRequestWhen":"active","checkinInterval":3600}

Comments

It works reasonable, but shows no battery for example.
I basically just copied an old Version of the previous version (https://www.zigbee2mqtt.io/devices/ZHEMI101.html)
I only linked a German Amazon Page, because the Vendor doesn't have a site for the product yet (this is the old version: https://frient.com/products/electricity-meter-interface/)

External converter

const exposes = require('zigbee-herdsman-converters/lib/exposes');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const constants = require('zigbee-herdsman-converters/lib/constants');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const utils = require('zigbee-herdsman-converters/lib/utils');
const ota = require('zigbee-herdsman-converters/lib/ota');
const e = exposes.presets;
const ea = exposes.access;

// develco specific cosntants
const manufacturerOptions = {manufacturerCode: 0x1015};

/* MOSZB-1xx - ledControl - bitmap8 - r/w
 * 0x00 Disable LED when movement is detected.
 * 0x01 Enables periodic fault flashes. These flashes are used to indicate e.g. low battery level.
 * 0x02 Enables green application defined LED. This is e.g. used to indicate motion detection.
 * Default value 0xFF ( seems to be fault + motion)
 */
const develcoLedControlMap = {
    0x00: 'off',
    0x01: 'fault_only',
    0x02: 'motion_only',
    0xFF: 'both',
};


// develco specific convertors
const develco = {
    configure: {
        read_sw_hw_version: async (device, logger) => {
            for (const ep of device.endpoints) {
                if (ep.supportsInputCluster('genBasic')) {
                    try {
                        const data = await ep.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'],
                            manufacturerOptions);

                        if (data.hasOwnProperty('develcoPrimarySwVersion')) {
                            device.softwareBuildID = data.develcoPrimarySwVersion.join('.');
                        }

                        if (data.hasOwnProperty('develcoPrimaryHwVersion')) {
                            device.hardwareVersion = data.develcoPrimaryHwVersion.join('.');
                        }
                    } catch (error) {/* catch timeouts of sleeping devices */}
                    break;
                }
            }
        },
    },
    fz: {
        // Some Develco devices report strange values sometimes
        // https://github.com/Koenkk/zigbee2mqtt/issues/13329
        electrical_measurement: {
            ...fz.electrical_measurement,
            convert: (model, msg, publish, options, meta) => {
                if (msg.data.rmsVoltage !== 0xFFFF && msg.data.rmsCurrent !== 0xFFFF && msg.data.activePower !== -0x8000) {
                    return fz.electrical_measurement.convert(model, msg, publish, options, meta);
                }
            },
        },
        device_temperature: {
            ...fz.device_temperature,
            convert: (model, msg, publish, options, meta) => {
                if (msg.data.currentTemperature !== -0x8000) {
                    return fz.device_temperature.convert(model, msg, publish, options, meta);
                }
            },
        },
        temperature: {
            ...fz.temperature,
            convert: (model, msg, publish, options, meta) => {
                if (msg.data.measuredValue !== -0x8000 && msg.data.measuredValue !== 0xFFFF) {
                    return fz.temperature.convert(model, msg, publish, options, meta);
                }
            },
        },
        metering: {
            ...fz.metering,
            convert: (model, msg, publish, options, meta) => {
                if (msg.data.instantaneousDemand !== -0x800000) {
                    return fz.metering.convert(model, msg, publish, options, meta);
                }
            },
        },
        pulse_configuration: {
            cluster: 'seMetering',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const result = {};
                if (msg.data.hasOwnProperty('develcoPulseConfiguration')) {
                    result[utils.postfixWithEndpointName('pulse_configuration', msg, model, meta)] =
                        msg.data['develcoPulseConfiguration'];
                }

                return result;
            },
        },
        interface_mode: {
            cluster: 'seMetering',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const result = {};
                if (msg.data.hasOwnProperty('develcoInterfaceMode')) {
                    result[utils.postfixWithEndpointName('interface_mode', msg, model, meta)] =
                        constants.develcoInterfaceMode.hasOwnProperty(msg.data['develcoInterfaceMode']) ?
                            constants.develcoInterfaceMode[msg.data['develcoInterfaceMode']] :
                            msg.data['develcoInterfaceMode'];
                }
                if (msg.data.hasOwnProperty('status')) {
                    result['battery_low'] = (msg.data.status & 2) > 0;
                    result['check_meter'] = (msg.data.status & 1) > 0;
                }

                return result;
            },
        },
        fault_status: {
            cluster: 'genBinaryInput',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const result = {};
                if (msg.data.hasOwnProperty('reliability')) {
                    const lookup = {0: 'no_fault_detected', 7: 'unreliable_other', 8: 'process_error'};
                    result.reliability = lookup[msg.data['reliability']];
                }
                if (msg.data.hasOwnProperty('statusFlags')) {
                    result.fault = (msg.data['statusFlags']===1);
                }
                return result;
            },
        },
        voc: {
            cluster: 'develcoSpecificAirQuality',
            type: ['attributeReport', 'readResponse'],
            options: [exposes.options.precision('voc'), exposes.options.calibration('voc')],
            convert: (model, msg, publish, options, meta) => {
                // from Sensirion_Gas_Sensors_SGP3x_TVOC_Concept.pdf
                // "The mean molar mass of this mixture is 110 g/mol and hence,
                // 1 ppb TVOC corresponds to 4.5 μg/m3."
                const vocPpb = parseFloat(msg.data['measuredValue']);
                const voc = vocPpb * 4.5;
                const vocProperty = utils.postfixWithEndpointName('voc', msg, model, meta);

                // from aqszb-110-technical-manual-air-quality-sensor-04-08-20.pdf page 6, section 2.2 voc
                // this contains a ppb to level mapping table.
                let airQuality;
                const airQualityProperty = utils.postfixWithEndpointName('air_quality', msg, model, meta);
                if (vocPpb <= 65) {
                    airQuality = 'excellent';
                } else if (vocPpb <= 220) {
                    airQuality = 'good';
                } else if (vocPpb <= 660) {
                    airQuality = 'moderate';
                } else if (vocPpb <= 2200) {
                    airQuality = 'poor';
                } else if (vocPpb <= 5500) {
                    airQuality = 'unhealthy';
                } else if (vocPpb > 5500) {
                    airQuality = 'out_of_range';
                } else {
                    airQuality = 'unknown';
                }
                return {[vocProperty]: utils.calibrateAndPrecisionRoundOptions(voc, options, 'voc'), [airQualityProperty]: airQuality};
            },
        },
        voc_battery: {
            cluster: 'genPowerCfg',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                /*
                 * Per the technical documentation for AQSZB-110:
                 * To detect low battery the system can monitor the "BatteryVoltage" by setting up a reporting interval of every 12 hour.
                 * When a voltage of 2.5V is measured the battery should be replaced.
                 * Low batt LED indication–RED LED will blink twice every 60 second.
                 */
                const result = fz.battery.convert(model, msg, publish, options, meta);
                result.battery_low = (result.voltage <= 2500);
                return result;
            },
        },
        led_control: {
            cluster: 'genBasic',
            type: ['attributeReport', 'readResponse'],
            options: [],
            convert: (model, msg, publish, options, meta) => {
                const state = {};

                if (msg.data.hasOwnProperty('develcoLedControl')) {
                    state['led_control'] = develcoLedControlMap[msg.data['develcoLedControl']];
                }

                return state;
            },
        },
        ias_occupancy_timeout: {
            cluster: 'ssIasZone',
            type: ['attributeReport', 'readResponse'],
            options: [],
            convert: (model, msg, publish, options, meta) => {
                const state = {};

                if (msg.data.hasOwnProperty('develcoAlarmOffDelay')) {
                    state['occupancy_timeout'] = msg.data['develcoAlarmOffDelay'];
                }

                return state;
            },
        },
        input: {
            cluster: 'genBinaryInput',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const result = {};
                if (msg.data.hasOwnProperty('presentValue')) {
                    const value = msg.data['presentValue'];
                    result[utils.postfixWithEndpointName('input', msg, model, meta)] = value == 1;
                }
                return result;
            },
        },
    },
    tz: {
        pulse_configuration: {
            key: ['pulse_configuration'],
            convertSet: async (entity, key, value, meta) => {
                await entity.write('seMetering', {'develcoPulseConfiguration': value}, manufacturerOptions);
                return {readAfterWriteTime: 200, state: {'pulse_configuration': value}};
            },
            convertGet: async (entity, key, meta) => {
                await entity.read('seMetering', ['develcoPulseConfiguration'], manufacturerOptions);
            },
        },
        interface_mode: {
            key: ['interface_mode'],
            convertSet: async (entity, key, value, meta) => {
                const payload = {'develcoInterfaceMode': utils.getKey(constants.develcoInterfaceMode, value, undefined, Number)};
                await entity.write('seMetering', payload, manufacturerOptions);
                return {readAfterWriteTime: 200, state: {'interface_mode': value}};
            },
            convertGet: async (entity, key, meta) => {
                await entity.read('seMetering', ['develcoInterfaceMode'], manufacturerOptions);
            },
        },
        current_summation: {
            key: ['current_summation'],
            convertSet: async (entity, key, value, meta) => {
                await entity.write('seMetering', {'develcoCurrentSummation': value}, manufacturerOptions);
                return {state: {'current_summation': value}};
            },
        },
        led_control: {
            key: ['led_control'],
            convertSet: async (entity, key, value, meta) => {
                const ledControl = utils.getKey(develcoLedControlMap, value, value, Number);
                await entity.write('genBasic', {'develcoLedControl': ledControl}, manufacturerOptions);
                return {state: {led_control: value}};
            },
            convertGet: async (entity, key, meta) => {
                await entity.read('genBasic', ['develcoLedControl'], manufacturerOptions);
            },
        },
        ias_occupancy_timeout: {
            key: ['occupancy_timeout'],
            convertSet: async (entity, key, value, meta) => {
                let timeoutValue = value;
                if (timeoutValue < 20) {
                    meta.logger.warn(`Minimum occupancy_timeout is 20, using 20 instead of ${timeoutValue}!`);
                    timeoutValue = 20;
                }
                await entity.write('ssIasZone', {'develcoAlarmOffDelay': timeoutValue}, manufacturerOptions);
                return {state: {occupancy_timeout: timeoutValue}};
            },
            convertGet: async (entity, key, meta) => {
                await entity.read('ssIasZone', ['develcoAlarmOffDelay'], manufacturerOptions);
            },
        },
        input: {
            key: ['input'],
            convertGet: async (entity, key, meta) => {
                await entity.read('genBinaryInput', ['presentValue']);
            },
        },
    },
};


const definition = {
    zigbeeModel: ['EMIZB-141'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
    model: 'EMIZB-141', // Vendor model number, look on the device for a model number
    vendor: 'frient A/S', // Vendor of the device (only used for documentation and startup logging)
    description: 'frient Powermeter', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
    fromZigbee: [develco.fz.metering, develco.fz.pulse_configuration, develco.fz.interface_mode],
        toZigbee: [develco.tz.pulse_configuration, develco.tz.interface_mode, develco.tz.current_summation],
        endpoint: (device) => {
            return {'default': 2};
        },
        configure: async (device, coordinatorEndpoint, logger) => {
            const endpoint = device.getEndpoint(2);
            await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
            await reporting.instantaneousDemand(endpoint);
            await reporting.readMeteringMultiplierDivisor(endpoint);
        },
        exposes: [
            e.power(),
            e.energy(),
            e.battery_low(),
            exposes.numeric('pulse_configuration', ea.ALL).withValueMin(0).withValueMax(65535)
                .withDescription('Pulses per kwh. Default 1000 imp/kWh. Range 0 to 65535'),
            exposes.enum('interface_mode', ea.ALL,
                ['electricity', 'gas', 'water', 'kamstrup-kmp', 'linky', 'IEC62056-21', 'DSMR-2.3', 'DSMR-4.0'])
                .withDescription('Operating mode/probe'),
            exposes.numeric('current_summation', ea.SET)
                .withDescription('Current summation value sent to the display. e.g. 570 = 0,570 kWh').withValueMin(0)
                .withValueMax(268435455),
            exposes.binary('check_meter', ea.STATE, true, false)
                .withDescription('Is true if communication problem with meter is experienced'),
        ],
};

module.exports = definition;

Supported color modes

No response

Color temperature range

No response

@lSh4dowl lSh4dowl added the new device support New device support request label Sep 21, 2023
@Koenkk
Copy link
Owner

Koenkk commented Sep 23, 2023

Could you make a PR to add support for this device?

@lSh4dowl
Copy link
Author

I am still testing and experiencing some weirdness, where I see less usage than in reality, however, I don’t know if it is due to my power meter or the device, since I have no other reader device to compare to.

@lSh4dowl
Copy link
Author

lSh4dowl commented Oct 1, 2023

I could need some help with this :)

Readings are definitely not accurate when set to the right frequency, also another problem I have noticed is that I now have a small solar system and it seems to add the generated overflow energy that goes out to the total.

@j91321
Copy link

j91321 commented Oct 1, 2023

I've encountered the same problem, it's mentioned even on develco website that this is not compatible with PV systems, it doesn't happen to 100% of electrometers, but some of them are configured to give impulse also on energy export and you have no way of distinguishing import from export (if you have on-grid setup for solar)

@lSh4dowl
Copy link
Author

lSh4dowl commented Oct 1, 2023

my system seems to have 2 IR Lights, so I wonder if one is dedicated for export and one for import, might test this out by just covering one up.

@j91321
Copy link

j91321 commented Oct 1, 2023

Many systems have multiple lights, my also has 2, but one shows imp./kWh the other imp./kvarh. Best to find and consult manual.

@lSh4dowl
Copy link
Author

lSh4dowl commented Oct 1, 2023

That would be a bummer, since to my knowledge this is the only zigbee power meter, that’s why I bought it and this makes it practically useless :/
Probably will have to send it back if this is the case.

@j91321
Copy link

j91321 commented Oct 1, 2023

There are other power meters like TuYa TS0601 although the installation is definitely more complex than the LED one. Based on my research so far this would also work better with PV because, it should be able to determine the import/export direction depending on where the clamps are installed.

@KaytheDays
Copy link

Will this device be officially supported ? I am considering it, as it seems the device with the most simple installation out there …
https://www.develcoproducts.com/de/produkte/zaehlermodule/modul-fuer-stromzaehler-2-led/#EMI2LEDAngaben

@LifeInZeitnot
Copy link

Hello, i'm new to Zigbee2mqtt, how can i import the config shown by lSh4dowl ?

@petosiso
Copy link

I had same problem yesterday, this worked for me:

Via the web terminal, I could create my converter file per the Z2M guide and place it in /config/zigbee2mqtt/.js (that's what the guide means by "This file has to be created next to the configuration.yaml", because the configuration.yaml file for Z2M is in /config/zigbee2mqtt, at least in HassOS).

Then, to tell Z2M to use the converter file, go to the Z2M UI, then click "Settings" > "External Converters". Enter the filename of the converter file you just created ("SPP02GIP.js" in my case), and click "Submit", then "Restart".

The external converter file should now be in use by Z2M, which you can verify in the logs per the guide linked in the OP.

@AlmightyCZ
Copy link

@petosiso Can you confirm, that the device is working correctly when you don't have a solar system?

@penroseg
Copy link

penroseg commented Nov 2, 2023

Hi @petosiso. I can confirm it's working well on a non-solar system meter. Have had it running for about 3 weeks (using the custom converter shared by @lSh4dowl. Including showing up in Energy Dashboard.

There are issues with some fields (Battery mainly) and the Summation resets to Zero no matter what is entered. I was hoping to use that latter field to input my starting Meter number and have it increase from there but from reading back it appears that was an issue with the v1 meter also. Maybe when 'proper' support comes to Z2M it will work but for the moment it is more than enough for me.

I've also set up Utility meters for Hour, Day & Month so I can see a visual. I used a version of this article here to set up my Day, Night & Peak rates. https://community.home-assistant.io/t/stuck-setting-up-peak-off-peak-electricity-tariff/419894/5

image

image

image

@petosiso
Copy link

petosiso commented Nov 3, 2023

@AlmightyCZ yes, I can also confirm that it works. Exactly as @penroseg described,
image
image

@jllarraz
Copy link

Does anyone knows when is this to be added to the list of supported devices?

ywaf referenced this issue in Koenkk/zigbee-herdsman-converters Dec 1, 2023
* Added Support for frient Electricity Meter Interface 2

* Update frient.ts

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
@AlmightyCZ
Copy link

It's now supported in 1.34.0(Koenkk/zigbee-herdsman-converters#6582 + https://www.zigbee2mqtt.io/devices/EMIZB-141.html)

@cawith
Copy link

cawith commented Dec 2, 2023

Great news that it is now supported in 1.34.0, but for some reason I don't get an energy reading. Does anybody face the same issue or have a fix? I tried reconfiguring.
Skærmbillede 2023-12-02 kl  11 55 09

@ywaf
Copy link

ywaf commented Dec 3, 2023

Great news that it is now supported in 1.34.0, but for some reason I don't get an energy reading. Does anybody face the same issue or have a fix? I tried reconfiguring. Skærmbillede 2023-12-02 kl 11 55 09

you have to set the pulse setting which isnt there in the official build, im currently working on a pr, or use the custom external converter

@alerich-x
Copy link

I've encountered the same problem, it's mentioned even on develco website that this is not compatible with PV systems, it doesn't happen to 100% of electrometers, but some of them are configured to give impulse also on energy export and you have no way of distinguishing import from export (if you have on-grid setup for solar)

So this is a hardware issue and the device support in Z2MQTT doesn't make any difference?

@akostamo
Copy link

This custom converter works so much better than what is currently in the release version, so eagerly waiting this to be the officially released!

@dawiinci
Copy link

Great news that it is now supported in 1.34.0, but for some reason I don't get an energy reading. Does anybody face the same issue or have a fix? I tried reconfiguring.

you have to set the pulse setting which isnt there in the official build, im currently working on a pr, or use the custom external converter

That is good news. What are your plans on the PR? I am considering using the external converter to make energy work, but this might interfere with the PR, right?

@ywaf
Copy link

ywaf commented Dec 13, 2023

Great news that it is now supported in 1.34.0, but for some reason I don't get an energy reading. Does anybody face the same issue or have a fix? I tried reconfiguring.

you have to set the pulse setting which isnt there in the official build, im currently working on a pr, or use the custom external converter

That is good news. What are your plans on the PR? I am considering using the external converter to make energy work, but this might interfere with the PR, right?

nah just remove the custom converter if u wanna go back to normal converter

@dawiinci
Copy link

In the external converter I am missing the battery indicator in %. Is there a way to add it?

@AlmightyCZ
Copy link

In the external converter I am missing the battery indicator in %. Is there a way to add it?

The converter in release is reporting battery percentage, but it's probably not working. Despite showing 100% consistently, my meter stopped updating (after 60 days of operation), indicating battery depletion. After replacing the batteries, it started working correctly again.

@AlmightyCZ
Copy link

Also the energy reporting has stoped working (as someone has already mentioned here) so I'm going back to the original external converter for now.

@fumantsu
Copy link

fumantsu commented Jan 4, 2024

I will agree with the use of external converter. It is much more complete. I managed to set the current summation but to be fair not sure what should be. Is it the "current value" in kWh that I see in the power box? (for the Czech people I have PRE).

@nivek1612
Copy link

Used the external converter mentioned above. Running for 5 days and the tracking of my usage matches the electricity meter perfectly.

@toabi
Copy link

toabi commented Sep 30, 2024

I'm using the device for nearly a year now with one of the first converters and I set the pulse to 10000 because my meter requires it. And it seems to work because I get correct readings from the device without any other hacks.

@fumantsu
Copy link

fumantsu commented Sep 30, 2024 via email

@Jens-Wymeersch
Copy link

I see a lot of folks using the converter in all kinds of ways. @tbowmo created a PR (thank you) which should be much easier for all in the future. Can someone help him figure this out ? (I unfortunately don't have these skills nor the device yet, else I would do it)

@jeppester
Copy link

jeppester commented Sep 30, 2024

I've been using this device since February, and I've been really happy with it. It's readings are extremely accurate, and in general it has been a revelation to be able to follow the whole house's energy consumption in real time. It makes it really easy to discover where to take action.

I can't remember exactly which of the converters I'm using, but what I have working is energy, power and setting the pulse configuration.

The battery shows 100% which can't be true. As far as I remember, the device will reset the energy to 0 if I change the current summation, no matter what the input is.

I'm thinking if it would make sense to - for a starting point - only include the stuff that works, e.g.:

  • Energy
  • Power
  • Setting the pulse configuration
  • Current summation could perhaps be re-purposed into a "reset sum" button (if that is even possible?)

I believe those features would be enough for the vast majority to get what they expect from this device.

@tbowmo
Copy link

tbowmo commented Sep 30, 2024

This seems to be the bare minimum at the moment, which I'm going to model in the herdsman-converter pr (in typescript). I have removed a lot of the code from OP, that doesn't make sense (like interface mode, for this device there is only one interface mode, the LED blinker)

const exposes = require('zigbee-herdsman-converters/lib/exposes');
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const constants = require('zigbee-herdsman-converters/lib/constants');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const utils = require('zigbee-herdsman-converters/lib/utils');
const ota = require('zigbee-herdsman-converters/lib/ota');
const e = exposes.presets;
const ea = exposes.access;
const modern = require('zigbee-herdsman-converters/lib/modernExtend');

// develco specific cosntants
const manufacturerOptions = {manufacturerCode: 0x1015};

// develco specific convertors
const develco = {
    fz: {
        // Some Develco devices report strange values sometimes
        // https://github.com/Koenkk/zigbee2mqtt/issues/13329
        pulse_configuration: {
            cluster: 'seMetering',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const result = {};
                if (msg.data.hasOwnProperty('develcoPulseConfiguration')) {
                    result[utils.postfixWithEndpointName('pulse_configuration', msg, model, meta)] = msg.data['develcoPulseConfiguration'];
                }

                return result;
            },
        },
    },
    tz: {
        pulse_configuration: {
            key: ['pulse_configuration'],
            convertSet: async (entity, key, value, meta) => {
                await entity.write('seMetering', {develcoPulseConfiguration: value}, manufacturerOptions);
                return {readAfterWriteTime: 200, state: {pulse_configuration: value}};
            },
            convertGet: async (entity, key, meta) => {
                await entity.read('seMetering', ['develcoPulseConfiguration'], manufacturerOptions);
            },
        },
        current_summation: {
            key: ['current_summation'],
            convertSet: async (entity, key, value, meta) => {
                await entity.write('seMetering', {develcoCurrentSummation: value}, manufacturerOptions);
                return {state: {current_summation: value}};
            },
        },
    },
};

const definition = {
    zigbeeModel: ['EMIZB-141'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
    model: 'EMIZB-141', // Vendor model number, look on the device for a model number
    vendor: 'frient A/S', // Vendor of the device (only used for documentation and startup logging)
    description: 'frient Powermeter', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
    fromZigbee: [develco.fz.pulse_configuration],
    toZigbee: [develco.tz.pulse_configuration, develco.tz.current_summation],
    extend: [
        modern.ota(),
        modern.battery(),
        modern.electricityMeter({cluster: 'metering', power: {divisor: 1000, multiplier: 1}, energy: {divisor: 1000, multiplier: 1}}),
    ],
    endpoint: (device) => {
        return {default: 2};
    },
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(2);
        await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
        await reporting.instantaneousDemand(endpoint);
        await reporting.readMeteringMultiplierDivisor(endpoint);
    },
    exposes: [
        exposes
            .numeric('pulse_configuration', ea.ALL)
            .withValueMin(0)
            .withValueMax(65535)
            .withDescription('Pulses per kwh. Default 1000 imp/kWh. Range 0 to 65535'),
        exposes
            .numeric('current_summation', ea.SET)
            .withDescription('Current summation value sent to the display. e.g. 570 = 0,570 kWh')
            .withValueMin(0)
            .withValueMax(268435455),
    ],
};

module.exports = definition;

@tbowmo
Copy link

tbowmo commented Sep 30, 2024

btw, Frient A/S is another name of Develco Products A/S, so it's the same company (based in Denmark)

@tbowmo
Copy link

tbowmo commented Oct 1, 2024

Ok, I was a bit quick about my last code piece, as it doesn't work for me.. It seems that I do not get the correct multiplier/divisor from the seMetering cluster, to use in the generic metering function in fromZigbee. So it refuses to calculate metering data for me.

I'll have to rethink things a bit..

@jllarraz
Copy link

jllarraz commented Oct 4, 2024

Hi @Jens-Wymeersch, Unfortunately I dont have too much spare time these days to do a PR and I think someone else has already done it.

Regarding to the battery not being updated, I have being testing lately this converter emizb_141.txt (Same as the one already publish here, but with a small modification)

The modification is to add "fz.battery" to "fromZigbee". now is looking as this
fromZigbee: [develco.fz.metering, develco.fz.pulse_configuration, develco.fz.interface_mode, fz.battery]

In my case after around 20 minutes of uploading the new converter I could see changes in battery level.

Note: if you are going to use the file uploaded change the extension to "js" also remember to restart z2m extension once the new converter is added

@nivek1612
Copy link

Thanks @jllarraz I have made that change to my convertor. No change yet but I will update once it does.

@Jens-Wymeersch
Copy link

@jllarraz Fully understand. That said, it looks like @tbowmo need someone to look at the PR. Maybe you can have a look ?

@nivek1612
Copy link

@jllarraz I can confirm your change now enables the battery % to update
Took around 30 minutes after uploading the new converter for it to update.
I’m seeing a reading of 80% which after around a year of operation feels correct.

@Jens-Wymeersch
Copy link

@nivek1612 Can you please share your updated and working converter ?

@nivek1612
Copy link

It’s the same as the one published above in @jllarraz post
Download that and change the txt extension to js

@Jens-Wymeersch
Copy link

@nivek1612 Maybe you can have a look at the PR that was made by @tbowmo Koenkk/zigbee-herdsman-converters#8044

@Jens-Wymeersch
Copy link

@tbowmo sorry to bother you. I saw that your PR was approved. Does it work ?

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

@Jens-Wymeersch I haven't tested yet myself yet, as the frient device is in the summerhouse, so I'll have to go there and do some tests.

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

@Jens-Wymeersch Went to the summerhouse, to test things out. and it works, below is the published state from my frient device.

had to jump a couple of loopholes before I got it working, but that's life on bleeding edge :)

{
    "battery": 100,
    "battery_low": false,
    "energy": 118.28,
    "interface_mode": "electricity",
    "linkquality": 112,
    "power": 421,
    "power_2": 357,
    "pulse_configuration": 1000,
    "update": {
        "installed_version": 196866,
        "latest_version": 196866,
        "state": "idle"
    },
    "voltage": 3100,
    "current_summation": null,
    "update_available": null
}

@nivek1612
Copy link

Battery 100% makes me think it may not be fully working

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

It's only been in operation for one week.

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

And by looking through the logs, that is the value that my ember zigbee stick is sending to zigbee2mqtt.

@Jens-Wymeersch
Copy link

@tbowmo maybe put an older battery inside and see if it still works

@Jens-Wymeersch
Copy link

@Koenkk Not sure in which release the PR will be reflected ?

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

@tbowmo maybe put an older battery inside and see if it still works

That could be done, but right now I've left the summerhouse again, not going back in rhe next couple of days

@nivek1612
Copy link

It's only been in operation for one week.

That would make sense, mine is only down to 80% after nearly a year

@tbowmo
Copy link

tbowmo commented Oct 5, 2024

If anyone is able to test my pr, please do so. Specially the part with changing pulse counts

@iceweasel1
Copy link

Hello everyone,

Is there any news on how to set the correct value for Home Assistant and ZigBee2MQTT if you have an electricity meter that does not output the standard 1000 pulses/kWh, but 10000, for example?

And also how the energy consumption can be displayed?

As of today, I have connected the Friend Electricity Interface 2 (EMIZB-141) via ZigBee2MQTT. My electricity meter is a Landi+Gyr E320-AM1D.A3A.A0-S1B-S3 and unfortunately has the 10000 imp/kWh at the said reading output.

As a result, it shows me the live value incorrectly because of the multiplied difference between 1000 and 10000 pulses.

For energy, I have “Unknown” as the value in Home Assistant and “zero” in ZigBee2MQTT.

All other things, such as battery, link quality, update state are displayed correctly.

Are there solutions for the 10000 and energy value problem without having to install an add-on or a helper or change something in the YAML in ZigBee2MQTT?

That would be too complicated for me. Sorry.

Regards
René

@tbowmo
Copy link

tbowmo commented Oct 14, 2024

I have a pr open, that should fix everything for the frient device.

However, I haven't had the time to verify it, as I have to go to my summerhouse, as that's where it's located. And currently the summerhouse is occupied.

Hopefully I can do it in the coming weekend.

If someone elsw is able to test it, please do so. (need to jump a couple of hoops, but is manageaable)

@tbowmo
Copy link

tbowmo commented Oct 16, 2024

So finally I got around to test my pr to zigbee-herdsman-converters, and it works like it should. So just waiting for @Koenkk to do his magic with merge and release

@nivek1612
Copy link

there is a new firmware for the frient - 196866

I can't to find much detail on what it brings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new device support New device support request
Projects
None yet
Development

Successfully merging a pull request may close this issue.