Koenkk / zigbee2mqtt

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

Support for OWON PC321 3-phase Clamp Power Meter #9525

Closed FoxConsult closed 2 years ago

FoxConsult commented 2 years ago

Please add the OWON PC321 3-phase Clamp Power Meter

Information about the device + link

Description: ZigBee 3-Phase Clamp Power Meter (80A/120A/200A/300A) Model: PC321 Vendor: OWON Technology Inc. ZigBee Profile: ZigBee HA1.2 Exposes: Irms, Vrms, Active Power & Energy, Reactive Power & Energy

Vendors product description: https://www.owon-smart.com/three-phase-clamp-measuring-equipment-energy-power-clamp-pc321-2-product/

Thanks

Update:

Here is my altered owon.js where i copied WSP404 to PC321, removed the switch stuff like on_off and changed the WSP404 line "exposes: [e.switch(), e.power(), e.energy()]," to "exposes: [e.voltage(), e.power(), e.current(), e.energy()],":

const exposes = require('../lib/exposes'); const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee}; const tz = require('../converters/toZigbee'); const constants = require('../lib/constants'); const reporting = require('../lib/reporting'); const e = exposes.presets;

module.exports = [ { zigbeeModel: ['PC321'], model: 'PC321', vendor: 'OWON', description: '3-Phase Clamp Power Meter', fromZigbee: [fz.metering], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.instantaneousDemand(endpoint, {min: 5, max: constants.repInterval.MINUTES_5, change: 2}); }, exposes: [e.voltage(), e.power(), e.current(), e.energy()], }, { zigbeeModel: ['WSP404'], model: 'WSP404', vendor: 'OWON', description: 'Smart plug', fromZigbee: [fz.on_off, fz.metering], toZigbee: [tz.on_off], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']); await reporting.onOff(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.instantaneousDemand(endpoint, {min: 5, max: constants.repInterval.MINUTES_5, change: 2}); }, exposes: [e.switch(), e.power(), e.energy()], },

The data coming back from the PC321 meter is:

Nov 6 20:11:14 raspberrypi-4 npm[32041]: #033[32mZigbee2MQTT:info #033[39m 2021-11-06 20:11:14: MQTT publish: topic 'zigbee2mqtt/0x3c6a2cfffed0d65c', payload '{"linkquality":123,"power":0}' Nov 6 20:11:14 raspberrypi-4 npm[32041]: #033[34mZigbee2MQTT:debug#033[39m 2021-11-06 20:11:14: Received Zigbee message from '0x3c6a2cfffed0d65c', type 'attributeReport', cluster 'seMetering', data '{"12288":2334,"12544":0,"16384":[0,142],"16640":[0,0],"16644":0,"8192":0,"8448":0}' from endpoint 1 with groupID 0 Nov 6 20:11:15 raspberrypi-4 npm[32041]: #033[34mZigbee2MQTT:debug#033[39m 2021-11-06 20:11:15: Received Zigbee message from '0x3c6a2cfffed0d65c', type 'attributeReport', cluster 'seMetering', data '{"12289":5,"12545":0,"16385":[0,141],"16641":[0,0],"16645":0,"8193":0,"8449":0}' from endpoint 1 with groupID 0 Nov 6 20:11:16 raspberrypi-4 npm[32041]: #033[34mZigbee2MQTT:debug#033[39m 2021-11-06 20:11:16: Received Zigbee message from '0x3c6a2cfffed0d65c', type 'attributeReport', cluster 'seMetering', data '{"12290":5,"12546":0,"16386":[0,142],"16642":[0,0],"16646":0,"8194":0,"8450":0}' from endpoint 1 with groupID 0 Nov 6 20:12:16 raspberrypi-4 npm[32041]: #033[34mZigbee2MQTT:debug#033[39m 2021-11-06 20:12:16: Received Zigbee message from '0x3c6a2cfffed0d65c', type 'attributeReport', cluster 'seMetering', data '{"12547":0,"16643":[0,0],"8451":0,"currentSummDelivered":[0,425],"instantaneousDemand":0,"status":0}' from endpoint 1 with groupID 0

And this is how the PC321 looks in my Domoticz installation: PC321_in_Domoticz

Unfortunately, I am stuck here not having the neccesary knowledge to make the PC231 Power Meter work.

Added 2021-11-16:

Instead of using t he WSP404 as basis I tried the 'EMIZB-132' from the develco.js file since the 'EMIZB-132' has 3-phase power measurement, added the line const "ea = exposes.access;" to my owon.js file as well as this:

{
    zigbeeModel: ['PC321'],
    model: 'PC321',
    vendor: 'OWON',
    description: '3-Phase Clamp Power Meter',
    supports: 'power measurement',
    fromZigbee: [fz.metering, fz.electrical_measurement, fz.develco_fw],
    toZigbee: [tz.EMIZB_132_mode],
    ota: ota.zigbeeOTA,
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(2);
        const options = {manufacturerCode: 4117};
        await endpoint.read('genBasic', [0x8000, 0x8010, 0x8020], options);
        await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering']);

        try {
            // Some don't support these attributes
            // https://github.com/Koenkk/zigbee-herdsman-converters/issues/974#issuecomment-621465038
            await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
            await reporting.rmsVoltage(endpoint);
            await reporting.rmsCurrent(endpoint);
            await reporting.activePower(endpoint);
        } catch (e) {
            e;
        }

        await reporting.readMeteringMultiplierDivisor(endpoint);
        endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 1000, multiplier: 1});
        await reporting.instantaneousDemand(endpoint);
        await reporting.currentSummDelivered(endpoint);
        await reporting.currentSummReceived(endpoint);
    },
    exposes: [e.power(), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(),
        e.voltage_phase_c()],
    onEvent: async (type, data, device) => {
        if (type === 'message' && data.type === 'attributeReport' && data.cluster === 'seMetering' && data.data['divisor']) {
            // Device sends wrong divisior (512) while it should be fixed to 1000
            // https://github.com/Koenkk/zigbee-herdsman-converters/issues/3066
            data.endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 1000, multiplier: 1});
        }
    },
},
{

but get this error

2021-11-16 13:45:58.052 Error: Zigbee2MQTT: 0x3c6a2cfffed0d65c: can not process numeric item "current_phase_b" 2021-11-16 13:45:58.052 Error: Zigbee2MQTT: 0x3c6a2cfffed0d65c: can not process numeric item "voltage_phase_b" 2021-11-16 13:45:58.052 Error: Zigbee2MQTT: 0x3c6a2cfffed0d65c: can not process numeric item "current_phase_c" 2021-11-16 13:45:58.052 Error: Zigbee2MQTT: 0x3c6a2cfffed0d65c: can not process numeric item "voltage_phase_c"

The device reports energy and power usage, but with a negative value:

owon_clamp_meter

I have emailed Owon and asked for a copy of the protocol, but unfortunately, no answer.

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

FoxConsult commented 2 years ago

Still need support for my OWON Power Meter.

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

Phil-ibert commented 2 years ago

Hello,

I also own this device but am struggling to configure an external converter for it... It seems like it reports to the "seMetering" cluster but that the IDs used are unknown by Z2M :

I'd be happy to help, if somebody would be able to provide guidance on this ;)

Received Zigbee message from '0x3c6a2cfffed1a7d2', type 'attributeReport', cluster 'seMetering', data '{"12288":2318,"12544":0,"16384":[0,0],"16640":[0,0],"16644":0,"8192":2,"8448":0}' from endpoint 1 with groupID 0 Debug Received Zigbee message from '0x3c6a2cfffed1a7d2', type 'attributeReport', cluster 'seMetering', data '{"12289":2312,"12545":0,"16385":[0,0],"16641":[0,0],"16645":0,"8193":0,"8449":0}' from endpoint 1 with groupID 0 Debug Received Zigbee message from '0x3c6a2cfffed1a7d2', type 'attributeReport', cluster 'seMetering', data '{"12290":2316,"12546":0,"16386":[0,0],"16642":[0,0],"16646":0,"8194":0,"8450":0}' from endpoint 1 with groupID 0 Debug Received Zigbee message from '0x3c6a2cfffed1a7d2', type 'attributeReport', cluster 'seMetering', data '{"12547":0,"16643":[0,0],"8451":0,"currentSummDelivered":[0,0],"instantaneousDemand":0,"status":0}' from endpoint 1 with groupID 0

FoxConsult commented 2 years ago

Hello,

I sold my meter since I no longer had any use for it, but before I did, I asked the manufacturer for the protocol spec's which I got, but only after signing a Non Disclosure Agreement which stipulates I cannot share the document with anyone.

My suggestion is that you request the protocol specification from the manufacturer. I sent my request to:

sales@owon.com and info@owon.com and got a reply from their outfit in Canada. I'm not at liberty of sharing their names and e-mail addresses, but I'm sure they will reply to you promptly which they did to me.

Phil-ibert commented 2 years ago

Hi FoxConsult,

Uon searching on the device, I found the following repository which contains basically all that is needed to integrate the device : https://github.com/froggyfly/pc321-zigbee

What I don't know however, is how to use the external converters for that, as to me it seems that the seMetering cluster definition of Z2M has to be extended to fully support this device.

Also, to test it I guess I have to (re)compile the whole Z2M project with the updated clusters.ts file ? Or can I simply edit a file on my Z2M instance ?

Hello @Koenkk, sorry to disturb you but if you could shed some light/point me towards the right direction... ;)

