/* Copyright (C) 2023 Fredrik Öhrström (gpl-3.0-or-later) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include"meters_common_implementation.h" namespace { struct Driver : public virtual MeterCommonImplementation { Driver(MeterInfo &mi, DriverInfo &di); }; static bool ok = registerDriver([](DriverInfo&di) { di.setName("nemo"); di.setDefaultFields( "name,id,status," "total_active_positive_3phase_kwh," "active_positive_3phase_kw," "timestamp"); di.setMeterType(MeterType::ElectricityMeter); di.addLinkMode(LinkMode::MBUS); di.addDetection(MANUFACTURER_IME, 0x02, 0x1d); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); // Telegram 1 ///////////////////////////////////////////////////////////////////// Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) { addNumericFieldWithExtractor( "total_active_positive_3phase", "Et+ the total 3-phase active positive energy.", DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) .set(StorageNr(0)) .set(TariffNr(1)) .set(SubUnitNr(1)) ); addNumericFieldWithExtractor( "active_positive_3phase", "P+ the 3-phase active positive power.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(StorageNr(0)) .set(TariffNr(1)) .set(SubUnitNr(1)) ); addNumericFieldWithExtractor( "total_reactive_positive_3phase", "Er+ the total 3-phase reactive positive energy.", DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) .set(StorageNr(0)) .set(TariffNr(1)) .set(SubUnitNr(2)) ); addNumericFieldWithExtractor( "reactive_positive_3phase", "Q+ the 3-phase reactive positive power.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(StorageNr(0)) .set(TariffNr(1)) .set(SubUnitNr(2)) ); addNumericFieldWithExtractor( "total_active_partial_3phase", "Part Et+ the total 3-phase active partial energy.", DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) .set(StorageNr(0)) .set(TariffNr(2)) .set(SubUnitNr(1)) ); addNumericFieldWithExtractor( "active_negative_3phase", "P- the 3-phase active negative power.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(StorageNr(0)) .set(TariffNr(2)) .set(SubUnitNr(1)) ); addNumericFieldWithExtractor( "total_reactive_partial_3phase", "Part Er+ the total 3-phase reactive partial energy.", DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) .set(StorageNr(0)) .set(TariffNr(2)) .set(SubUnitNr(2)) ); addNumericFieldWithExtractor( "reactive_negative_3phase", "Q- the 3-phase reactive negative power.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(StorageNr(0)) .set(TariffNr(2)) .set(SubUnitNr(2)) ); addNumericFieldWithExtractor( "power", "PF the power factor.", DEFAULT_PRINT_PROPERTIES, Quantity::Dimensionless, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Dimensionless), Unit::FACTOR ); addStringFieldWithExtractorAndLookup( "status", "Status. OK if no error flags are set.", PrintProperty::STATUS | PrintProperty::INCLUDE_TPL_STATUS, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::ErrorFlags), Translate::Lookup() .add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString) .set(MaskBits(0xff)) .set(DefaultMessage("OK")) )); // Telegram 2 ///////////////////////////////////////////////////////////// addNumericFieldWithExtractor( "current_at_phase_1", "I1 Amperage for L1 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Amperage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Amperage) .add(VIFCombinable::Mfct01) ); addNumericFieldWithExtractor( "current_at_phase_2", "I2 Amperage for L2 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Amperage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Amperage) .add(VIFCombinable::Mfct02) ); addNumericFieldWithExtractor( "current_at_phase_3", "I3 Amperage for L3 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Amperage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Amperage) .add(VIFCombinable::Mfct03) ); addNumericFieldWithExtractor( "voltage_at_phase_1", "L1-N Voltage for L1 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct01) ); addNumericFieldWithExtractor( "voltage_at_phase_2", "L2-N Voltagefor L2 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct02) ); addNumericFieldWithExtractor( "voltage_at_phase_3", "L3-N Voltage for L3 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct03) ); // Telegram 3 ///////////////////////////////////////////////////////////// addNumericFieldWithExtractor( "active_power_at_phase_1", "P1 Power for L1 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(1)) .add(VIFCombinable::Mfct01) ); addNumericFieldWithExtractor( "active_power_at_phase_2", "P2 Power for L2 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(1)) .add(VIFCombinable::Mfct02) ); addNumericFieldWithExtractor( "active_power_at_phase_3", "P3 Power for L3 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(1)) .add(VIFCombinable::Mfct03) ); addNumericFieldWithExtractor( "reactive_power_at_phase_1", "Q1 Power for L1 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(2)) .add(VIFCombinable::Mfct01) ); addNumericFieldWithExtractor( "reactive_power_at_phase_2", "Q2 Power for L2 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(2)) .add(VIFCombinable::Mfct02) ); addNumericFieldWithExtractor( "reactive_power_at_phase_3", "Q3 Power for L3 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyPowerVIF) .set(SubUnitNr(2)) .add(VIFCombinable::Mfct03) ); addNumericFieldWithExtractor( "at_phase_1_power", "PF1 the power factor for L1 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Dimensionless, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Dimensionless) .add(VIFCombinable::Mfct01), Unit::FACTOR ); addNumericFieldWithExtractor( "at_phase_2_power", "PF2 the power factor for L2 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Dimensionless, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Dimensionless) .add(VIFCombinable::Mfct02), Unit::FACTOR ); addNumericFieldWithExtractor( "at_phase_3_power", "PF3 the power factor for L3 phase.", DEFAULT_PRINT_PROPERTIES, Quantity::Dimensionless, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Dimensionless) .add(VIFCombinable::Mfct03), Unit::FACTOR ); addNumericFieldWithExtractor( "voltage_l1_l2", "L1-L2 Voltage between phases.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct04) ); addNumericFieldWithExtractor( "voltage_l2_l3", "L2-L3 Voltage between phases.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct05) ); addNumericFieldWithExtractor( "voltage_l3_l1", "L3-L1 Voltage between phases.", DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Voltage) .add(VIFCombinable::Mfct06) ); addNumericFieldWithExtractor( "current_in_neutral", "I Neutral amperage.", DEFAULT_PRINT_PROPERTIES, Quantity::Amperage, VifScaling::Auto, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Amperage) .add(VIFCombinable::Mfct04) ); addNumericFieldWithExtractor( "raw_frequency", "Frequency in 0.1 Hz", DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE, Quantity::Frequency, VifScaling::None, FieldMatcher::build() .set(DifVifKey("05FF5A")) ); addNumericFieldWithCalculator( "frequency", "Frequency of AC.", DEFAULT_PRINT_PROPERTIES, Quantity::Frequency, "raw_frequency_hz / 10 counter"); } } // Test: Elen nemo 00067609 NOKEY // comment: Telegram 1 // telegram=|6864646808657209760600A5251D02000000008E500400355873060085502B0013BF478E9040040029452501008590402B00F800468E600400000000000085602B000000008EA0400400890000000085A0402B0000000005FD3ADCF97E3F01FD17001F00000000009116| // {"media":"electricity", "meter":"nemo", "name":"Elen", "id":"00067609", "total_active_positive_3phase_kwh":6735835, "active_positive_3phase_kw":97.83, "total_reactive_positive_3phase_kwh":1254529, "reactive_positive_3phase_kw":8.254, "total_active_partial_3phase_kwh":0, "active_negative_3phase_kw":0, "total_reactive_partial_3phase_kwh":89, "reactive_negative_3phase_kw":0, "power_factor":-0.996, "status":"OK", "frequency_hz":null, "timestamp":"1111-11-11T11:11:11Z"} // |Elen;00067609;OK;6735835;97.83;1111-11-11 11:11.11 // comment: Telegram 2 // telegram=|684B4B6808657209760600A5251D020100000005FDD9FF0100F4174805FDD9FF0200B8084805FDD9FF0300B0014805FDC8FF0100C0104505FDC8FF020040114505FDC8FF03005011451F00000000000716| // {"media":"electricity", "meter":"nemo", "name":"Elen", "id":"00067609", "total_active_positive_3phase_kwh":6735835, "active_positive_3phase_kw":97.83, "total_reactive_positive_3phase_kwh":1254529, "reactive_positive_3phase_kw":8.254, "total_active_partial_3phase_kwh":0, "active_negative_3phase_kw":0, "total_reactive_partial_3phase_kwh":89, "reactive_negative_3phase_kw":0, "power_factor":-0.996, "status":"OK", "current_at_phase_1_a":155.6, "current_at_phase_2_a":140, "current_at_phase_3_a":132.8, "voltage_at_phase_1_v":231.6, "voltage_at_phase_2_v":232.4, "voltage_at_phase_3_v":232.5, "frequency_hz":null, "timestamp":"1111-11-11T11:11:11Z"} // |Elen;00067609;OK;6735835;97.83;1111-11-11 11:11.11 // comment: Telegram 3 // telegram=|689E9E6808657209760600A5251D02020000008540ABFF0100360B478540ABFF02002CFA468540ABFF030074ED46858040ABFF0100C0E244858040ABFF0200405A45858040ABFF030060364505FDBAFF0178BE7F3F05FDBAFF0240357E3F05FDBAFF0353B87E3F05FDC8FF0400907A4505FDC8FF0500707B4505FDC8FF0600807B4505FDD9FF0400502A4705FF5A0000FA4302FD3AC80002FD3A0A000F00000000008B16| // {"media":"electricity", "meter":"nemo", "name":"Elen", "id":"00067609", "total_active_positive_3phase_kwh":6735835, "active_positive_3phase_kw":97.83, "total_reactive_positive_3phase_kwh":1254529, "reactive_positive_3phase_kw":8.254, "total_active_partial_3phase_kwh":0, "active_negative_3phase_kw":0, "total_reactive_partial_3phase_kwh":89, "reactive_negative_3phase_kw":0, "power_factor":-200, "status":"OK", "current_at_phase_1_a":155.6, "current_at_phase_2_a":140, "current_at_phase_3_a":132.8, "voltage_at_phase_1_v":231.6, "voltage_at_phase_2_v":232.4, "voltage_at_phase_3_v":232.5, "active_power_at_phase_1_kw":35.638, "active_power_at_phase_2_kw":32.022, "active_power_at_phase_3_kw":30.394, "reactive_power_at_phase_1_kw":1.814, "reactive_power_at_phase_2_kw":3.492, "reactive_power_at_phase_3_kw":2.918, "at_phase_1_power_factor":-0.999, "at_phase_2_power_factor":-0.993, "at_phase_3_power_factor":-0.995, "voltage_l1_l2_v":400.9, "voltage_l2_l3_v":402.3, "voltage_l3_l1_v":402.4, "current_in_neutral_a":43.6, "frequency_hz":50, "timestamp":"1111-11-11T11:11:11Z"} // |Elen;00067609;OK;6735835;97.83;1111-11-11 11:11.11