diff --git a/Makefile b/Makefile index f06b247..fdaf0cc 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ METER_OBJS:=\ $(BUILD)/meter_cma12w.o \ $(BUILD)/meter_q400.o \ $(BUILD)/meter_ehzp.o \ + $(BUILD)/meter_esyswm.o \ $(BUILD)/printer.o \ $(BUILD)/serial.o \ $(BUILD)/shell.o \ diff --git a/README.md b/README.md index 3108aab..b4eca0b 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,7 @@ Elvaco CMa12w Thermometer (cma12w) Supported electricity meters: Tauron Amiplus (amiplus) (includes vendor apator and echelon) EMH Metering (ehzp) +Easy Meter ESYS-WM20 (esyswm) Work in progress: Electricity meter Kamstrup Omnipower (omnipower) diff --git a/src/dvparser.cc b/src/dvparser.cc index 3027d90..73691b2 100644 --- a/src/dvparser.cc +++ b/src/dvparser.cc @@ -301,7 +301,7 @@ bool hasKey(std::map> *values, std::string ke return values->count(key) > 0; } -bool findKey(MeasurementType mit, ValueInformation vif, int storagenr, +bool findKey(MeasurementType mit, ValueInformation vif, int storagenr, int tariffnr, std::string *key, std::map> *values) { int low, hi; @@ -316,13 +316,15 @@ bool findKey(MeasurementType mit, ValueInformation vif, int storagenr, MeasurementType ty = v.second.second.type; int vi = v.second.second.value_information; int sn = v.second.second.storagenr; + int tn = v.second.second.tariff; debug("(dvparser) match? %s type=%s vif=%02x (%s) and storagenr=%d\n", v.first.c_str(), measurementTypeName(ty).c_str(), vi, toString(toValueInformation(vi)), storagenr, sn); if (vi >= low && vi <= hi && (mit == MeasurementType::Unknown || mit == ty) - && (storagenr == ANY_STORAGENR || storagenr == sn)) + && (storagenr == ANY_STORAGENR || storagenr == sn) + && (tariffnr == ANY_TARIFFNR || tariffnr == tn)) { *key = v.first; debug("(dvparser) found key %s for type=%s vif=%02x (%s) storagenr=%d\n", diff --git a/src/dvparser.h b/src/dvparser.h index 506dbbe..2ba06c0 100644 --- a/src/dvparser.h +++ b/src/dvparser.h @@ -64,8 +64,11 @@ bool parseDV(Telegram *t, // find an existing difvif entry in the values based on the desired value information type. // Like: Volume, VolumeFlow, FlowTemperature, ExternalTemperature etc // in combination with the storagenr. (Later I will add tariff/subunit) -bool findKey(MeasurementType mt, ValueInformation vi, int storagenr, std::string *key, std::map> *values); +bool findKey(MeasurementType mt, ValueInformation vi, int storagenr, int tariffnr, + std::string *key, std::map> *values); + #define ANY_STORAGENR -1 +#define ANY_TARIFFNR -1 bool hasKey(std::map> *values, std::string key); diff --git a/src/main.cc b/src/main.cc index e94f247..08e46a8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -302,7 +302,7 @@ LIST_OF_METERS t.parserNoWarnings(); // Try a best effort parse, do not print any warnings. t.parse(frame, &mk); t.print(); - t.explainParse("",0); + t.explainParse("(wmbus)",0); logTelegram("(wmbus)", t.frame, 0, 0); return true; }); diff --git a/src/meter_amiplus.cc b/src/meter_amiplus.cc index 1fba839..dcd880b 100644 --- a/src/meter_amiplus.cc +++ b/src/meter_amiplus.cc @@ -120,12 +120,12 @@ void MeterAmiplus::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_energy_kwh_); t->addMoreExplanation(offset, " total energy (%f kwh)", total_energy_kwh_); } - if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_power_kw_); t->addMoreExplanation(offset, " current power (%f kw)", current_power_kw_); } @@ -136,7 +136,7 @@ void MeterAmiplus::processContent(Telegram *t) extractDVdouble(&t->values, "0BAB3C", &offset, ¤t_power_returned_kw_); t->addMoreExplanation(offset, " current power returned (%f kw)", current_power_returned_kw_); - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); device_date_time_ = strdatetime(&datetime); diff --git a/src/meter_apator162.cc b/src/meter_apator162.cc index d6ee1d4..58f61e7 100644 --- a/src/meter_apator162.cc +++ b/src/meter_apator162.cc @@ -118,7 +118,7 @@ void MeterApator162::processContent(Telegram *t) vendor_values["0413"] = { 25, DVEntry(MeasurementType::Instantaneous, 0x13, 0, 0, 0, total) }; int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &vendor_values)) + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &vendor_values)) { extractDVdouble(&vendor_values, key, &offset, &total_water_consumption_m3_); //Adding explanation have to wait since it assumes that the dvparser could do something, but it could not here. diff --git a/src/meter_cma12w.cc b/src/meter_cma12w.cc index 00aa771..db02209 100644 --- a/src/meter_cma12w.cc +++ b/src/meter_cma12w.cc @@ -99,13 +99,13 @@ void MeterCMa12w::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 0, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_temperature_c_); t->addMoreExplanation(offset, " current temperature (%f C)", current_temperature_c_); } - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &average_temperature_1h_c_); t->addMoreExplanation(offset, " average temperature 1h (%f C))", average_temperature_1h_c_); diff --git a/src/meter_ehzp.cc b/src/meter_ehzp.cc index 90dfa68..d929c33 100644 --- a/src/meter_ehzp.cc +++ b/src/meter_ehzp.cc @@ -22,7 +22,8 @@ #include"wmbus_utils.h" #include"util.h" -struct MeterEHZP : public virtual ElectricityMeter, public virtual MeterCommonImplementation { +struct MeterEHZP : public virtual ElectricityMeter, public virtual MeterCommonImplementation +{ MeterEHZP(WMBus *bus, MeterInfo &mi); double totalEnergyConsumption(Unit u); @@ -44,18 +45,10 @@ private: MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) : MeterCommonImplementation(bus, mi, MeterType::EHZP, MANUFACTURER_EMH) { - setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV); + setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV); - // This is one manufacturer of EHZP compatible meters. - addManufacturer(MANUFACTURER_APA); addMedia(0x02); // Electricity meter - // This is another manufacturer - addManufacturer(MANUFACTURER_DEV); - // Oddly, this device has not been configured to send as a electricity meter, - // but instead a device/media type that is used for gateway or relays or something? - addMedia(0x37); // Radio converter (meter side) - addLinkMode(LinkMode::T1); setExpectedVersion(0x02); @@ -113,16 +106,31 @@ double MeterEHZP::currentPowerProduction(Unit u) void MeterEHZP::processContent(Telegram *t) { + /* + (ehzp) 26: 07 dif (64 Bit Integer/Binary Instantaneous value) + (ehzp) 27: 00 vif (Energy mWh) + (ehzp) 28: * 583B740200000000 total energy (41.171800 kwh) + (ehzp) 30: 07 dif (64 Bit Integer/Binary Instantaneous value) + (ehzp) 31: 80 vif (Energy mWh) + (ehzp) 32: 3C vife (backward flow) + (ehzp) 33: * BCD7020000000000 total energy returned (0.186300 kwh) + (ehzp) 3b: 07 dif (64 Bit Integer/Binary Instantaneous value) + (ehzp) 3c: 28 vif (Power mW) + (ehzp) 3d: * B070200000000000 current power (2.126000 kw) + (ehzp) 45: 04 dif (32 Bit Integer/Binary Instantaneous value) + (ehzp) 46: 20 vif (On time seconds) + (ehzp) 47: * 92A40600 on time (120.929444 h) + */ int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_energy_kwh_); t->addMoreExplanation(offset, " total energy (%f kwh)", total_energy_kwh_); } - if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_power_kw_); t->addMoreExplanation(offset, " current power (%f kw)", current_power_kw_); diff --git a/src/meter_esyswm.cc b/src/meter_esyswm.cc new file mode 100644 index 0000000..292ec78 --- /dev/null +++ b/src/meter_esyswm.cc @@ -0,0 +1,249 @@ +/* + Copyright (C) 2020 Fredrik Öhrström + + 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"dvparser.h" +#include"meters.h" +#include"meters_common_implementation.h" +#include"wmbus.h" +#include"wmbus_utils.h" +#include"util.h" + +struct MeterESYSWM : public virtual ElectricityMeter, public virtual MeterCommonImplementation +{ + MeterESYSWM(WMBus *bus, MeterInfo &mi); + + double totalEnergyConsumption(Unit u); + double totalEnergyConsumptionTariff1(Unit u); + double totalEnergyConsumptionTariff2(Unit u); + double currentPowerConsumption(Unit u); + double currentPowerConsumptionPhase1(Unit u); + double currentPowerConsumptionPhase2(Unit u); + double currentPowerConsumptionPhase3(Unit u); + double totalEnergyProduction(Unit u); + double currentPowerProduction(Unit u); + +private: + + void processContent(Telegram *t); + + double total_energy_kwh_ {}; + double total_energy_tariff1_kwh_ {}; + double total_energy_tariff2_kwh_ {}; + double current_power_kw_ {}; + double current_power_phase1_kw_ {}; + double current_power_phase2_kw_ {}; + double current_power_phase3_kw_ {}; + double total_energy_returned_kwh_ {}; + double current_power_returned_kw_ {}; + string device_date_time_; +}; + +MeterESYSWM::MeterESYSWM(WMBus *bus, MeterInfo &mi) : + MeterCommonImplementation(bus, mi, MeterType::ESYSWM, 0) +{ + setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV); + + addManufacturer(MANUFACTURER_EMH); + + // The ESYS-WM-20 and ESYS-WM15 are addons to the electricity meters. + addMedia(0x37); // Radio converter (meter side) + + addLinkMode(LinkMode::T1); + + setExpectedVersion(0x30); + + addPrint("total_energy_consumption", Quantity::Energy, + [&](Unit u){ return totalEnergyConsumption(u); }, + "The total energy consumption recorded by this meter.", + true, true); + + addPrint("current_power_consumption", Quantity::Power, + [&](Unit u){ return currentPowerConsumption(u); }, + "Current power consumption.", + true, true); + + addPrint("total_energy_production", Quantity::Energy, + [&](Unit u){ return totalEnergyProduction(u); }, + "The total energy production recorded by this meter.", + true, true); + + addPrint("total_energy_consumption_tariff1", Quantity::Energy, + [&](Unit u){ return totalEnergyConsumptionTariff1(u); }, + "The total energy consumption recorded by this meter on tariff 1.", + false, true); + + addPrint("total_energy_consumption_tariff2", Quantity::Energy, + [&](Unit u){ return totalEnergyConsumptionTariff2(u); }, + "The total energy consumption recorded by this meter on tariff 2.", + false, true); + + addPrint("current_power_consumption_phase1", Quantity::Power, + [&](Unit u){ return currentPowerConsumptionPhase1(u); }, + "Current power consumption phase 1.", + false, true); + + addPrint("current_power_consumption_phase2", Quantity::Power, + [&](Unit u){ return currentPowerConsumptionPhase2(u); }, + "Current power consumption phase 2.", + false, true); + + addPrint("current_power_consumption_phase3", Quantity::Power, + [&](Unit u){ return currentPowerConsumptionPhase3(u); }, + "Current power consumption phase 3.", + false, true); + +} + +unique_ptr createESYSWM(WMBus *bus, MeterInfo &mi) +{ + return unique_ptr(new MeterESYSWM(bus, mi)); +} + +double MeterESYSWM::totalEnergyConsumption(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(total_energy_kwh_, Unit::KWH, u); +} + +double MeterESYSWM::totalEnergyConsumptionTariff1(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(total_energy_tariff1_kwh_, Unit::KWH, u); +} + +double MeterESYSWM::totalEnergyConsumptionTariff2(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(total_energy_tariff2_kwh_, Unit::KWH, u); +} + +double MeterESYSWM::currentPowerConsumption(Unit u) +{ + assertQuantity(u, Quantity::Power); + return convert(current_power_kw_, Unit::KW, u); +} + +double MeterESYSWM::currentPowerConsumptionPhase1(Unit u) +{ + assertQuantity(u, Quantity::Power); + return convert(current_power_phase1_kw_, Unit::KW, u); +} + +double MeterESYSWM::currentPowerConsumptionPhase2(Unit u) +{ + assertQuantity(u, Quantity::Power); + return convert(current_power_phase2_kw_, Unit::KW, u); +} + +double MeterESYSWM::currentPowerConsumptionPhase3(Unit u) +{ + assertQuantity(u, Quantity::Power); + return convert(current_power_phase3_kw_, Unit::KW, u); +} + +double MeterESYSWM::totalEnergyProduction(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(total_energy_returned_kwh_, Unit::KWH, u); +} + +double MeterESYSWM::currentPowerProduction(Unit u) +{ + assertQuantity(u, Quantity::Power); + return convert(current_power_returned_kw_, Unit::KW, u); +} + +void MeterESYSWM::processContent(Telegram *t) +{ + /* + (esyswm) 2e: 07 dif (64 Bit Integer/Binary Instantaneous value) + (esyswm) 2f: 02 vif (Energy 10⁻¹ Wh) + (esyswm) 30: * F5C3FA0000000000 total energy (1643.416500 kwh) + + (esyswm) 38: 07 dif (64 Bit Integer/Binary Instantaneous value) + (esyswm) 39: 82 vif (Energy 10⁻¹ Wh) + (esyswm) 3a: 3C vife (backward flow) + (esyswm) 3b: * 5407000000000000 total energy returned (0.187600 kwh) + + (esyswm) 43: 84 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 44: 10 dife (subunit=0 tariff=1 storagenr=0) + (esyswm) 45: 04 vif (Energy 10¹ Wh) + (esyswm) 46: * E0810200 total energy tariff 1 (1643.200000 kwh) + + (esyswm) 4a: 84 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 4b: 20 dife (subunit=0 tariff=2 storagenr=0) + (esyswm) 4c: 04 vif (Energy 10¹ Wh) + (esyswm) 4d: * 15000000 total energy tariff 2 (0.210000 kwh) + + (esyswm) 51: 04 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 52: 29 vif (Power 10⁻² W) + (esyswm) 53: * 38AB0000 current power (0.438320 kw) + + (esyswm) 57: 04 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 58: A9 vif (Power 10⁻² W) + (esyswm) 59: FF vife (additive correction constant: unit of VIF * 10^0) + (esyswm) 5a: 01 vife (?) + (esyswm) 5b: FA0A0000 + + (esyswm) 5f: 04 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 60: A9 vif (Power 10⁻² W) + (esyswm) 61: FF vife (additive correction constant: unit of VIF * 10^0) + (esyswm) 62: 02 vife (?) + (esyswm) 63: 050A0000 + + (esyswm) 67: 04 dif (32 Bit Integer/Binary Instantaneous value) + (esyswm) 68: A9 vif (Power 10⁻² W) + (esyswm) 69: FF vife (additive correction constant: unit of VIF * 10^0) + (esyswm) 6a: 03 vife (?) + (esyswm) 6b: 38960000 + */ + int offset; + string key; + + if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) { + extractDVdouble(&t->values, key, &offset, &total_energy_kwh_); + t->addMoreExplanation(offset, " total energy (%f kwh)", total_energy_kwh_); + } + + if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, 1, &key, &t->values)) { + extractDVdouble(&t->values, key, &offset, &total_energy_tariff1_kwh_); + t->addMoreExplanation(offset, " total energy tariff 1 (%f kwh)", total_energy_tariff1_kwh_); + } + + if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, 2, &key, &t->values)) { + extractDVdouble(&t->values, key, &offset, &total_energy_tariff2_kwh_); + t->addMoreExplanation(offset, " total energy tariff 2 (%f kwh)", total_energy_tariff2_kwh_); + } + + if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, 0, &key, &t->values)) { + extractDVdouble(&t->values, key, &offset, ¤t_power_kw_); + t->addMoreExplanation(offset, " current power (%f kw)", current_power_kw_); + } + + extractDVdouble(&t->values, "07823C", &offset, &total_energy_returned_kwh_); + t->addMoreExplanation(offset, " total energy returned (%f kwh)", total_energy_returned_kwh_); + + extractDVdouble(&t->values, "04A9FF01", &offset, ¤t_power_phase1_kw_); + t->addMoreExplanation(offset, " current power phase 1 (%f kwh)", current_power_phase1_kw_); + + extractDVdouble(&t->values, "04A9FF02", &offset, ¤t_power_phase1_kw_); + t->addMoreExplanation(offset, " current power phase 2 (%f kwh)", current_power_phase2_kw_); + + extractDVdouble(&t->values, "04A9FF03", &offset, ¤t_power_phase1_kw_); + t->addMoreExplanation(offset, " current power phase 3 (%f kwh)", current_power_phase3_kw_); + +} diff --git a/src/meter_eurisii.cc b/src/meter_eurisii.cc index 178bea0..161f2af 100644 --- a/src/meter_eurisii.cc +++ b/src/meter_eurisii.cc @@ -212,13 +212,13 @@ void MeterEurisII::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 0, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_consumption_hca_); t->addMoreExplanation(offset, " current consumption (%f hca)", current_consumption_hca_); } - if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, 0, &key, &t->values)) { struct tm date; extractDVdate(&t->values, key, &offset, &date); set_date_ = strdate(&date); @@ -227,7 +227,7 @@ void MeterEurisII::processContent(Telegram *t) for (int i=1; i<=17; ++i) { - if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, i, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, i, 0, &key, &t->values)) { string info; strprintf(info, " consumption at set date %d (%%f hca)", i); diff --git a/src/meter_hydrodigit.cc b/src/meter_hydrodigit.cc index 89bbfc2..bba1e69 100644 --- a/src/meter_hydrodigit.cc +++ b/src/meter_hydrodigit.cc @@ -68,12 +68,12 @@ void MeterHydrodigit::processContent(Telegram *t) int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); meter_datetime_ = strdatetime(&datetime); diff --git a/src/meter_hydrus.cc b/src/meter_hydrus.cc index b873af5..8cf94bf 100644 --- a/src/meter_hydrus.cc +++ b/src/meter_hydrus.cc @@ -134,27 +134,27 @@ void MeterHydrus::processContent(Telegram *t) int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &max_flow_m3h_); t->addMoreExplanation(offset, " max flow (%f m3/h)", max_flow_m3h_); } - if(findKey(MeasurementType::Unknown, ValueInformation::FlowTemperature, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::FlowTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &flow_temperature_c_); t->addMoreExplanation(offset, " flow temperature (%f °C)", flow_temperature_c_); } - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 3, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 3, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_at_date_m3_); t->addMoreExplanation(offset, " total consumption at date (%f m3)", total_water_consumption_at_date_m3_); } - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 3, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 3, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); at_date_ = strdatetime(&datetime); diff --git a/src/meter_iperl.cc b/src/meter_iperl.cc index 9a5a945..3ffb8a0 100644 --- a/src/meter_iperl.cc +++ b/src/meter_iperl.cc @@ -73,12 +73,12 @@ void MeterIperl::processContent(Telegram *t) int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, ANY_STORAGENR, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, ANY_STORAGENR, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &max_flow_m3h_); t->addMoreExplanation(offset, " max flow (%f m3/h)", max_flow_m3h_); } diff --git a/src/meter_lansenth.cc b/src/meter_lansenth.cc index b522fe3..e22c81a 100644 --- a/src/meter_lansenth.cc +++ b/src/meter_lansenth.cc @@ -131,19 +131,19 @@ void MeterLansenTH::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 0, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_temperature_c_); t->addMoreExplanation(offset, " current temperature (%f C)", current_temperature_c_); } - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &average_temperature_1h_c_); t->addMoreExplanation(offset, " average temperature 1h (%f C))", average_temperature_1h_c_); } - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 2, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 2, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &average_temperature_24h_c_); t->addMoreExplanation(offset, " average temperature 24h (%f C))", average_temperature_24h_c_); diff --git a/src/meter_multical21.cc b/src/meter_multical21.cc index b56e1ff..7569541 100644 --- a/src/meter_multical21.cc +++ b/src/meter_multical21.cc @@ -307,30 +307,30 @@ void MeterMultical21::processContent(Telegram *t) extractDVuint16(&t->values, "02FF20", &offset, &info_codes_); t->addMoreExplanation(offset, " info codes (%s)", statusHumanReadable().c_str()); - if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); has_total_water_consumption_ = true; t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 1, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &target_water_consumption_m3_); has_target_water_consumption_ = true; t->addMoreExplanation(offset, " target consumption (%f m3)", target_water_consumption_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, ANY_STORAGENR, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, ANY_STORAGENR, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &max_flow_m3h_); has_max_flow_ = true; t->addMoreExplanation(offset, " max flow (%f m3/h)", max_flow_m3h_); } - if(findKey(MeasurementType::Unknown, ValueInformation::FlowTemperature, ANY_STORAGENR, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::FlowTemperature, ANY_STORAGENR, 0, &key, &t->values)) { has_flow_temperature_ = extractDVdouble(&t->values, key, &offset, &flow_temperature_c_); t->addMoreExplanation(offset, " flow temperature (%f °C)", flow_temperature_c_); } - if(findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, ANY_STORAGENR, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, ANY_STORAGENR, 0, &key, &t->values)) { has_external_temperature_ = extractDVdouble(&t->values, key, &offset, &external_temperature_c_); t->addMoreExplanation(offset, " external temperature (%f °C)", external_temperature_c_); } diff --git a/src/meter_multical302.cc b/src/meter_multical302.cc index 4576a51..50c5d86 100644 --- a/src/meter_multical302.cc +++ b/src/meter_multical302.cc @@ -151,27 +151,27 @@ void MeterMultical302::processContent(Telegram *t) extractDVuint8(&t->values, "01FF21", &offset, &info_codes_); t->addMoreExplanation(offset, " info codes (%s)", status().c_str()); - if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 0, &key, &t->values)) { + if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_energy_kwh_); t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_energy_kwh_); } - if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_volume_m3_); t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); } - if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 1, &key, &t->values)) { + if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &target_energy_kwh_); t->addMoreExplanation(offset, " target energy consumption (%f kWh)", target_energy_kwh_); } - if(findKey(MeasurementType::Instantaneous, ValueInformation::PowerW, 0, &key, &t->values)) { + if(findKey(MeasurementType::Instantaneous, ValueInformation::PowerW, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_power_kw_); t->addMoreExplanation(offset, " current power consumption (%f kW)", current_power_kw_); } - if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); target_date_ = strdatetime(&datetime); diff --git a/src/meter_q400.cc b/src/meter_q400.cc index 8408661..9385495 100644 --- a/src/meter_q400.cc +++ b/src/meter_q400.cc @@ -100,17 +100,17 @@ void MeterQ400::processContent(Telegram *t) int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 1, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &consumption_at_set_date_m3_); t->addMoreExplanation(offset, " consumption at set date (%f m3)", consumption_at_set_date_m3_); } - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 1, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 1, 0, &key, &t->values)) { struct tm date; extractDVdate(&t->values, key, &offset, &date); set_date_ = strdate(&date); diff --git a/src/meter_qcaloric.cc b/src/meter_qcaloric.cc index 3d5a6c7..cc7ef78 100644 --- a/src/meter_qcaloric.cc +++ b/src/meter_qcaloric.cc @@ -169,29 +169,29 @@ void MeterQCaloric::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_consumption_hca_); t->addMoreExplanation(offset, " current consumption (%f hca)", current_consumption_hca_); } - if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::Date, 1, 0, &key, &t->values)) { struct tm date; extractDVdate(&t->values, key, &offset, &date); set_date_ = strdate(&date); t->addMoreExplanation(offset, " set date (%s)", set_date_.c_str()); } - if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 1, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &consumption_at_set_date_hca_); t->addMoreExplanation(offset, " consumption at set date (%f hca)", consumption_at_set_date_hca_); } - if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 17, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::HeatCostAllocation, 17, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &consumption_at_set_date_17_hca_); t->addMoreExplanation(offset, " consumption at set date 17 (%f hca)", consumption_at_set_date_17_hca_); } - if (findKey(MeasurementType::Unknown, ValueInformation::Date, 17, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::Date, 17, 0, &key, &t->values)) { struct tm date; extractDVdate(&t->values, key, &offset, &date); set_date_17_ = strdate(&date); @@ -206,7 +206,7 @@ void MeterQCaloric::processContent(Telegram *t) t->addMoreExplanation(offset, " error date (%s)", error_date_.c_str()); } - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); device_date_time_ = strdatetime(&datetime); diff --git a/src/meter_rfmamb.cc b/src/meter_rfmamb.cc index 3346e40..bdb8524 100644 --- a/src/meter_rfmamb.cc +++ b/src/meter_rfmamb.cc @@ -266,45 +266,45 @@ void MeterRfmAmb::processContent(Telegram *t) int offset; string key; - if (findKey(MeasurementType::Instantaneous, ValueInformation::ExternalTemperature, 0, &key, &t->values)) + if (findKey(MeasurementType::Instantaneous, ValueInformation::ExternalTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, ¤t_temperature_c_); t->addMoreExplanation(offset, " current temperature (%f C)", current_temperature_c_); } - if (findKey(MeasurementType::Maximum, ValueInformation::ExternalTemperature, 0, &key, &t->values)) + if (findKey(MeasurementType::Maximum, ValueInformation::ExternalTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &maximum_temperature_1h_c_); t->addMoreExplanation(offset, " maximum temperature 1h (%f C)", maximum_temperature_1h_c_); } - if (findKey(MeasurementType::Minimum, ValueInformation::ExternalTemperature, 0, &key, &t->values)) + if (findKey(MeasurementType::Minimum, ValueInformation::ExternalTemperature, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &minimum_temperature_1h_c_); t->addMoreExplanation(offset, " minimum temperature 1h (%f C)", minimum_temperature_1h_c_); } - if (findKey(MeasurementType::Maximum, ValueInformation::ExternalTemperature, 1, &key, &t->values)) + if (findKey(MeasurementType::Maximum, ValueInformation::ExternalTemperature, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &maximum_temperature_24h_c_); t->addMoreExplanation(offset, " maximum temperature 24h (%f C)", maximum_temperature_24h_c_); } - if (findKey(MeasurementType::Minimum, ValueInformation::ExternalTemperature, 1, &key, &t->values)) + if (findKey(MeasurementType::Minimum, ValueInformation::ExternalTemperature, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &minimum_temperature_24h_c_); t->addMoreExplanation(offset, " minimum temperature 24h (%f C)", minimum_temperature_24h_c_); } - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 1, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &average_temperature_1h_c_); t->addMoreExplanation(offset, " average temperature 1h (%f C)", average_temperature_1h_c_); } - if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 2, &key, &t->values)) + if (findKey(MeasurementType::Unknown, ValueInformation::ExternalTemperature, 2, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &average_temperature_24h_c_); t->addMoreExplanation(offset, " average temperature 24h (%f C)", average_temperature_24h_c_); @@ -369,7 +369,7 @@ void MeterRfmAmb::processContent(Telegram *t) t->addMoreExplanation(offset, " relative humidity 24h (%f RH)", average_relative_humidity_24h_rh_); } - if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, &key, &t->values)) { + if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, 0, &key, &t->values)) { struct tm datetime; extractDVdate(&t->values, key, &offset, &datetime); device_date_time_ = strdatetime(&datetime); diff --git a/src/meter_supercom587.cc b/src/meter_supercom587.cc index 6d73cb3..0f8457e 100644 --- a/src/meter_supercom587.cc +++ b/src/meter_supercom587.cc @@ -66,7 +66,7 @@ void MeterSupercom587::processContent(Telegram *t) int offset; string key; - if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, &key, &t->values)) { + if(findKey(MeasurementType::Unknown, ValueInformation::Volume, 0, 0, &key, &t->values)) { extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_); t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_); } diff --git a/src/meters.h b/src/meters.h index aa775b1..682e54a 100644 --- a/src/meters.h +++ b/src/meters.h @@ -30,7 +30,8 @@ X(apator162, C1_bit|T1_bit, Water, APATOR162, Apator162) \ X(cma12w, C1_bit|T1_bit, TempHygro, CMA12W, CMa12w) \ X(eurisii, T1_bit, HeatCostAllocation, EURISII, EurisII) \ - X(ehzp, T1_bit, Water, EHZP, EHZP) \ + X(ehzp, T1_bit, Electricity, EHZP, EHZP) \ + X(esyswm, T1_bit, Electricity, ESYSWM, ESYSWM) \ X(flowiq3100, C1_bit, Water, FLOWIQ3100, Multical21) \ X(hydrus, T1_bit, Water, HYDRUS, Hydrus) \ X(hydrodigit, T1_bit, Water, HYDRODIGIT, Hydrodigit) \ @@ -208,6 +209,7 @@ unique_ptr createLansenTH(WMBus *bus, MeterInfo &m); unique_ptr createCMa12w(WMBus *bus, MeterInfo &m); unique_ptr createRfmAmb(WMBus *bus, MeterInfo &m); unique_ptr createEHZP(WMBus *bus, MeterInfo &m); +unique_ptr createESYSWM(WMBus *bus, MeterInfo &m); GenericMeter *createGeneric(WMBus *bus, MeterInfo &m); #endif diff --git a/src/wmbus.cc b/src/wmbus.cc index 64a340c..398edc4 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -1305,7 +1305,15 @@ bool Telegram::parseTPLConfig(std::vector::iterator &pos) // If there is a tpl_counter, then use it, else use afl_counter. input.insert(input.end(), afl_counter_b, afl_counter_b+4); // If there is a tpl_id, then use it, else use ddl_id. - input.insert(input.end(), dll_id_b, dll_id_b+4); + if (tpl_id_found) + { + input.insert(input.end(), tpl_id_b, tpl_id_b+4); + } + else + { + input.insert(input.end(), dll_id_b, dll_id_b+4); + } + // Pad. for (int i=0; i<7; ++i) input.insert(input.end(), 0x07); @@ -1342,6 +1350,7 @@ bool Telegram::parseShortTPL(std::vector::iterator &pos) bool Telegram::parseLongTPL(std::vector::iterator &pos) { + tpl_id_found = true; tpl_id_b[0] = *(pos+0); tpl_id_b[1] = *(pos+1); tpl_id_b[2] = *(pos+2); @@ -1518,6 +1527,7 @@ bool Telegram::parseTPL(vector::iterator &pos) bool Telegram::parseHeader(vector &input_frame) { bool ok; + explanations.clear(); frame = input_frame; vector::iterator pos = frame.begin(); // Parsed accumulates parsed bytes. @@ -1537,6 +1547,7 @@ bool Telegram::parseHeader(vector &input_frame) bool Telegram::parse(vector &input_frame, MeterKeys *mk) { + explanations.clear(); meter_keys = mk; assert(meter_keys != NULL); bool ok; @@ -1682,7 +1693,6 @@ bool Telegram::parse(vector &input_frame, MeterKeys *mk) void Telegram::explainParse(string intro, int from) { for (auto& p : explanations) { - if (p.first < from) continue; debug("%s %02x: %s\n", intro.c_str(), p.first, p.second.c_str()); } string hex = bin2hex(parsed); diff --git a/src/wmbus.h b/src/wmbus.h index 2ae0901..778eb1d 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -283,6 +283,7 @@ struct Telegram int tpl_kdf_selection {}; // 1 byte vector tpl_generated_key; // 16 bytes + bool tpl_id_found {}; // If set to true, then tpl_id_b contains valid values. uchar tpl_id_b[4]; // 4 bytes uchar tpl_mft_b[2]; // 2 bytes uchar tpl_version; // 1 bytes