Koenkk commented 2 years ago

It seems the device is using non standard attributes and therefore zigbee2mqtt doesn't know what the device means with e.g. "12547":0,"16643":[0,0],"8451":0. You have to reverse engineer what they do either by asking the manufacturer or by guessing based on their values. Keep in mind that if all functions of the device works correctly, there is no need to do this and the device can be added to z2m.

Phil-ibert commented 2 years ago

Thank you for your reply,

I have all the attributes definition (ID, name, type, default values...) image

However I do not know how to proceed with an external converter to make it work... My guess is that the non standard attributes have to be added to the seMetering cluster definition, and then exposed with an external converter. But, how to add the seMetering definition ? can it be done from the external converter file? or must it be extended from cluster.ts in the Herdsman project ?

Thank you

Koenkk commented 2 years ago

I see you added the manufacturer specific attributes, you can create a new converter which converts these to MQTT.

  1. update to the latest-dev (https://www.zigbee2mqtt.io/advanced/more/switch-to-dev-branch.html)
  2. Add the following 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 extend = require('zigbee-herdsman-converters/lib/extend');
    const ota = require('zigbee-herdsman-converters/lib/ota');
    const e = exposes.presets;
    const ea = exposes.access;

const fzLocal = { PC321_metering: { cluster: 'seMetering', type: ['attributeReport', 'readResponse'], convert: (model, msg, publish, options, meta) => { const payload = {};

        // TODO: add the other attributes here

        if (msg.data.hasOwnProperty('owonL1Energy')) {
            payload.energy_l1 = msg.data['owonL1Energy'];
        }

        return payload;
    },
}

}

const definition = { zigbeeModel: ['PC321'], model: 'PC321', vendor: 'OWON', description: '3-Phase Clamp Power Meter', toZigbee: [], fromZigbee: [fz.metering, fzLocal.PC321_metering], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.instantaneousDemand(endpoint, {min: 5, max: constants.repInterval.MINUTES_5, change: 2}); }, exposes: [e.voltage(), e.power(), e.current(), e.energy()], };

module.exports = definition;

Phil-ibert commented 2 years ago

Many thanks Koenkk for the converter template.

I added it and switched to the dev branch, but Z2M fails to start, returning the following error:

(node:28624) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'push' of undefined at Object.addDefinition [as addDeviceDefinition] (/app/node_modules/zigbee-herdsman-converters/index.js:78:25) at new ExternalConverters (/app/lib/extension/externalConverters.ts:15:17) at new Controller (/app/lib/controller.ts:83:58) at start (/app/index.js:100:18) (Usenode --trace-warnings ...to show where the warning was created) (node:28624) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag--unhandled-rejections=strict(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:28624) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Following the template, if I wanted to expose the phase 1 energy, e.energy_l1() into exposes would be enough ?

Sorry for all those questions, I am not really familiar with nodejs..

Koenkk commented 2 years ago

Updated https://github.com/Koenkk/zigbee2mqtt/issues/9525#issuecomment-1086852577, should be fixed now.

Phil-ibert commented 2 years ago

It works ! I even managed to have the attributes exposed to Home Assistant using a new numeric() definition in the 'exposes' array.

There are a couple minor issues left, for which I am pretty much clueless for now... Here they are :

I fixed the first two by dividing the data before storing it to the payload, but that does not seem the right way to do :)

Z2M also reports some errors, most likely while trying to get the multiplier/divisor values which could be related to some of the issues faced ?

Here is the error message : Failed to configure 'Owon Power meter', attempt 2 (ReferenceError: constants is not defined at Object.configure (/app/dist/util/externally-loaded.js:76:69) at Configure.configure (/app/lib/extension/configure.ts:115:13))

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

const fzLocal = {
    PC321_metering: {
        cluster: 'seMetering',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const payload = {};
            if (msg.data.hasOwnProperty('owonL2Energy')) {
                payload.energy_l2 = msg.data['owonL2Energy'] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3Energy')) {
                payload.energy_l3 = msg.data['owonL3Energy'] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL1PhasePower')) {
                payload.power_l1 = msg.data['owonL1PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL2PhasePower')) {
                payload.power_l2 = msg.data['owonL2PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL3PhasePower')) {
                payload.power_l3 = msg.data['owonL3PhasePower'];
            }

            if (msg.data.hasOwnProperty('owonL1PhaseVoltage')) {
                payload.voltage_l1 = msg.data['owonL1PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL2PhaseVoltage')) {
                payload.voltage_l2 = msg.data['owonL2PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL3PhaseVoltage')) {
                payload.voltage_l3 = msg.data['owonL3PhaseVoltage'] / 10.0;
            }

            if (msg.data.hasOwnProperty('owonL1PhaseCurrent')) {
                payload.current_l1 = msg.data['owonL1PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL2PhaseCurrent')) {
                payload.current_l2 = msg.data['owonL2PhaseCurrent'] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3PhaseCurrent')) {
                payload.current_l3 = msg.data['owonL3PhaseCurrent'] / 1000.0;
            }

            // TODO: add the other attributes here

            if (msg.data.hasOwnProperty('owonL1Energy')) {
                payload.energy_l1 = msg.data['owonL1Energy'] / 1000.0;
            }

            return payload;
        },
    },
};

const definition = {
    zigbeeModel: ['PC321'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
    model: 'PC321', // Vendor model number, look on the device for a model number
    vendor: 'OWON', // Vendor of the device (only used for documentation and startup logging)
    description: '3-Phase Clamp Power Meter', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
    fromZigbee: [fz.metering, fzLocal.PC321_metering],
    toZigbee: [], // Should be empty, unless device can be controlled (e.g. lights, switches).
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
        await reporting.readMeteringMultiplierDivisor(endpoint);
        await reporting.instantaneousDemand(endpoint, {min: 5, max: constants.repInterval.MINUTES_5, change: 2});
    },
    exposes: [e.energy(),
    exposes.numeric('voltage_l1',ea.STATE).withUnit('V').withDescription('Phase 1 Voltage'),
    exposes.numeric('voltage_l2',ea.STATE).withUnit('V').withDescription('Phase 2 Voltage'),
    exposes.numeric('voltage_l3',ea.STATE).withUnit('V').withDescription('Phase 3 Voltage'),
    exposes.numeric('current_l1',ea.STATE).withUnit('A').withDescription('Phase 1 Current'),
    exposes.numeric('current_l2',ea.STATE).withUnit('A').withDescription('Phase 2 Current'),
    exposes.numeric('current_l3',ea.STATE).withUnit('A').withDescription('Phase 3 Current'),
    exposes.numeric('energy_l1',ea.STATE).withUnit('kWh').withDescription('Phase 1 Energy'),
    exposes.numeric('energy_l2',ea.STATE).withUnit('kWh').withDescription('Phase 2 Energy'),
    exposes.numeric('energy_l3',ea.STATE).withUnit('kWh').withDescription('Phase 3 Energy'),
    exposes.numeric('power_l1',ea.STATE).withUnit('W').withDescription('Phase 1 Power'),
    exposes.numeric('power_l2',ea.STATE).withUnit('W').withDescription('Phase 2 Power'),
    exposes.numeric('power_l3',ea.STATE).withUnit('W').withDescription('Phase 3 Power'),
    ],

};

module.exports = definition;
Koenkk commented 2 years ago

Try adding the following line at the top of your file: const constants = require('zigbee-herdsman-converters/lib/constants');

Phil-ibert commented 2 years ago

Hi Koenkk, I thought I posted this last sunday but I didnt... my bad

It improved but now Z2M goes into timeout trying to configure the device, here is the error :

Failed to configure 'Owon Power meter', attempt 2 (Error: ConfigureReporting 0x3c6a2cfffed1a7d2/1 seMetering([{"attribute":"instantaneousDemand","minimumReportInterval":5,"maximumReportInterval":300,"reportableChange":2}], {"sendWhen":"immediate","timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Timeout - 43847 - 1 - 6 - 1794 - 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))

I am all ears (and fingers) to try to improve this ;)

Koenkk commented 2 years ago

What is you replace await reporting.instantaneousDemand(endpoint, {min: 5, max: constants.repInterval.MINUTES_5, change: 2}); with:

            const payload = [{
                attribute: 'owonL2Energy',
                minimumReportInterval: 5,
                maximumReportInterval: 3600,
                reportableChange: 0,
            }];
            await endpoint.configureReporting('haElectricalMeasurement', payload);
Phil-ibert commented 2 years ago

Hi Koenkk,

it still fails, but with another error

Failed to configure 'Owon Power meter', attempt 2 (Error: ConfigureReporting 0x3c6a2cfffed1a7d2/1 haElectricalMeasurement([{"attribute":"owonL2Energy","minimumReportInterval":5,"maximumReportInterval":3600,"reportableChange":0}], {"sendWhen":"immediate","timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Don't know value type for 'undefined') at Object.IsDataTypeAnalogOrDiscrete (/app/node_modules/zigbee-herdsman/src/zcl/utils.ts:30:15) at /app/node_modules/zigbee-herdsman/src/zcl/zclFrame.ts:354:38 at Array.find (<anonymous>) at Function.conditionsValid (/app/node_modules/zigbee-herdsman/src/zcl/zclFrame.ts:338:58) at ZclFrame.writePayloadGlobal (/app/node_modules/zigbee-herdsman/src/zcl/zclFrame.ts:113:35) at ZclFrame.toBuffer (/app/node_modules/zigbee-herdsman/src/zcl/zclFrame.ts:76:18) at ZStackAdapter.sendZclFrameToEndpointInternal (/app/node_modules/zigbee-herdsman/src/adapter/z-stack/adapter/zStackAdapter.ts:388:22) at Object.func (/app/node_modules/zigbee-herdsman/src/adapter/z-stack/adapter/zStackAdapter.ts:356:25) at Queue.executeNext (/app/node_modules/zigbee-herdsman/src/utils/queue.ts:32:42) at /app/node_modules/zigbee-herdsman/src/utils/queue.ts:21:18)

Koenkk commented 2 years ago

@Phil-ibert is the on the latest z2m dev? (https://www.zigbee2mqtt.io/advanced/more/switch-to-dev-branch.html)

Phil-ibert commented 2 years ago

I am currently running 1.25.0-dev commit: 91d80f1

I'll upgrade to the latest, see if there is any improvement

Phil-ibert commented 2 years ago

After upgrading to the last dev version no error messages anymore, you rock Sir !

Ano10 commented 2 years ago

Hi, I haven't see this device into supported device list. Is it working ? If so are you planning to add it ?

Phil-ibert commented 2 years ago

Hi Ano10,

I managed to get most of the data reporting working, only the network frequency is not reported but it seems to be on the device side.

However, I did not know how to configure Z2M in order to set up the writable attributes such as the report frequency or threshold. Maybe @Koenkk could have a look sometime ? I'll push my custom file to the appropriate repo this week

Koenkk commented 2 years ago

@Phil-ibert you will be able to write any value via the dev console (frontend -> click on your device)

zekje commented 2 years ago

Hi, i have tried to install it to Zigbee2Mqtt (into Home Assistant) .

Home assistant 2022.6.2 Zigbee2mqtt Edge 1.25.2-dev commit: [300b297]

i have added a file ( OWONPC321.js ) into the config dir, with the content of post #9525

Item is now 'supported' :)

but i have this errors : Failed to configure '0x3c6a2cfffed15361', attempt 2 (ReferenceError: constants is not defined at Object.configure (/app/dist/util/externally-loaded.js:40:63) at Configure.configure (/app/lib/extension/configure.ts:115:13) at Configure.onMQTTMessage (/app/lib/extension/configure.ts:55:21))

on the exposed value , i have only ( in french ) voltage Sans valeur V power 1W current Sans valeur A energy 104.4kWh linkquality 255lqi

(in french , 'sans valeur' is 'no value' in english ) how to measure the 3 phases separately ?

thank's

Phil-ibert commented 2 years ago

Hi Zekje,

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

const fzLocal = {
    PC321_metering: {
        cluster: 'seMetering',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const payload = {};
            if (msg.data.hasOwnProperty('owonL1Energy')) {
                payload.energy_l1 = msg.data['owonL1Energy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL2Energy')) {
                payload.energy_l2 = msg.data['owonL2Energy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3Energy')) {
                payload.energy_l3 = msg.data['owonL3Energy'][1] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL1ReactiveEnergy')) {
                payload.reactive_energy_l1 = msg.data['owonL1ReactiveEnergy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL2ReactiveEnergy')) {
                payload.reactive_energy_l2 = msg.data['owonL2ReactiveEnergy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3ReactiveEnergy')) {
                payload.reactive_energy_l3 = msg.data['owonL3ReactiveEnergy'][1] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL1PhasePower')) {
                payload.power_l1 = msg.data['owonL1PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL2PhasePower')) {
                payload.power_l2 = msg.data['owonL2PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL3PhasePower')) {
                payload.power_l3 = msg.data['owonL3PhasePower'];
            }

             if (msg.data.hasOwnProperty('owonL1PhaseReactivePower')) {
                payload.reactive_power_l1 = msg.data['owonL1PhaseReactivePower'];
            }
            if (msg.data.hasOwnProperty('owonL2PhaseReactivePower')) {
                payload.reactive_power_l2 = msg.data['owonL2PhaseReactivePower'];
            }
            if (msg.data.hasOwnProperty('owonL3PhaseReactivePower')) {
                payload.reactive_power_l3 = msg.data['owonL3PhaseReactivePower'];
            }

            if (msg.data.hasOwnProperty('owonL1PhaseVoltage')) {
                payload.voltage_l1 = msg.data['owonL1PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL2PhaseVoltage')) {
                payload.voltage_l2 = msg.data['owonL2PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL3PhaseVoltage')) {
                payload.voltage_l3 = msg.data['owonL3PhaseVoltage'] / 10.0;
            }

            if (msg.data.hasOwnProperty('owonL1PhaseCurrent')) {
                payload.current_l1 = msg.data['owonL1PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL2PhaseCurrent')) {
                payload.current_l2 = msg.data['owonL2PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL3PhaseCurrent')) {
                payload.current_l3 = msg.data['owonL3PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonFrequency')) {
                payload.frequency = msg.data['owonFrequency'];
            }

            if (msg.data.hasOwnProperty('owonReactiveEnergySum')) {
                payload.reactive_energy_sum = msg.data['owonReactiveEnergySum'];
            }

            return payload;
        },
    },
};

const definition = {
    zigbeeModel: ['PC321'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
    model: 'PC321', // Vendor model number, look on the device for a model number
    vendor: 'OWON', // Vendor of the device (only used for documentation and startup logging)
    description: '3-Phase Clamp Power Meter', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
    fromZigbee: [fz.metering, fzLocal.PC321_metering],
    toZigbee: [], // Should be empty, unless device can be controlled (e.g. lights, switches).
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
        await reporting.readMeteringMultiplierDivisor(endpoint);
        const payload = [{
                attribute: 'owonFrequency',
                minimumReportInterval: 5,
                maximumReportInterval: 3600,
                reportableChange: 0,
            }];
            await endpoint.configureReporting('seMetering', payload);
    },
    exposes: [e.energy(),
    exposes.numeric('voltage_l1',ea.STATE).withUnit('V').withDescription('Phase 1 Voltage'),
    exposes.numeric('voltage_l2',ea.STATE).withUnit('V').withDescription('Phase 2 Voltage'),
    exposes.numeric('voltage_l3',ea.STATE).withUnit('V').withDescription('Phase 3 Voltage'),
    exposes.numeric('current_l1',ea.STATE).withUnit('A').withDescription('Phase 1 Current'),
    exposes.numeric('current_l2',ea.STATE).withUnit('A').withDescription('Phase 2 Current'),
    exposes.numeric('current_l3',ea.STATE).withUnit('A').withDescription('Phase 3 Current'),
    exposes.numeric('energy_l1',ea.STATE).withUnit('kWh').withDescription('Phase 1 Energy'),
    exposes.numeric('energy_l2',ea.STATE).withUnit('kWh').withDescription('Phase 2 Energy'),
    exposes.numeric('energy_l3',ea.STATE).withUnit('kWh').withDescription('Phase 3 Energy'),
    exposes.numeric('reactive_energy_l1',ea.STATE).withUnit('kVArh').withDescription('Phase 1 Reactive Energy'),
    exposes.numeric('reactive_energy_l2',ea.STATE).withUnit('kVArh').withDescription('Phase 2 Reactive Energy'),
    exposes.numeric('reactive_energy_l3',ea.STATE).withUnit('kVArh').withDescription('Phase 3 Reactive Energy'),
    exposes.numeric('power_l1',ea.STATE).withUnit('W').withDescription('Phase 1 Power'),
    exposes.numeric('power_l2',ea.STATE).withUnit('W').withDescription('Phase 2 Power'),
    exposes.numeric('power_l3',ea.STATE).withUnit('W').withDescription('Phase 3 Power'),
    exposes.numeric('reactive_power_l1',ea.STATE).withUnit('VAr').withDescription('Phase 1 Reactive Power'),
    exposes.numeric('reactive_power_l2',ea.STATE).withUnit('VAr').withDescription('Phase 2 Reactive Power'),
    exposes.numeric('reactive_power_l3',ea.STATE).withUnit('VAr').withDescription('Phase 3 Reactive Power'),
    exposes.numeric('frequency',ea.STATE).withUnit('Hz').withDescription('Frequency'),
    exposes.numeric('reactive_energy_sum',ea.STATE).withUnit('kVArh').withDescription('Reactive Energy Sum'),
    ],

};

module.exports = definition;

I have a pending pull request for the device to be supported natively by Z2M, it may be closed soon ;)

Phil-ibert commented 2 years ago

@Phil-ibert you will be able to write any value via the dev console (frontend -> click on your device)

Hi Koenkk,

when I try to use the console dev, I get an "Unsupported_attribute" error, even on data items that are already reporting correctly image

zekje commented 2 years ago

@phil-ibert thank's , all data is show now :)

some adjustement needed , but not important . ( frequency not measured , and the device show with '?' instead of sector (or battery) )

dokkomp commented 1 year ago

@Koenkk Hi, i have tried to install it to Zigbee2Mqtt (Home Assistant) .

Model: OWON PC321-Z-TY Home Assistant 2022.10.5 Zigbee2MQTT Current version: 1.28.0-1 Zigbee model 'TS0601' and manufacturer name '_TZE200_nslr42tt'

I have added a file ( 321-z-ty.js ) into the config dir, with the content of post @Phil-ibert :

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

const fzLocal = {
    PC321_metering: {
        cluster: 'seMetering',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const payload = {};
            if (msg.data.hasOwnProperty('owonL1Energy')) {
                payload.energy_l1 = msg.data['owonL1Energy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL2Energy')) {
                payload.energy_l2 = msg.data['owonL2Energy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3Energy')) {
                payload.energy_l3 = msg.data['owonL3Energy'][1] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL1ReactiveEnergy')) {
                payload.reactive_energy_l1 = msg.data['owonL1ReactiveEnergy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL2ReactiveEnergy')) {
                payload.reactive_energy_l2 = msg.data['owonL2ReactiveEnergy'][1] / 1000.0;
            }
            if (msg.data.hasOwnProperty('owonL3ReactiveEnergy')) {
                payload.reactive_energy_l3 = msg.data['owonL3ReactiveEnergy'][1] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL1PhasePower')) {
                payload.power_l1 = msg.data['owonL1PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL2PhasePower')) {
                payload.power_l2 = msg.data['owonL2PhasePower'];
            }
            if (msg.data.hasOwnProperty('owonL3PhasePower')) {
                payload.power_l3 = msg.data['owonL3PhasePower'];
            }

             if (msg.data.hasOwnProperty('owonL1PhaseReactivePower')) {
                payload.reactive_power_l1 = msg.data['owonL1PhaseReactivePower'];
            }
            if (msg.data.hasOwnProperty('owonL2PhaseReactivePower')) {
                payload.reactive_power_l2 = msg.data['owonL2PhaseReactivePower'];
            }
            if (msg.data.hasOwnProperty('owonL3PhaseReactivePower')) {
                payload.reactive_power_l3 = msg.data['owonL3PhaseReactivePower'];
            }

            if (msg.data.hasOwnProperty('owonL1PhaseVoltage')) {
                payload.voltage_l1 = msg.data['owonL1PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL2PhaseVoltage')) {
                payload.voltage_l2 = msg.data['owonL2PhaseVoltage'] / 10.0;
            }
            if (msg.data.hasOwnProperty('owonL3PhaseVoltage')) {
                payload.voltage_l3 = msg.data['owonL3PhaseVoltage'] / 10.0;
            }

            if (msg.data.hasOwnProperty('owonL1PhaseCurrent')) {
                payload.current_l1 = msg.data['owonL1PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL2PhaseCurrent')) {
                payload.current_l2 = msg.data['owonL2PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonL3PhaseCurrent')) {
                payload.current_l3 = msg.data['owonL3PhaseCurrent'] / 1000.0;
            }

            if (msg.data.hasOwnProperty('owonFrequency')) {
                payload.frequency = msg.data['owonFrequency'];
            }

            if (msg.data.hasOwnProperty('owonReactiveEnergySum')) {
                payload.reactive_energy_sum = msg.data['owonReactiveEnergySum'];
            }

            return payload;
        },
    },
};

const definition = {
    zigbeeModel: ['TS0601'], // The model ID from: Device with modelID 'lumi.sens' is not supported.
    model: 'TS0601', // Vendor model number, look on the device for a model number
    vendor: 'OWON', // Vendor of the device (only used for documentation and startup logging)
    description: '3-Phase Clamp Power Meter', // Description of the device, copy from vendor site. (only used for documentation and startup logging)
    fromZigbee: [fz.metering, fzLocal.PC321_metering],
    toZigbee: [], // Should be empty, unless device can be controlled (e.g. lights, switches).
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
        await reporting.readMeteringMultiplierDivisor(endpoint);
        const payload = [{
                attribute: 'owonFrequency',
                minimumReportInterval: 5,
                maximumReportInterval: 3600,
                reportableChange: 0,
            }];
            await endpoint.configureReporting('seMetering', payload);
    },
    exposes: [e.energy(),
    exposes.numeric('voltage_l1',ea.STATE).withUnit('V').withDescription('Phase 1 Voltage'),
    exposes.numeric('voltage_l2',ea.STATE).withUnit('V').withDescription('Phase 2 Voltage'),
    exposes.numeric('voltage_l3',ea.STATE).withUnit('V').withDescription('Phase 3 Voltage'),
    exposes.numeric('current_l1',ea.STATE).withUnit('A').withDescription('Phase 1 Current'),
    exposes.numeric('current_l2',ea.STATE).withUnit('A').withDescription('Phase 2 Current'),
    exposes.numeric('current_l3',ea.STATE).withUnit('A').withDescription('Phase 3 Current'),
    exposes.numeric('energy_l1',ea.STATE).withUnit('kWh').withDescription('Phase 1 Energy'),
    exposes.numeric('energy_l2',ea.STATE).withUnit('kWh').withDescription('Phase 2 Energy'),
    exposes.numeric('energy_l3',ea.STATE).withUnit('kWh').withDescription('Phase 3 Energy'),
    exposes.numeric('reactive_energy_l1',ea.STATE).withUnit('kVArh').withDescription('Phase 1 Reactive Energy'),
    exposes.numeric('reactive_energy_l2',ea.STATE).withUnit('kVArh').withDescription('Phase 2 Reactive Energy'),
    exposes.numeric('reactive_energy_l3',ea.STATE).withUnit('kVArh').withDescription('Phase 3 Reactive Energy'),
    exposes.numeric('power_l1',ea.STATE).withUnit('W').withDescription('Phase 1 Power'),
    exposes.numeric('power_l2',ea.STATE).withUnit('W').withDescription('Phase 2 Power'),
    exposes.numeric('power_l3',ea.STATE).withUnit('W').withDescription('Phase 3 Power'),
    exposes.numeric('reactive_power_l1',ea.STATE).withUnit('VAr').withDescription('Phase 1 Reactive Power'),
    exposes.numeric('reactive_power_l2',ea.STATE).withUnit('VAr').withDescription('Phase 2 Reactive Power'),
    exposes.numeric('reactive_power_l3',ea.STATE).withUnit('VAr').withDescription('Phase 3 Reactive Power'),
    exposes.numeric('frequency',ea.STATE).withUnit('Hz').withDescription('Frequency'),
    exposes.numeric('reactive_energy_sum',ea.STATE).withUnit('kVArh').withDescription('Reactive Energy Sum'),
    ],

};

module.exports = definition;

but i have this errors :

Zigbee2MQTT:info 2022-10-28 20:09:57: Configuring 'Energy' Zigbee2MQTT:error 2022-10-28 20:10:17: Failed to configure 'Energy', attempt 2 (Error: Read 0xa4c138129f4abd2e/1 seMetering(["multiplier","divisor"], {"sendWhen":"immediate","timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"srcEndpoint":null,"reservedBits":0,"manufacturerCode":null,"transactionSequenceNumber":null,"writeUndiv":false}) failed (Timeout - 26610 - 1 - 4 - 1794 - 1 after 10000ms) at Timeout._onTimeout (/app/node_modules/zigbee-herdsman/src/utils/waitress.ts:64:35) at listOnTimeout (node:internal/timers:559:17) at processTimers (node:internal/timers:502:7))

please help me

Koenkk commented 1 year ago

@dokkomp https://github.com/Koenkk/zigbee2mqtt/issues/9525#issuecomment-1148274734

@zekje @Phil-ibert sorry I did not respond, does the device work well with the external converter?

dokkomp commented 1 year ago

Hi @Koenkk @zekje @Phil-ibert Guys don't answer(. Can you help me with my problem? Please)

zekje commented 1 year ago

Sorry i am not at home, i Can answer today with my working configuration

Le mar. 1 nov. 2022, 12:44, dokkomp @.***> a écrit :

Hi @Koenkk https://github.com/Koenkk @zekje https://github.com/zekje @Phil-ibert https://github.com/Phil-ibert Guys don't answer(. Can you help me with my problem? Please)

— Reply to this email directly, view it on GitHub https://github.com/Koenkk/zigbee2mqtt/issues/9525#issuecomment-1298397132, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHBIBLQMOCZV42F43ISJLVLWGD7BVANCNFSM5HONYNRQ . You are receiving this because you were mentioned.Message ID: @.***>

Phil-ibert commented 1 year ago

Hi @dokkomp,

My apologies for the late reply.

Regarding the frequency, the documentation of the device says it reports it through a specified attribute, but it actually does not report anything for that...

As to the power source, it is actually working into the code I pushed to the official repository.

Today, all you need is to have an up to date Z2M version (1.28 at least ?)

dokkomp commented 1 year ago

I have the latest version now 1.28.1-1 Here is my log: Zigbee2MQTT:debug 2022-11-02 14:47:22: Received Zigbee message from 'Energy', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,0],"type":"Buffer"},"datatype":2,"dp":122}],"seq":44032}' from endpoint 1 with groupID 0 Zigbee2MQTT:warn 2022-11-02 14:47:22: Received message from unsupported device with Zigbee model 'TS0601' and manufacturer name '_TZE200_nslr42tt' Zigbee2MQTT:warn 2022-11-02 14:47:22: Please see: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html

Phil-ibert commented 1 year ago

This error is in regard of a Tuya switch, not the OWON PC321

https://fr.aliexpress.com/item/4001181765345.html?spm=a2g0s.9042311.0.0.71ef5c0fxTke0W&gatewayAdapt=glo2fra

You should already see your power meter device, provided that you paired it with Z2M ?

dokkomp commented 1 year ago

@Phil-ibert yes, you are right( MatSeePlus PC321-Z-TY

https://www.aliexpress.com/item/1005004446589629.html?srcSns=sns_Telegram&spreadType=socialShare&bizType=ProductDetail&social_params=60213178328&aff_fcid=2848df6c4a68491a8cd51a489e83758c-1667397700768-07323-_Eu5e3Mv&tt=MG&aff_fsk=_Eu5e3Mv&aff_platform=default&sk=_Eu5e3Mv&aff_trace_key=2848df6c4a68491a8cd51a489e83758c-1667397700768-07323-_Eu5e3Mv&shareId=60213178328&businessType=ProductDetail&platform=AE&terminal_id=a5c9729122214353b83495ad3abfeba1&afSmartRedirect=y&gatewayAdapt=glo2bra

how do i add it now in z2m?

Phil-ibert commented 1 year ago

You just have to follow the usual pairing process :

Please note that the PC321-TY is wifi and the PC321-Z-TY is Zigbee

dokkomp commented 1 year ago

@Phil-ibert In z2m I added it But I am not receiving data from that device.

Phil-ibert commented 1 year ago

What does the "exposes" tab shows for your device ? How did you wire it in your electrical installation ?

dokkomp commented 1 year ago

@Phil-ibert

Without an external converter: Empty exposes definition

With the external converter from the post above: energy Sum of consumed energy N/AkWh voltage_l1 Phase 1 Voltage N/AV voltage_l2 Phase 2 Voltage N/AV voltage_l3 Phase 3 Voltage N/AV current_l1 Phase 1 Current N/AA current_l2 Phase 2 Current N/AA current_l3 Phase 3 Current N/AA energy_l1 Phase 1 Energy N/AkWh energy_l2 Phase 2 Energy N/AkWh energy_l3 Phase 3 Energy N/AkWh reactive_energy_l1 Phase 1 Reactive Energy N/AkVArh reactive_energy_l2 Phase 2 Reactive Energy N/AkVArh reactive_energy_l3 Phase 3 Reactive Energy N/AkVArh power_l1 Phase 1 Power N/AW power_l2 Phase 2 Power N/AW power_l3 Phase 3 Power N/AW reactive_power_l1 Phase 1 Reactive Power N/AVAr reactive_power_l2 Phase 2 Reactive Power N/AVAr reactive_power_l3 Phase 3 Reactive Power N/AVAr frequency Frequency N/AHz reactive_energy_sum Reactive Energy Sum N/AkVArh linkquality Link quality (signal strength) 255lqi

Phil-ibert commented 1 year ago

Maybe the PC321-Z-TY is different than the PC321 that I have ?

Because mine is working as expected with the default converter image

maybe @Koenkk can help out on this, I believe some debug logging of the device could be helpful ?

Koenkk commented 1 year ago

@dokkomp this is a completely different device, please fill in the "New device support request" https://github.com/Koenkk/zigbee2mqtt/issues/new/choose

tparvais commented 1 year ago

Hi, is this pc321 suppose to work well in both direction I’d used to monitor house energy having solar panel ? (We can inject energy to grid , and the opposite when no sun)

I think it’s not ok in energy Dashboard home assistant