diff --git a/CHANGES b/CHANGES index 48884ba..837c25f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,35 @@ + ╭─────────────────────────────────────────────────────────────────╮ + │ │ + │ Important change! The old style │ + │ of writing drivers is now gone! BUT BUT BUT │ + │ the final set of drivers to be converted were │ + │ the multical 302/303/403/602/603/803 meters that │ + │ were merged into a single hamheat driver. It was not │ + │ possible to keep all of them backwards compatible! │ + │ │ + │ Note that the default fields for these meters are changed! │ + │ Please use --selectfields to resolve this. │ + │ │ + │ I.e. It is a very good idea to check your multical heat │ + │ meter values when you upgrade to wmbusmeters 2.0 ! │ + │ │ + ╰─────────────────────────────────────────────────────────────────╯ + Important change! The feature --addconversions=GJ has been removed!!! But there is a replacement! It was used to add conversions to all energy values into gj, eg you have total_kwh and add total_gj. -This feature was too broad and the conversion happened too late in the processing code. -You can now achieved the same thing but you have to specify each field you want to convert +The addconversion feature was too broad and the conversion happened too late in the processing code. +You can now achieve the same thing but you have to specify each field you want to convert using the calculation feature. E.g. --calculate_total_gj=total_kwh +ATTENTION! The multical 302/303/403/602/603/803 heat meter drivers have been merged into a single kamheat +driver. Not all values are backwards compatible! I.e. 302 is very changed, less so for the others. +The default fields have changed! + ATTENTION! The gransystems driver has been refactored to the new driver format. The field currrent_at_phase_1_a has been renamed to current_at_phase_1_a. The info strings in the "status" field now have underscores instead of spaces within a single string. diff --git a/simulations/simulation_bad_keys.txt b/simulations/simulation_bad_keys.txt index 9413838..466ac74 100644 --- a/simulations/simulation_bad_keys.txt +++ b/simulations/simulation_bad_keys.txt @@ -1,8 +1,4 @@ -telegram=||33446850165706039480A20F9E28F2003018370011EA07D5070018001800160900000000000000000000000009190A22322C1215| telegram=||294468501657060394087A4C001025A11E4EFF816C2F8D147ED0C1F959F55E0F0FF724805FCC33D19A19| -telegram=||33446850165706039480A20F9E28F2003018370011EA07D5070018001800160900000000000000000000000009190A22322C1215| telegram=||294468501657060394087A4C001025A11E4EFF816C2F8D147ED0C1F959F55E0F0FF724805FCC33D19A19| -telegram=||33446850165706039480A20F9E28F2003018370011EA07D5070018001800160900000000000000000000000009190A22322C1215| telegram=||294468501657060394087A4C001025A11E4EFF816C2F8D147ED0C1F959F55E0F0FF724805FCC33D19A19| -telegram=||33446850165706039480A20F9E28F2003018370011EA07D5070018001800160900000000000000000000000009190A22322C1215| telegram=||294468501657060394087A4C001025A11E4EFF816C2F8D147ED0C1F959F55E0F0FF724805FCC33D19A19| diff --git a/simulations/simulation_c1.txt b/simulations/simulation_c1.txt index 0632e50..9e557b6 100644 --- a/simulations/simulation_c1.txt +++ b/simulations/simulation_c1.txt @@ -19,24 +19,6 @@ telegram=|21442D2C776655441B168D2079CC8C3A20_F4307912C40DFF00002F4E00003D010203| telegram=|4D44372C525252523A168D203894DF7920F93278_04FF23000000000413AEAC0000441364A80000426C812A023B000092013BEF01A2013B000006FF1B067000097000A1015B0C91015B14A1016713| {"media":"cold water","meter":"flowiq2200","name":"MyWater","id":"52525252","status":"OK","total_m3":44.206,"target_m3":43.108,"target_date":"2020-10-01","flow_m3h":0,"min_flow_temperature_c":12,"max_flow_temperature_c":20,"min_external_temperature_c":19,"max_flow_m3h":0.495,"min_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"} -# Test Multical302 C1 telegrams - -# full telegram -telegram=|2E442D2C6767676730048D2039D1684020_BCDB7803062C000043060000000314630000426C7F2A022D130001FF2100| -{"media":"heat","meter":"multical302","name":"MyHeater","id":"67676767","total_energy_consumption_kwh":44,"current_power_consumption_kw":1.9,"total_volume_m3":0.99,"at_date":"2019-10-31 00:00","total_energy_consumption_at_date_kwh":0,"current_status":"","timestamp":"1111-11-11T11:11:11Z"} - -# compressed telegram -telegram=|25442D2C6767676730048D203AD2684020_D81579E7F1D5902C00000000006300007F2A130000| -{"media":"heat","meter":"multical302","name":"MyHeater","id":"67676767","total_energy_consumption_kwh":44,"current_power_consumption_kw":1.9,"total_volume_m3":0.99,"at_date":"2019-10-31 00:00","total_energy_consumption_at_date_kwh":0,"current_status":"","timestamp":"1111-11-11T11:11:11Z"} - -# Mj full telegram -telegram=|2E442D2C46464646300C8D207A70EA6021B1C178_030FC51000430F9210000314072B05426CBE2B022D0C0001FF2100| -{"media":"heat volume at inlet","meter":"multical302","name":"MyHeaterMj","id":"46464646","total_energy_consumption_kwh":11925,"current_power_consumption_kw":1.2,"total_volume_m3":3386.95,"at_date":"2021-11-30 00:00","total_energy_consumption_at_date_kwh":11783.333333,"current_status":"","timestamp":"1111-11-11T11:11:11Z"} - -# Mj compressed telegram -telegram=|25442D2C46464646300C8D20D3E2EB60212B6D79E26DCD65_C51000921000152B05BE2B0C0000| -{"media":"heat volume at inlet","meter":"multical302","name":"MyHeaterMj","id":"46464646","total_energy_consumption_kwh":11925,"current_power_consumption_kw":1.2,"total_volume_m3":3387.09,"at_date":"2021-11-30 00:00","total_energy_consumption_at_date_kwh":11783.333333,"current_status":"","timestamp":"1111-11-11T11:11:11Z"} - # Test QCaloric C1 telegrams telegram=|314493441234567835087a740000200b6e2701004b6e450100426c5f2ccb086e790000c2086c7f21326cffff046d200b7422| @@ -54,34 +36,6 @@ telegram=|314493449392919034087a520000200b6e9700004b6e700200426c9f2ccb086e970000 telegram=|2744961566666666201B7AF9000020_2F2F02651E094265180902FD1B30030DFD0F05302E302E340F| {"media":"room sensor","meter":"cma12w","name":"Rum","id":"66666666","software_version":"4.0.0","status":"OK","current_temperature_c":23.34,"average_temperature_1h_c":23.28,"battery":"BATTERY_330","timestamp":"1111-11-11T11:11:11Z"} -# Test Multical403 C1 telegrams, with cooling configuration - -# full telegram -telegram=|88442D2C02017878340A8D208D529C132037FC78_040E2D0A000004FF07F8FF000004FF08401801000413C1900500844014000000008480401400000000043BED0000000259BC06025DCD07142DE7FFFFFF84100E0000000084200E0000000004FF2200000000026C9228440E5F0300004413960D0200C4401400000000C480401400000000426C8128| -{"media":"cooling load volume at outlet","meter":"multical403","name":"My403Cooling","id":"78780102","total_energy_consumption_kwh":723.611111,"total_volume_m3":364.737,"volume_flow_m3h":0.237,"t1_temperature_c":17.24,"t2_temperature_c":19.97,"at_date":"2020-08-18 00:00","current_status":"","timestamp":"1111-11-11T11:11:11Z"} -# compressed telegram -telegram=|5B442D2C02017878340A8D2096809C1320EF2B7934147ED7_2D0A0000FAFF000043180100CE9005000000000000000000EE000000BA06CB07E7FFFFFF00000000000000000000000092285F030000960D020000000000000000008128| -{"media":"cooling load volume at outlet","meter":"multical403","name":"My403Cooling","id":"78780102","total_energy_consumption_kwh":723.611111,"total_volume_m3":364.75,"volume_flow_m3h":0.238,"t1_temperature_c":17.22,"t2_temperature_c":19.95,"at_date":"2020-08-18 00:00","current_status":"","timestamp":"1111-11-11T11:11:11Z"} - -# Test Multical602 C1 telegram full - -telegram=|7A442D2C012815781C048D206450E76322344678_02F9FF1511130406690B010004EEFF07C1BC020004EEFF0890D401000414A925040084401400000000848040140000000002FD170000026CB929426CBF284406100A01004414D81A0400C4401400000000C480401400000000043B3900000002592A17025D2912| -{"media":"heat","meter":"multical602","name":"Heato","id":"78152801","total_energy_consumption_kwh":68457,"total_volume_m3":2717.85,"volume_flow_m3h":0.057,"t1_temperature_c":59.3,"t2_temperature_c":46.49,"at_date":"2021-09-25 00:00","current_status":"","energy_forward_kwh":0,"energy_returned_kwh":0,"timestamp":"1111-11-11T11:11:11Z"} - -# Test Multical602 C1 telegram compressed - -telegram=|4F442D2C012815781C048D206551E76322BE767900843005_1113690B0100C1BC020090D40100A925040000000000000000000000B929BF28100A0100D81A04000000000000000000390000002A172912| -{"media":"heat","meter":"multical602","name":"Heato","id":"78152801","total_energy_consumption_kwh":68457,"total_volume_m3":2717.85,"volume_flow_m3h":0.057,"t1_temperature_c":59.3,"t2_temperature_c":46.49,"at_date":"2021-09-25 00:00","current_status":"","energy_forward_kwh":0,"energy_returned_kwh":0,"timestamp":"1111-11-11T11:11:11Z"} - -# Test Multical603 C1 telegram - -telegram=|42442D2C3636363635048D20E18025B62087D078_0406A500000004FF072B01000004FF089C000000041421020000043B120000000259D014025D000904FF2200000000| -{"media":"heat","meter":"multical603","name":"Heat","id":"36363636","status":"OK","total_energy_consumption_kwh":165,"total_volume_m3":5.45,"volume_flow_m3h":0.018,"t1_temperature_c":53.28,"t2_temperature_c":23.04,"current_status":"","forward_energy_m3c":299,"return_energy_m3c":156,"energy_forward_kwh":299,"energy_returned_kwh":156,"timestamp":"1111-11-11T11:11:11Z"} - -# Test Multical803 C1 telegram -telegram=|88442D2C8180808039048D208640513220EA7978_040FA000000004FF070200000004FF08090000000414FF000000844014000000008480401400000000043B0000000002590000025D0000142D0000000084100F0000000084200F0000000004FF2260000100026C892B440F00000000441400000000C4401400000000C480401400000000426C812B| -{"media":"heat","meter":"multical803","name":"Heater","id":"80808081","total_energy_consumption_kwh":444.444444,"total_volume_m3":2.55,"volume_flow_m3h":0,"t1_temperature_c":0,"t2_temperature_c":0,"at_date":"2020-11-09 00:00","current_status":"SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE","energy_forward_kwh":0.555556,"energy_returned_kwh":2.5,"timestamp":"1111-11-11T11:11:11Z"} - # Test Kamstrup OmniPower C1 tlg # Full tlg telegram=|2D442D2C5768663230028D20E4E2C81C20878C78_04041A03000004843C00000000042B0300000004AB3C00000000| diff --git a/simulations/simulation_oneshot.txt b/simulations/simulation_oneshot.txt new file mode 100644 index 0000000..22bdf3d --- /dev/null +++ b/simulations/simulation_oneshot.txt @@ -0,0 +1,2 @@ +telegram=|2A442D2C998734761B168D2091D37CAC21576C78_02FF207100041308190000441308190000615B7F616713| +telegram=|2E442D2C6767676730048D2039D1684020_BCDB7803062C000043060000000314630000426C7F2A022D130001FF2100| diff --git a/src/cmdline.cc b/src/cmdline.cc index 93e2b99..bbd3919 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -152,8 +152,7 @@ static shared_ptr parseNormalCommandLine(Configuration *c, int ar MeterInfo mi; mi.parse("x", s, "00000000", ""); - if (mi.driver == MeterDriver::UNKNOWN && - mi.driver_name.str() == "") + if (mi.driver_name.str() == "") { error("Not a valid meter driver \"%s\"\n", s.c_str()); } @@ -634,14 +633,14 @@ static shared_ptr parseNormalCommandLine(Configuration *c, int ar mi.parse(name, driver, id, key); mi.poll_interval = c->pollinterval; - if (mi.driver == MeterDriver::UNKNOWN && - mi.driver_name.str() == "") + if (mi.driver_name.str() == "") { error("Not a valid meter driver \"%s\"\n", driver.c_str()); } - LinkModeSet default_modes = toMeterLinkModeSet(mi.driver); + //LinkModeSet default_modes = toMeterLinkModeSet(mi.driver); + /* if (default_modes.has(LinkMode::MBUS)) { // MBus primary address 0-250 @@ -653,6 +652,7 @@ static shared_ptr parseNormalCommandLine(Configuration *c, int ar if (!isValidMatchExpressions(id, true)) error("Not a valid id nor a valid meter match expression \"%s\"\n", id.c_str()); } if (!isValidKey(key, mi)) error("Not a valid meter key \"%s\"\n", key.c_str()); + */ c->meters.push_back(mi); diff --git a/src/config.cc b/src/config.cc index 82fbdaa..b9c4c0a 100644 --- a/src/config.cc +++ b/src/config.cc @@ -187,11 +187,6 @@ void parseMeterConfig(Configuration *c, vector &buf, string file) debug("(cmdline) setting link modes to %s for meter %s\n", mi.link_modes.hr().c_str(), name.c_str()); */ - MeterDriver mt = mi.driver; - if (mt == MeterDriver::UNKNOWN) { - warning("Not a valid meter driver \"%s\"\n", driver.c_str()); - use = false; - } if (!isValidMatchExpressions(id, true)) { warning("Not a valid meter id nor a valid meter match expression \"%s\"\n", id.c_str()); use = false; @@ -816,7 +811,7 @@ LinkModeCalculationResult calculateLinkModes(Configuration *config, BusDevice *d { meters_union.unionLinkModeSet(m.link_modes); string meter = m.link_modes.hr(); - debug("(config) meter %s link mode(s): %s\n", toString(m.driver).c_str(), meter.c_str()); + debug("(config) meter %s link mode(s): %s\n", m.driverName().str().c_str(), meter.c_str()); } string metersu = meters_union.hr(); debug("(config) all possible link modes that the meters might transmit on: %s\n", metersu.c_str()); diff --git a/src/driver_apator162.cc b/src/driver_apator162.cc index ae4a3cf..313b5a2 100644 --- a/src/driver_apator162.cc +++ b/src/driver_apator162.cc @@ -246,7 +246,7 @@ namespace // |MyTapWaterg;27202020;15.992;1111-11-11 11:11.11 -// Test: NewAndOld apator172 00148686 NOKEY +// Test: NewAndOld apator162 00148686 NOKEY // Comment: New apator162 telegram which can be decoded. // telegram=4E4401068686140005077A350040852F2F_0F005B599600000010AA55000041545A42850BD800437D037301C5500000564B00009E4600006A410000A01778EC03FFFFFFFFFFFFFFFFFFFFFFFFFFE393 // {"media":"water","meter":"apator162","name":"NewAndOld","id":"00148686","total_m3":21.93,"timestamp":"1111-11-11T11:11:11Z"} diff --git a/src/driver_multical603.cc b/src/driver_kamheat.cc similarity index 55% rename from src/driver_multical603.cc rename to src/driver_kamheat.cc index 0dd51fd..5b59d56 100644 --- a/src/driver_multical603.cc +++ b/src/driver_kamheat.cc @@ -27,13 +27,30 @@ namespace static bool ok = registerDriver([](DriverInfo&di) { - di.setName("multical603"); - di.setDefaultFields("name,id,total_energy_consumption_kwh,total_volume_m3,volume_flow_m3h,t1_temperature_c,t2_temperature_c,current_status,timestamp"); + di.setName("kamheat"); + di.addNameAlias("multical302"); + di.addNameAlias("multical303"); + di.addNameAlias("multical403"); + di.addNameAlias("multical602"); + di.addNameAlias("multical603"); + di.addNameAlias("multical803"); + di.setDefaultFields("name,id,total_energy_consumption_kwh,total_volume_m3,status,timestamp"); di.setMeterType(MeterType::HeatMeter); di.addLinkMode(LinkMode::C1); di.addLinkMode(LinkMode::T1); - di.addDetection(MANUFACTURER_KAM, 0x04, 0x35); - di.addDetection(MANUFACTURER_KAM, 0x0c, 0x35); + di.addDetection(MANUFACTURER_KAM, 0x04, 0x30); // 302 + di.addDetection(MANUFACTURER_KAM, 0x0d, 0x30); // 302 + di.addDetection(MANUFACTURER_KAM, 0x0c, 0x30); // 302 + di.addDetection(MANUFACTURER_KAM, 0x04, 0x40); // 303 + di.addDetection(MANUFACTURER_KAM, 0x0a, 0x34); // 403 + di.addDetection(MANUFACTURER_KAM, 0x0b, 0x34); // 403 + di.addDetection(MANUFACTURER_KAM, 0x0c, 0x34); // 403 + di.addDetection(MANUFACTURER_KAM, 0x0d, 0x34); // 403 + di.addDetection(MANUFACTURER_KAM, 0x04, 0x1c); // 602 + di.addDetection(MANUFACTURER_KAM, 0x04, 0x35); // 603 + di.addDetection(MANUFACTURER_KAM, 0x0c, 0x35); // 603 + di.addDetection(MANUFACTURER_KAM, 0x04, 0x39); // 803 + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); @@ -45,8 +62,7 @@ namespace addStringFieldWithExtractorAndLookup( "status", "Status and error flags.", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT | - PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, + PrintProperty::JSON | PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, FieldMatcher::build() .set(DifVifKey("04FF22")), Translate::Lookup( @@ -98,7 +114,7 @@ namespace addNumericFieldWithExtractor( "total_energy_consumption", "The total energy consumption recorded by this meter.", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, + PrintProperty::JSON | PrintProperty::OPTIONAL, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() @@ -172,7 +188,6 @@ namespace .set(VIFRange::ReturnTemperature) ); - addNumericFieldWithExtractor( "max_flow", "The maximum flow of water that passed through this meter.", @@ -184,59 +199,6 @@ namespace .set(VIFRange::VolumeFlow) ); - // Backwards compatible current_status to be removed. - addStringFieldWithExtractorAndLookup( - "current_status", - "Status and error flags (9/369/ Info Bits).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::DEPRECATED, - FieldMatcher::build() - .set(DifVifKey("04FF22")), - Translate::Lookup( - { - { - { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffffffff), - "", - { - { 0x00000001, "VOLTAGE_INTERRUPTED" }, - { 0x00000002, "LOW_BATTERY_LEVEL" }, - { 0x00000004, "SENSOR_ERROR" }, - { 0x00000008, "SENSOR_T1_ABOVE_MEASURING_RANGE" }, - { 0x00000010, "SENSOR_T2_ABOVE_MEASURING_RANGE" }, - { 0x00000020, "SENSOR_T1_BELOW_MEASURING_RANGE" }, - { 0x00000040, "SENSOR_T2_BELOW_MEASURING_RANGE" }, - { 0x00000080, "TEMP_DIFF_WRONG_POLARITY" }, - { 0x00000100, "FLOW_SENSOR_WEAK_OR_AIR" }, - { 0x00000200, "WRONG_FLOW_DIRECTION" }, - { 0x00000400, "RESERVED_BIT_10" }, - { 0x00000800, "FLOW_INCREASED" }, - { 0x00001000, "IN_A1_LEAKAGE_IN_THE_SYSTEM" }, - { 0x00002000, "IN_B1_LEAKAGE_IN_THE_SYSTEM" }, - { 0x00004000, "IN-A1_A2_EXTERNAL_ALARM" }, - { 0x00008000, "IN-B1_B2_EXTERNAL_ALARM" }, - { 0x00010000, "V1_COMMUNICATION_ERROR" }, - { 0x00020000, "V1_WRONG_PULSE_FIGURE" }, - { 0x00040000, "IN_A2_LEAKAGE_IN_THE_SYSTEM" }, - { 0x00080000, "IN_B2_LEAKAGE_IN_THE_SYSTEM" }, - { 0x00100000, "T3_ABOVE_MEASURING_RANGE_OR_SWITCHED_OFF" }, - { 0x00200000, "T3_BELOW_MEASURING_RANGE_OR_SHORT_CIRCUITED" }, - { 0x00400000, "V2_COMMUNICATION_ERROR" }, - { 0x00800000, "V2_WRONG_PULSE_FIGURE" }, - { 0x01000000, "V2_AIR" }, - { 0x02000000, "V2_WRONG_FLOW_DIRECTION" }, - { 0x04000000, "RESERVED_BIT_26" }, - { 0x08000000, "V2_INCREASED_FLOW" }, - { 0x10000000, "V1_V2_BURST_WATER_LOSS" }, - { 0x20000000, "V1_V2_BURST_WATER_PENETRATION" }, - { 0x40000000, "V1_V2_LEAKAGE_WATER_LOSS" }, - { 0x80000000, "V1_V2_LEAKAGE_WATER_PENETRATION" } - } - }, - }, - })); - addNumericFieldWithExtractor( "forward_energy", "The forward energy of the water (4/97/Energy E8).", @@ -257,28 +219,6 @@ namespace .set(DifVifKey("04FF08")), Unit::M3C); - /* Deprecated kwh version where unit should be m3c. */ - addNumericFieldWithExtractor( - "energy_forward", - "Deprecated! The forward energy of the water but in wrong unit! Should be m3c!", - PrintProperty::JSON | PrintProperty::OPTIONAL | PrintProperty::DEPRECATED, - Quantity::Energy, - VifScaling::None, - FieldMatcher::build() - .set(DifVifKey("04FF07")), - Unit::KWH); - - /* Deprecated kwh version where unit should be m3c. */ - addNumericFieldWithExtractor( - "energy_returned", - "Deprecated! The return energy of the water but in wrong unit! Should be m3c!", - PrintProperty::JSON | PrintProperty::OPTIONAL | PrintProperty::DEPRECATED, - Quantity::Energy, - VifScaling::None, - FieldMatcher::build() - .set(DifVifKey("04FF08")), - Unit::KWH); - addStringFieldWithExtractor( "meter_date", "The date and time (10/348/Date and time).", @@ -291,7 +231,7 @@ namespace addNumericFieldWithExtractor( "target_energy", "The energy consumption recorded by this meter at the set date (11/60/Heat energy E1/026C).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL, + PrintProperty::JSON | PrintProperty::OPTIONAL, Quantity::Energy, VifScaling::Auto, FieldMatcher::build() @@ -303,7 +243,7 @@ namespace addNumericFieldWithExtractor( "target_volume", "The amount of water that had passed through this meter at the set date (13/68/Volume V1).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL, + PrintProperty::JSON | PrintProperty::OPTIONAL, Quantity::Volume, VifScaling::Auto, FieldMatcher::build() @@ -315,7 +255,7 @@ namespace addStringFieldWithExtractor( "target_date", "The most recent billing period date and time (14/348/Date and Time logged).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL, + PrintProperty::JSON | PrintProperty::OPTIONAL, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Date) @@ -323,13 +263,57 @@ namespace ); } } + +// Test: MyHeater multical302 67676767 NOKEY +// Comment: Using vif kwh +// telegram=|2E442D2C6767676730048D2039D1684020_BCDB7803062C000043060000000314630000426C7F2A022D130001FF2100| +// {"id": "67676767","media": "heat","meter": "kamheat","name": "MyHeater","power_kw": 1.9,"status": "OK","target_date": "2019-10-31","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 44,"total_volume_m3": 0.99} +// |MyHeater;67676767;44;0.99;OK;1111-11-11 11:11.11 + +// telegram=|25442D2C6767676730048D203AD2684020_D81579E7F1D5902C00000000006300007F2A130000| +// {"id": "67676767","media": "heat","meter": "kamheat","name": "MyHeater","power_kw": 1.9,"status": "OK","target_date": "2019-10-31","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 44,"total_volume_m3": 0.99} +// |MyHeater;67676767;44;0.99;OK;1111-11-11 11:11.11 + +// Test: MyHeaterMj multical302 46464646 NOKEY +// Comment: Using mj kwh +// telegram=|2E442D2C46464646300C8D207A70EA6021B1C178_030FC51000430F9210000314072B05426CBE2B022D0C0001FF2100| +// {"id": "46464646","media": "heat volume at inlet","meter": "kamheat","name": "MyHeaterMj","power_kw": 1.2,"status": "OK","target_date": "2021-11-30","target_energy_kwh": 11783.333333,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 11925,"total_volume_m3": 3386.95} +// |MyHeaterMj;46464646;11925;3386.95;OK;1111-11-11 11:11.11 + +// telegram=|25442D2C46464646300C8D20D3E2EB60212B6D79E26DCD65_C51000921000152B05BE2B0C0000| +// {"id": "46464646","media": "heat volume at inlet","meter": "kamheat","name": "MyHeaterMj","power_kw": 1.2,"status": "OK","target_date": "2021-11-30","target_energy_kwh": 11783.333333,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 11925,"total_volume_m3": 3387.09} +// |MyHeaterMj;46464646;11925;3387.09;OK;1111-11-11 11:11.11 + // Test: Heat multical603 36363636 NOKEY // Comment: // telegram=|42442D2C3636363635048D20E18025B62087D078_0406A500000004FF072B01000004FF089C000000041421020000043B120000000259D014025D000904FF2200000000| -// {"media":"heat","meter":"multical603","name":"Heat","id":"36363636","status":"OK","total_energy_consumption_kwh":165,"total_volume_m3":5.45,"volume_flow_m3h":0.018,"t1_temperature_c":53.28,"t2_temperature_c":23.04,"current_status":"","forward_energy_m3c":299,"return_energy_m3c":156,"energy_forward_kwh":299,"energy_returned_kwh":156,"timestamp":"1111-11-11T11:11:11Z"} -// |Heat;36363636;165;5.45;0.018;53.28;23.04;;1111-11-11 11:11.11 +// {"media":"heat","meter":"kamheat","name":"Heat","id":"36363636","status":"OK","total_energy_consumption_kwh":165,"total_volume_m3":5.45,"volume_flow_m3h":0.018,"t1_temperature_c":53.28,"t2_temperature_c":23.04,"forward_energy_m3c":299,"return_energy_m3c":156,"timestamp":"1111-11-11T11:11:11Z"} +// |Heat;36363636;165;5.45;OK;1111-11-11 11:11.11 // Test: HeatInlet multical603 66666666 NOKEY // telegram=|5A442D2C66666666350C8D2066D0E16420C6A178_0406051C000004FF07393D000004FF08AE2400000414F7680000043B47000000042D1600000002596D14025DFD0804FF22000000000422E61A0000143B8C010000142D7C000000| -// {"media":"heat volume at inlet","meter":"multical603","name":"HeatInlet","id":"66666666","on_time_h":6886,"status":"OK","total_energy_consumption_kwh":7173,"total_volume_m3":268.71,"volume_flow_m3h":0.071,"power_kw":2.2,"max_power_kw":12.4,"t1_temperature_c":52.29,"t2_temperature_c":23.01,"max_flow_m3h":0.396,"current_status":"","forward_energy_m3c":15673,"return_energy_m3c":9390,"energy_forward_kwh":15673,"energy_returned_kwh":9390,"timestamp":"1111-11-11T11:11:11Z"} -// |HeatInlet;66666666;7173;268.71;0.071;52.29;23.01;;1111-11-11 11:11.11 +// {"media":"heat volume at inlet","meter":"kamheat","name":"HeatInlet","id":"66666666","on_time_h":6886,"status":"OK","total_energy_consumption_kwh":7173,"total_volume_m3":268.71,"volume_flow_m3h":0.071,"power_kw":2.2,"max_power_kw":12.4,"t1_temperature_c":52.29,"t2_temperature_c":23.01,"max_flow_m3h":0.396,"forward_energy_m3c":15673,"return_energy_m3c":9390,"timestamp":"1111-11-11T11:11:11Z"} +// |HeatInlet;66666666;7173;268.71;OK;1111-11-11 11:11.11 + +// Test: My403Cooling multical403 78780102 NOKEY +// telegram=|88442D2C02017878340A8D208D529C132037FC78_040E2D0A000004FF07F8FF000004FF08401801000413C1900500844014000000008480401400000000043BED0000000259BC06025DCD07142DE7FFFFFF84100E0000000084200E0000000004FF2200000000026C9228440E5F0300004413960D0200C4401400000000C480401400000000426C8128| +// {"forward_energy_m3c": 65528,"id": "78780102","max_power_kw": 429496727.1,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71744,"status": "OK","t1_temperature_c": 17.24,"t2_temperature_c": 19.97,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.737,"volume_flow_m3h": 0.237} +// |My403Cooling;78780102;723.611111;364.737;OK;1111-11-11 11:11.11 + +// telegram=|5B442D2C02017878340A8D2096809C1320EF2B7934147ED7_2D0A0000FAFF000043180100CE9005000000000000000000EE000000BA06CB07E7FFFFFF00000000000000000000000092285F030000960D020000000000000000008128| +// {"forward_energy_m3c": 65530,"id": "78780102","max_power_kw": 429496727.1,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71747,"status": "OK","t1_temperature_c": 17.22,"t2_temperature_c": 19.95,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.75,"volume_flow_m3h": 0.238} +// |My403Cooling;78780102;723.611111;364.75;OK;1111-11-11 11:11.11 + +// Test: Heato multical602 78152801 NOKEY +// telegram=|7A442D2C012815781C048D206450E76322344678_02F9FF1511130406690B010004EEFF07C1BC020004EEFF0890D401000414A925040084401400000000848040140000000002FD170000026CB929426CBF284406100A01004414D81A0400C4401400000000C480401400000000043B3900000002592A17025D2912| +// {"id": "78152801","media": "heat","meter": "kamheat","meter_date": "2021-09-25","name": "Heato","status": "OK","t1_temperature_c": 59.3,"t2_temperature_c": 46.49,"target_date": "2021-08-31","target_energy_kwh": 68112,"target_volume_m3": 2690.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 68457,"total_volume_m3": 2717.85,"volume_flow_m3h": 0.057} +// |Heato;78152801;68457;2717.85;OK;1111-11-11 11:11.11 + +// telegram=|4F442D2C012815781C048D206551E76322BE767900843005_1113690B0100C1BC020090D40100A925040000000000000000000000B929BF28100A0100D81A04000000000000000000390000002A172912| +// {"id": "78152801","media": "heat","meter": "kamheat","meter_date": "2021-09-25","name": "Heato","status": "OK","t1_temperature_c": 59.3,"t2_temperature_c": 46.49,"target_date": "2021-08-31","target_energy_kwh": 68112,"target_volume_m3": 2690.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 68457,"total_volume_m3": 2717.85,"volume_flow_m3h": 0.057} +// |Heato;78152801;68457;2717.85;OK;1111-11-11 11:11.11 + +// Test: Heater multical803 80808081 NOKEY +// telegram=|88442D2C8180808039048D208640513220EA7978_040FA000000004FF070200000004FF08090000000414FF000000844014000000008480401400000000043B0000000002590000025D0000142D0000000084100F0000000084200F0000000004FF2260000100026C892B440F00000000441400000000C4401400000000C480401400000000426C812B| +// {"forward_energy_m3c": 2,"id": "80808081","max_power_kw": 0,"media": "heat","meter": "kamheat","meter_date": "2020-11-09","name": "Heater","return_energy_m3c": 9,"status": "SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR","t1_temperature_c": 0,"t2_temperature_c": 0,"target_date": "2020-11-01","target_energy_kwh": 0,"target_volume_m3": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 444.444444,"total_volume_m3": 2.55,"volume_flow_m3h": 0} +// |Heater;80808081;444.444444;2.55;SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR;1111-11-11 11:11.11 diff --git a/src/driver_lse_08.cc b/src/driver_lse_08.cc index ebe0559..c0293b5 100644 --- a/src/driver_lse_08.cc +++ b/src/driver_lse_08.cc @@ -126,7 +126,7 @@ namespace } } -// Test: HCA2 qcaloric 04998541 NOKEY +// Test: HCA2 lse_08 04998541 NOKEY // telegram=|294465324185990401087a0080000082046c7f018b046e210300046d1a0e6f0202fdac7e012301fd0c01| // {"media":"heat cost allocation","meter":"lse_08","name":"HCA2","id":"04998541","status":"TPL_MFCT_80","set_date":"2003-01-31","consumption_at_set_date_hca":321,"device_date_time":"2003-02-15 14:26","duration_since_readout_h":2.489167,"model_version":"01","timestamp":"1111-11-11T11:11:11Z"} // |HCA2;04998541;2003-01-31;321;1111-11-11 11:11.11 diff --git a/src/driver_multical303.cc b/src/driver_multical303.cc deleted file mode 100644 index 48c590c..0000000 --- a/src/driver_multical303.cc +++ /dev/null @@ -1,197 +0,0 @@ -/* - Copyright (C) 2020-2022 thecem (gpl-3.0-or-later) - Copyright (C) 2022 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("multical303"); - di.setDefaultFields("name,id,status,total_energy_kwh,target_energy_kwh,timestamp"); - di.setMeterType(MeterType::HeatMeter); - di.addLinkMode(LinkMode::C1); - di.addLinkMode(LinkMode::T1); - di.addDetection(MANUFACTURER_KAM, 0x04, 0x40); - di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); - }); - - Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) - { - addNumericFieldWithExtractor( - "total_energy", - "The total energy consumption recorded by this meter.", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - Quantity::Energy, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::AnyEnergyVIF) - ); - - addNumericFieldWithExtractor( - "total_volume", - "The volume of water (3/68/Volume V1).", - PrintProperty::JSON | PrintProperty::OPTIONAL, - Quantity::Volume, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::Volume) - ); - - addNumericFieldWithExtractor( - "forward_energy", - "The forward energy of the water (4/97/Energy E8).", - PrintProperty::JSON, - Quantity::Energy, - VifScaling::None, - FieldMatcher::build() - .set(DifVifKey("04FF07")), - Unit::M3C); - - addNumericFieldWithExtractor( - "return_energy", - "The return energy of the water (5/110/Energy E9).", - PrintProperty::JSON, - Quantity::Energy, - VifScaling::None, - FieldMatcher::build() - .set(DifVifKey("04FF08")), - Unit::M3C); - - addNumericFieldWithExtractor( - "forward", - "The forward temperature of the water (6/86/t2 actual 2 decimals).", - PrintProperty::JSON | PrintProperty::OPTIONAL, - Quantity::Temperature, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::FlowTemperature) - ); - - addNumericFieldWithExtractor( - "return", - "The return temperature of the water (7/87/t2 actual 2 decimals).", - PrintProperty::JSON | PrintProperty::OPTIONAL, - Quantity::Temperature, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::ReturnTemperature) - ); - - addNumericFieldWithExtractor( - "actual_flow", - "The actual amount of water that pass through this meter (8/74/Flow V1 actual).", - PrintProperty::JSON, - Quantity::Flow, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::VolumeFlow) - ); - - addStringFieldWithExtractorAndLookup( - "status", - "Status and error flags (9/369/ Info Bits).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT | - PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, - FieldMatcher::build() - .set(DifVifKey("02FF22")), - Translate::Lookup( - { - { - { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffff), - "OK", - { - { 0x0000, "OK" }, - { 0x0001, "VOLTAGE_INTERRUPTED" }, - { 0x0002, "LOW_BATTERY_LEVEL" }, - { 0x0004, "SENSOR_ERROR" }, - { 0x0008, "SENSOR_T1_ABOVE_MEASURING_RANGE" }, - { 0x0010, "SENSOR_T2_ABOVE_MEASURING_RANGE" }, - { 0x0020, "SENSOR_T1_BELOW_MEASURING_RANGE" }, - { 0x0040, "SENSOR_T2_BELOW_MEASURING_RANGE" }, - { 0x0080, "TEMP_DIFF_WRONG_POLARITY" }, - { 0x0100, "FLOW_SENSOR_WEAK_OR_AIR" }, - { 0x0200, "WRONG_FLOW_DIRECTION" }, - { 0x0400, "UNKNOWN" }, - { 0x0800, "FLOW_INCREASED" }, - } - }, - }, - })); - - addStringFieldWithExtractor( - "meter_date", - "The date and time (10/348/Date and time).", - PrintProperty::JSON | PrintProperty::OPTIONAL, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::Date) - ); - - addNumericFieldWithExtractor( - "target_energy", - "The energy consumption recorded by this meter at the set date (11/60/Heat energy E1/026C).", - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - Quantity::Energy, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::AnyEnergyVIF) - .set(StorageNr(1)) - ); - - addNumericFieldWithExtractor( - "target_volume", - "The amount of water that had passed through this meter at the set date (13/68/Volume V1).", - PrintProperty::JSON | PrintProperty::FIELD, - Quantity::Volume, - VifScaling::Auto, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::Volume) - .set(StorageNr(1)) - ); - - addStringFieldWithExtractor( - "target_date", - "The most recent billing period date and time (14/348/Date and Time logged).", - PrintProperty::JSON | PrintProperty::FIELD, - FieldMatcher::build() - .set(MeasurementType::Instantaneous) - .set(VIFRange::Date) - .set(StorageNr(1)) - ); - } -} -// Test: Heat multical303 82788281 75EDE0CBBB6E126764898645AA366568 -// Comment: -// telegram=|_5E442D2C8182788240047A83005025186E9C6D9815EBFC04CBE8E4B8C8A6B9949C9DAA629CD96D920F321CFBEE7AE104DD8532C5C0EE79B4CFACCFA75D3A5EB6D4493DFAFE91B15C3A3DCFCE899138B8EA02CDB609D31CF019F9E4FD04559E| -// {"media":"heat","meter":"multical303","name":"Heat","id":"82788281","total_energy_kwh":0,"total_volume_m3":2.38,"forward_energy_m3c":61,"return_energy_m3c":61,"forward_c":26.07,"return_c":26.22,"actual_flow_m3h":0,"status":"OK","meter_date":"2022-08-18","target_energy_kwh":0,"target_volume_m3":0,"target_date":"2022-08-01","timestamp":"1111-11-11T11:11:11Z"} -// |Heat;82788281;OK;0;0;1111-11-11 11:11.11 diff --git a/src/main.cc b/src/main.cc index 0ebdef4..9f6eeb3 100644 --- a/src/main.cc +++ b/src/main.cc @@ -197,20 +197,12 @@ void list_shell_envs(Configuration *config, string meter_driver) shared_ptr meter; DriverInfo di; - mi.driver = toMeterDriver(meter_driver); - if (mi.driver != MeterDriver::UNKNOWN) + mi.driver_name = meter_driver; + if (!lookupDriverInfo(meter_driver, &di)) { - meter = createMeter(&mi); - } - else - { - mi.driver_name = meter_driver; - if (!lookupDriverInfo(meter_driver, &di)) - { - error("No such driver %s\n", meter_driver.c_str()); - } - meter = di.construct(mi); + error("No such driver %s\n", meter_driver.c_str()); } + meter = di.construct(mi); printf("METER_DEVICE\n" "METER_ID\n" @@ -254,20 +246,12 @@ void list_fields(Configuration *config, string meter_driver) shared_ptr meter; DriverInfo di; - mi.driver = toMeterDriver(meter_driver); - if (mi.driver != MeterDriver::UNKNOWN) + mi.driver_name = meter_driver; + if (!lookupDriverInfo(meter_driver, &di)) { - meter = createMeter(&mi); - } - else - { - mi.driver_name = meter_driver; - if (!lookupDriverInfo(meter_driver, &di)) - { - error("No such driver %s\n", meter_driver.c_str()); - } - meter = di.construct(mi); + error("No such driver %s\n", meter_driver.c_str()); } + meter = di.construct(mi); int width = 13; // Width of timestamp_utc for (FieldInfo &fi : meter->fieldInfos()) @@ -321,14 +305,6 @@ void list_fields(Configuration *config, string meter_driver) void list_meters(Configuration *config) { -#define X(mname,link,info,type,cname) \ - if (config->list_meters_search == "" || \ - stringFoundCaseIgnored(#info, config->list_meters_search) || \ - stringFoundCaseIgnored(#mname, config->list_meters_search)) \ - printf("%-14s %s\n", #mname, #info); -LIST_OF_METERS -#undef X - for (DriverInfo *di : allDrivers()) { string mname = di->name().str(); @@ -485,7 +461,7 @@ void setup_meters(Configuration *config, MeterManager *manager) config->extra_calculated_fields.begin(), config->extra_calculated_fields.end()); - if (m.usesPolling() || driverNeedsPolling(m.driver, m.driver_name)) + if (m.usesPolling() || driverNeedsPolling(m.driver_name)) { // A polling meter must be defined from the start. auto meter = createMeter(&m); diff --git a/src/meter_detection.h b/src/meter_detection.h deleted file mode 100644 index 4cc6161..0000000 --- a/src/meter_detection.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright (C) 2017-2022 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 . -*/ - -// This is the old style meter detection. Drivers are succesively rewritten -// from meter_xyz.cc to driver_xyz.cc only old style drivers are listed here. -// The new driver_xyz.cc file format is selfcontained so eventually this -// file be empty and go away. -// -// This file is only included into meters.cc -// -// List of numbers that can be used to detect the meter driver from a telegram. -// -// meter driver, manufacturer, media, version -// -#define METER_DETECTION \ - X(MULTICAL302,MANUFACTURER_KAM, 0x04, 0x30) \ - X(MULTICAL302,MANUFACTURER_KAM, 0x0d, 0x30) \ - X(MULTICAL302,MANUFACTURER_KAM, 0x0c, 0x30) \ - X(MULTICAL403,MANUFACTURER_KAM, 0x0a, 0x34) \ - X(MULTICAL403,MANUFACTURER_KAM, 0x0b, 0x34) \ - X(MULTICAL403,MANUFACTURER_KAM, 0x0c, 0x34) \ - X(MULTICAL403,MANUFACTURER_KAM, 0x0d, 0x34) \ - X(MULTICAL602,MANUFACTURER_KAM, 0x04, 0x1c) \ - X(MULTICAL803,MANUFACTURER_KAM, 0x04, 0x39) \ - - - -// End of list diff --git a/src/meter_multical302.cc b/src/meter_multical302.cc deleted file mode 100644 index 49475e7..0000000 --- a/src/meter_multical302.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - Copyright (C) 2018-2020 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.h" -#include"meters_common_implementation.h" -#include"dvparser.h" -#include"wmbus.h" -#include"wmbus_utils.h" -#include"util.h" - -#define INFO_CODE_VOLTAGE_INTERRUPTED 1 -#define INFO_CODE_WRONG_FLOW_DIRECTION 2 -#define INFO_CODE_SENSOR_T2_OUT_OF_RANGE 4 -#define INFO_CODE_SENSOR_T1_OUT_OF_RANGE 8 -#define INFO_CODE_FLOW_SENSOR_WEAK_OR_AIR 16 -#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 32 -#define INFO_CODE_VOLTAGE_TOO_LOW 128 - -struct MeterMultical302 : public virtual MeterCommonImplementation { - MeterMultical302(MeterInfo &mi); - - double totalEnergyConsumption(Unit u); - double targetEnergyConsumption(Unit u); - double currentPowerConsumption(Unit u); - string status(); - double totalVolume(Unit u); - double targetVolume(Unit u); - -private: - void processContent(Telegram *t); - - uchar info_codes_ {}; - double total_energy_kwh_ {}; - double target_energy_kwh_ {}; - double current_power_kw_ {}; - double total_volume_m3_ {}; - string target_date_ {}; -}; - -MeterMultical302::MeterMultical302(MeterInfo &mi) : - MeterCommonImplementation(mi, "multical302") -{ - setMeterType(MeterType::HeatMeter); - - setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR); - - addLinkMode(LinkMode::C1); - - addPrint("total_energy_consumption", Quantity::Energy, - [&](Unit u){ return totalEnergyConsumption(u); }, - "The total energy consumption recorded by this meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("current_power_consumption", Quantity::Power, - [&](Unit u){ return currentPowerConsumption(u); }, - "Current power consumption.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("total_volume", Quantity::Volume, - [&](Unit u){ return totalVolume(u); }, - "Total volume of heat media.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("at_date", Quantity::Text, - [&](){ return target_date_; }, - "Date when total energy consumption was recorded.", - PrintProperty::JSON); - - addPrint("total_energy_consumption_at_date", Quantity::Energy, - [&](Unit u){ return targetEnergyConsumption(u); }, - "The total energy consumption recorded at the target date.", - PrintProperty::JSON); - - addPrint("current_status", Quantity::Text, - [&](){ return status(); }, - "Status of meter.", - PrintProperty::FIELD | PrintProperty::JSON); -} - -shared_ptr createMultical302(MeterInfo &mi) { - return shared_ptr(new MeterMultical302(mi)); -} - -double MeterMultical302::totalEnergyConsumption(Unit u) -{ - assertQuantity(u, Quantity::Energy); - return convert(total_energy_kwh_, Unit::KWH, u); -} - -double MeterMultical302::targetEnergyConsumption(Unit u) -{ - assertQuantity(u, Quantity::Energy); - return convert(target_energy_kwh_, Unit::KWH, u); -} - -double MeterMultical302::totalVolume(Unit u) -{ - assertQuantity(u, Quantity::Volume); - return convert(total_volume_m3_, Unit::M3, u); -} - -double MeterMultical302::currentPowerConsumption(Unit u) -{ - assertQuantity(u, Quantity::Power); - return convert(current_power_kw_, Unit::KW, u); -} - -void MeterMultical302::processContent(Telegram *t) -{ - /* - (multical302) 11: bcdb payload crc - (multical302) 13: 78 frame type (long frame) - (multical302) 14: 03 dif (24 Bit Integer/Binary Instantaneous value) - (multical302) 15: 06 vif (Energy kWh) - (multical302) 16: * 2C0000 total energy consumption (44.000000 kWh) - (multical302) 19: 43 dif (24 Bit Integer/Binary Instantaneous value storagenr=1) - (multical302) 1a: 06 vif (Energy kWh) - (multical302) 1b: * 000000 target energy consumption (0.000000 kWh) - (multical302) 1e: 03 dif (24 Bit Integer/Binary Instantaneous value) - (multical302) 1f: 14 vif (Volume 10⁻² m³) - (multical302) 20: * 630000 total volume (0.990000 m3) - (multical302) 23: 42 dif (16 Bit Integer/Binary Instantaneous value storagenr=1) - (multical302) 24: 6C vif (Date type G) - (multical302) 25: * 7F2A target date (2019-10-31 00:00) - (multical302) 27: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical302) 28: 2D vif (Power 10² W) - (multical302) 29: * 1300 current power consumption (1.900000 kW) - (multical302) 2b: 01 dif (8 Bit Integer/Binary Instantaneous value) - (multical302) 2c: FF vif (Vendor extension) - (multical302) 2d: 21 vife (per minute) - (multical302) 2e: * 00 info codes (00) - */ - - int offset; - string key; - - extractDVuint8(&t->dv_entries, "01FF21", &offset, &info_codes_); - t->addMoreExplanation(offset, " info codes (%s)", status().c_str()); - - if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyWh, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_energy_kwh_); - t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_energy_kwh_); - } else if (findKey(MeasurementType::Instantaneous, VIFRange::EnergyMJ, 0, 0, &key, &t->dv_entries)) { - double mj; - extractDVdouble(&t->dv_entries, key, &offset, &mj); - total_energy_kwh_ = convert(mj, Unit::MJ, Unit::KWH); - t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_energy_kwh_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_volume_m3_); - t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyWh, 1, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &target_energy_kwh_); - t->addMoreExplanation(offset, " target energy consumption (%f kWh)", target_energy_kwh_); - } else if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyMJ, 1, 0, &key, &t->dv_entries)){ - double mj; - extractDVdouble(&t->dv_entries, key, &offset, &mj); - target_energy_kwh_ = convert(mj, Unit::MJ, Unit::KWH); - t->addMoreExplanation(offset, " target energy consumption (%f kWh)", target_energy_kwh_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::PowerW, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, ¤t_power_kw_); - t->addMoreExplanation(offset, " current power consumption (%f kW)", current_power_kw_); - } - - if (findKey(MeasurementType::Instantaneous, VIFRange::Date, 1, 0, &key, &t->dv_entries)) { - struct tm datetime; - extractDVdate(&t->dv_entries, key, &offset, &datetime); - target_date_ = strdatetime(&datetime); - t->addMoreExplanation(offset, " target date (%s)", target_date_.c_str()); - } -} - -string MeterMultical302::status() -{ - string s; - if (info_codes_ & INFO_CODE_VOLTAGE_INTERRUPTED) s.append("VOLTAGE_INTERRUPTED "); - if (info_codes_ & INFO_CODE_WRONG_FLOW_DIRECTION) s.append("WRONG_FLOW_DIRECTION "); - if (info_codes_ & INFO_CODE_SENSOR_T2_OUT_OF_RANGE) s.append("SENSOR_T2_OUT_OF_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T1_OUT_OF_RANGE) s.append("SENSOR_T1_OUT_OF_RANGE "); - if (info_codes_ & INFO_CODE_FLOW_SENSOR_WEAK_OR_AIR) s.append("FLOW_SENSOR_WEAK_OR_AIR "); - if (info_codes_ & INFO_CODE_TEMP_DIFF_WRONG_POLARITY) s.append("TEMP_DIFF_WRONG_POLARITY "); - if (info_codes_ & 64) s.append("UNKNOWN_64 "); - if (info_codes_ & INFO_CODE_VOLTAGE_TOO_LOW) s.append("VOLTAGE_TOO_LOW "); - if (s.length() > 0) { - s.pop_back(); // Remove final space - return s; - } - return s; -} diff --git a/src/meter_multical403.cc b/src/meter_multical403.cc deleted file mode 100644 index ffc04dc..0000000 --- a/src/meter_multical403.cc +++ /dev/null @@ -1,209 +0,0 @@ -/* - Copyright (C) 2018-2020 Fredrik Öhrström (gpl-3.0-or-later) - Copyright (C) 2020 Eric Bus (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.h" -#include"meters_common_implementation.h" -#include"dvparser.h" -#include"wmbus.h" -#include"wmbus_utils.h" -#include"util.h" - -#define INFO_CODE_VOLTAGE_INTERRUPTED 1 -#define INFO_CODE_LOW_BATTERY_LEVEL 2 -#define INFO_CODE_EXTERNAL_ALARM 4 -#define INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE 8 -#define INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE 16 -#define INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE 32 -#define INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE 64 -#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 128 - -struct MeterMultical403 : public virtual MeterCommonImplementation { - MeterMultical403(MeterInfo &mi); - - double totalEnergyConsumption(Unit u); - string status(); - double totalVolume(Unit u); - double volumeFlow(Unit u); - - // Water temperatures - double t1Temperature(Unit u); - bool hasT1Temperature(); - double t2Temperature(Unit u); - bool hasT2Temperature(); - -private: - void processContent(Telegram *t); - - uchar info_codes_ {}; - double total_energy_mj_ {}; - double total_volume_m3_ {}; - double volume_flow_m3h_ {}; - double t1_temperature_c_ { 127 }; - bool has_t1_temperature_ {}; - double t2_temperature_c_ { 127 }; - bool has_t2_temperature_ {}; - string target_date_ {}; -}; - -MeterMultical403::MeterMultical403(MeterInfo &mi) : - MeterCommonImplementation(mi, "multical403") -{ - setMeterType(MeterType::HeatMeter); - - setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR); - - addLinkMode(LinkMode::C1); - - addPrint("total_energy_consumption", Quantity::Energy, - [&](Unit u){ return totalEnergyConsumption(u); }, - "The total energy consumption recorded by this meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("total_volume", Quantity::Volume, - [&](Unit u){ return totalVolume(u); }, - "Total volume of media.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("volume_flow", Quantity::Flow, - [&](Unit u){ return volumeFlow(u); }, - "The current flow.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t1_temperature", Quantity::Temperature, - [&](Unit u){ return t1Temperature(u); }, - "The T1 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t2_temperature", Quantity::Temperature, - [&](Unit u){ return t2Temperature(u); }, - "The T2 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("at_date", Quantity::Text, - [&](){ return target_date_; }, - "Date when total energy consumption was recorded.", - PrintProperty::JSON); - - addPrint("current_status", Quantity::Text, - [&](){ return status(); }, - "Status of meter.", - PrintProperty::FIELD | PrintProperty::JSON); -} - -shared_ptr createMultical403(MeterInfo &mi) { - return shared_ptr(new MeterMultical403(mi)); -} - -double MeterMultical403::totalEnergyConsumption(Unit u) -{ - assertQuantity(u, Quantity::Energy); - return convert(total_energy_mj_, Unit::MJ, u); -} - -double MeterMultical403::totalVolume(Unit u) -{ - assertQuantity(u, Quantity::Volume); - return convert(total_volume_m3_, Unit::M3, u); -} - -double MeterMultical403::t1Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t1_temperature_c_, Unit::C, u); -} - -bool MeterMultical403::hasT1Temperature() -{ - return has_t1_temperature_; -} - -double MeterMultical403::t2Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t2_temperature_c_, Unit::C, u); -} - -bool MeterMultical403::hasT2Temperature() -{ - return has_t2_temperature_; -} - -double MeterMultical403::volumeFlow(Unit u) -{ - assertQuantity(u, Quantity::Flow); - return convert(volume_flow_m3h_, Unit::M3H, u); -} - -void MeterMultical403::processContent(Telegram *t) -{ - int offset; - string key; - - extractDVuint8(&t->dv_entries, "04FF22", &offset, &info_codes_); - t->addMoreExplanation(offset, " info codes (%s)", status().c_str()); - - if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyMJ, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_energy_mj_); - t->addMoreExplanation(offset, " total energy consumption (%f MJ)", total_energy_mj_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_volume_m3_); - t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::VolumeFlow, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &volume_flow_m3h_); - t->addMoreExplanation(offset, " volume flow (%f m3/h)", volume_flow_m3h_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::FlowTemperature, 0, 0, &key, &t->dv_entries)) { - has_t1_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t1_temperature_c_); - t->addMoreExplanation(offset, " T1 flow temperature (%f °C)", t1_temperature_c_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::ReturnTemperature, 0, 0, &key, &t->dv_entries)) { - has_t2_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t2_temperature_c_); - t->addMoreExplanation(offset, " T2 flow temperature (%f °C)", t2_temperature_c_); - } - - if (findKey(MeasurementType::Instantaneous, VIFRange::Date, 0, 0, &key, &t->dv_entries)) { - struct tm datetime; - extractDVdate(&t->dv_entries, key, &offset, &datetime); - target_date_ = strdatetime(&datetime); - t->addMoreExplanation(offset, " target date (%s)", target_date_.c_str()); - } -} - -string MeterMultical403::status() -{ - string s; - if (info_codes_ & INFO_CODE_VOLTAGE_INTERRUPTED) s.append("VOLTAGE_INTERRUPTED "); - if (info_codes_ & INFO_CODE_LOW_BATTERY_LEVEL) s.append("LOW_BATTERY_LEVEL "); - if (info_codes_ & INFO_CODE_EXTERNAL_ALARM) s.append("EXTERNAL_ALARM "); - if (info_codes_ & INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE) s.append("SENSOR_T1_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE) s.append("SENSOR_T2_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE) s.append("SENSOR_T1_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE) s.append("SENSOR_T2_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_TEMP_DIFF_WRONG_POLARITY) s.append("TEMP_DIFF_WRONG_POLARITY "); - if (s.length() > 0) { - s.pop_back(); // Remove final space - return s; - } - return s; -} diff --git a/src/meter_multical602.cc b/src/meter_multical602.cc deleted file mode 100644 index 0d1aabb..0000000 --- a/src/meter_multical602.cc +++ /dev/null @@ -1,285 +0,0 @@ -/* - Copyright (C) 2018-2021 Fredrik Öhrström (gpl-3.0-or-later) - Copyright (C) 2020 Eric Bus (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.h" -#include"meters_common_implementation.h" -#include"dvparser.h" -#include"wmbus.h" -#include"wmbus_utils.h" -#include"util.h" - -#define INFO_CODE_VOLTAGE_INTERRUPTED 1 -#define INFO_CODE_LOW_BATTERY_LEVEL 2 -#define INFO_CODE_EXTERNAL_ALARM 4 -#define INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE 8 -#define INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE 16 -#define INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE 32 -#define INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE 64 -#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 128 - -struct MeterMultical602 : public virtual MeterCommonImplementation { - MeterMultical602(MeterInfo &mi); - - double totalEnergyConsumption(Unit u); - string status(); - double totalVolume(Unit u); - double volumeFlow(Unit u); - - // Water temperatures - double t1Temperature(Unit u); - bool hasT1Temperature(); - double t2Temperature(Unit u); - bool hasT2Temperature(); - -private: - void processContent(Telegram *t); - - uchar info_codes_ {}; - double total_energy_kwh_ {}; - double total_volume_m3_ {}; - double volume_flow_m3h_ {}; - double t1_temperature_c_ { 127 }; - bool has_t1_temperature_ {}; - double t2_temperature_c_ { 127 }; - bool has_t2_temperature_ {}; - string target_date_ {}; - - uint32_t energy_forward_kwh_ {}; - uint32_t energy_returned_kwh_ {}; -}; - -MeterMultical602::MeterMultical602(MeterInfo &mi) : - MeterCommonImplementation(mi, "multical602") -{ - setMeterType(MeterType::HeatMeter); - - setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR); - - addLinkMode(LinkMode::C1); - - addPrint("total_energy_consumption", Quantity::Energy, - [&](Unit u){ return totalEnergyConsumption(u); }, - "The total energy consumption recorded by this meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("total_volume", Quantity::Volume, - [&](Unit u){ return totalVolume(u); }, - "Total volume of media.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("volume_flow", Quantity::Flow, - [&](Unit u){ return volumeFlow(u); }, - "The current flow.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t1_temperature", Quantity::Temperature, - [&](Unit u){ return t1Temperature(u); }, - "The T1 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t2_temperature", Quantity::Temperature, - [&](Unit u){ return t2Temperature(u); }, - "The T2 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("at_date", Quantity::Text, - [&](){ return target_date_; }, - "Date when total energy consumption was recorded.", - PrintProperty::JSON); - - addPrint("current_status", Quantity::Text, - [&](){ return status(); }, - "Status of meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("energy_forward", Quantity::Energy, - [&](Unit u){ assertQuantity(u, Quantity::Energy); return convert(energy_forward_kwh_, Unit::KWH, u); }, - "Energy forward.", - PrintProperty::JSON); - - addPrint("energy_returned", Quantity::Energy, - [&](Unit u){ assertQuantity(u, Quantity::Energy); return convert(energy_returned_kwh_, Unit::KWH, u); }, - "Energy returned.", - PrintProperty::JSON); -} - -shared_ptr createMultical602(MeterInfo &mi) { - return shared_ptr(new MeterMultical602(mi)); -} - -double MeterMultical602::totalEnergyConsumption(Unit u) -{ - assertQuantity(u, Quantity::Energy); - return convert(total_energy_kwh_, Unit::KWH, u); -} - -double MeterMultical602::totalVolume(Unit u) -{ - assertQuantity(u, Quantity::Volume); - return convert(total_volume_m3_, Unit::M3, u); -} - -double MeterMultical602::t1Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t1_temperature_c_, Unit::C, u); -} - -bool MeterMultical602::hasT1Temperature() -{ - return has_t1_temperature_; -} - -double MeterMultical602::t2Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t2_temperature_c_, Unit::C, u); -} - -bool MeterMultical602::hasT2Temperature() -{ - return has_t2_temperature_; -} - -double MeterMultical602::volumeFlow(Unit u) -{ - assertQuantity(u, Quantity::Flow); - return convert(volume_flow_m3h_, Unit::M3H, u); -} - -void MeterMultical602::processContent(Telegram *t) -{ - /* - (multical602) 14: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical602) 15: F9 vif (Enhanced identification) - (multical602) 16: FF vife (additive correction constant: unit of VIF * 10^0) - (multical602) 17: 15 vife (?) - (multical602) 18: 1113 - (multical602) 1a: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 1b: 06 vif (Energy kWh) - (multical602) 1c: * 690B0100 total energy consumption (68457.000000 kWh) - (multical602) 20: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 21: EE vif (Units for H.C.A.) - (multical602) 22: FF vife (additive correction constant: unit of VIF * 10^0) - (multical602) 23: 07 vife (?) - (multical602) 24: C1BC0200 - (multical602) 28: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 29: EE vif (Units for H.C.A.) - (multical602) 2a: FF vife (additive correction constant: unit of VIF * 10^0) - (multical602) 2b: 08 vife (?) - (multical602) 2c: 90D40100 - (multical602) 30: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 31: 14 vif (Volume 10⁻² m³) - (multical602) 32: * A9250400 total volume (2717.850000 m3) - (multical602) 36: 84 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 37: 40 dife (subunit=1 tariff=0 storagenr=0) - (multical602) 38: 14 vif (Volume 10⁻² m³) - (multical602) 39: 00000000 - (multical602) 3d: 84 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 3e: 80 dife (subunit=0 tariff=0 storagenr=0) - (multical602) 3f: 40 dife (subunit=2 tariff=0 storagenr=0) - (multical602) 40: 14 vif (Volume 10⁻² m³) - (multical602) 41: 00000000 - (multical602) 45: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical602) 46: FD vif (Second extension FD of VIF-codes) - (multical602) 47: 17 vife (Error flags (binary)) - (multical602) 48: 0000 - (multical602) 4a: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical602) 4b: 6C vif (Date type G) - (multical602) 4c: * B929 target date (2021-09-25 00:00) - (multical602) 4e: 42 dif (16 Bit Integer/Binary Instantaneous value storagenr=1) - (multical602) 4f: 6C vif (Date type G) - (multical602) 50: BF28 - (multical602) 52: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (multical602) 53: 06 vif (Energy kWh) - (multical602) 54: 100A0100 - (multical602) 58: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (multical602) 59: 14 vif (Volume 10⁻² m³) - (multical602) 5a: D81A0400 - (multical602) 5e: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (multical602) 5f: 40 dife (subunit=1 tariff=0 storagenr=1) - (multical602) 60: 14 vif (Volume 10⁻² m³) - (multical602) 61: 00000000 - (multical602) 65: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (multical602) 66: 80 dife (subunit=0 tariff=0 storagenr=1) - (multical602) 67: 40 dife (subunit=2 tariff=0 storagenr=1) - (multical602) 68: 14 vif (Volume 10⁻² m³) - (multical602) 69: 00000000 - (multical602) 6d: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical602) 6e: 3B vif (Volume flow l/h) - (multical602) 6f: * 39000000 volume flow (0.057000 m3/h) - (multical602) 73: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical602) 74: 59 vif (Flow temperature 10⁻² °C) - (multical602) 75: * 2A17 T1 flow temperature (59.300000 °C) - (multical602) 77: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical602) 78: 5D vif (Return temperature 10⁻² °C) - (multical602) 79: * 2912 T2 flow temperature (46.490000 °C) - */ - int offset; - string key; - - if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyWh, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_energy_kwh_); - t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_energy_kwh_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_volume_m3_); - t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::VolumeFlow, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &volume_flow_m3h_); - t->addMoreExplanation(offset, " volume flow (%f m3/h)", volume_flow_m3h_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::FlowTemperature, 0, 0, &key, &t->dv_entries)) { - has_t1_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t1_temperature_c_); - t->addMoreExplanation(offset, " T1 flow temperature (%f °C)", t1_temperature_c_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::ReturnTemperature, 0, 0, &key, &t->dv_entries)) { - has_t2_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t2_temperature_c_); - t->addMoreExplanation(offset, " T2 flow temperature (%f °C)", t2_temperature_c_); - } - - if (findKey(MeasurementType::Instantaneous, VIFRange::Date, 0, 0, &key, &t->dv_entries)) { - struct tm datetime; - extractDVdate(&t->dv_entries, key, &offset, &datetime); - target_date_ = strdatetime(&datetime); - t->addMoreExplanation(offset, " target date (%s)", target_date_.c_str()); - } -} - -string MeterMultical602::status() -{ - string s; - if (info_codes_ & INFO_CODE_VOLTAGE_INTERRUPTED) s.append("VOLTAGE_INTERRUPTED "); - if (info_codes_ & INFO_CODE_LOW_BATTERY_LEVEL) s.append("LOW_BATTERY_LEVEL "); - if (info_codes_ & INFO_CODE_EXTERNAL_ALARM) s.append("EXTERNAL_ALARM "); - if (info_codes_ & INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE) s.append("SENSOR_T1_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE) s.append("SENSOR_T2_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE) s.append("SENSOR_T1_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE) s.append("SENSOR_T2_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_TEMP_DIFF_WRONG_POLARITY) s.append("TEMP_DIFF_WRONG_POLARITY "); - if (s.length() > 0) { - s.pop_back(); // Remove final space - return s; - } - return s; -} diff --git a/src/meter_multical803.cc b/src/meter_multical803.cc deleted file mode 100644 index ab4b27b..0000000 --- a/src/meter_multical803.cc +++ /dev/null @@ -1,298 +0,0 @@ -/* - Copyright (C) 2018-2020 Fredrik Öhrström (gpl-3.0-or-later) - Copyright (C) 2020 Eric Bus (gpl-3.0-or-later) - Copyright (C) 2020 Nikodem Jędrzejczak (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.h" -#include"meters_common_implementation.h" -#include"dvparser.h" -#include"wmbus.h" -#include"wmbus_utils.h" -#include"util.h" - -#define INFO_CODE_VOLTAGE_INTERRUPTED 1 -#define INFO_CODE_LOW_BATTERY_LEVEL 2 -#define INFO_CODE_EXTERNAL_ALARM 4 -#define INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE 8 -#define INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE 16 -#define INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE 32 -#define INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE 64 -#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 128 - -struct MeterMultical803 : public virtual MeterCommonImplementation { - MeterMultical803(MeterInfo &mi); - - double totalEnergyConsumption(Unit u); - string status(); - double totalVolume(Unit u); - double volumeFlow(Unit u); - - // Water temperatures - double t1Temperature(Unit u); - bool hasT1Temperature(); - double t2Temperature(Unit u); - bool hasT2Temperature(); - -private: - void processContent(Telegram *t); - - uchar info_codes_ {}; - double total_energy_mj_ {}; - double total_volume_m3_ {}; - double volume_flow_m3h_ {}; - double t1_temperature_c_ { 127 }; - bool has_t1_temperature_ {}; - double t2_temperature_c_ { 127 }; - bool has_t2_temperature_ {}; - string target_date_ {}; - - uint32_t energy_forward_mj_ {}; - uint32_t energy_returned_mj_ {}; -}; - -MeterMultical803::MeterMultical803(MeterInfo &mi) : - MeterCommonImplementation(mi, "multical803") -{ - setMeterType(MeterType::HeatMeter); - - setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR); - - addLinkMode(LinkMode::C1); - - addPrint("total_energy_consumption", Quantity::Energy, - [&](Unit u){ return totalEnergyConsumption(u); }, - "The total energy consumption recorded by this meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("total_volume", Quantity::Volume, - [&](Unit u){ return totalVolume(u); }, - "Total volume of media.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("volume_flow", Quantity::Flow, - [&](Unit u){ return volumeFlow(u); }, - "The current flow.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t1_temperature", Quantity::Temperature, - [&](Unit u){ return t1Temperature(u); }, - "The T1 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("t2_temperature", Quantity::Temperature, - [&](Unit u){ return t2Temperature(u); }, - "The T2 temperature.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("at_date", Quantity::Text, - [&](){ return target_date_; }, - "Date when total energy consumption was recorded.", - PrintProperty::JSON); - - addPrint("current_status", Quantity::Text, - [&](){ return status(); }, - "Status of meter.", - PrintProperty::FIELD | PrintProperty::JSON); - - addPrint("energy_forward", Quantity::Energy, - [&](Unit u){ assertQuantity(u, Quantity::Energy); return convert(energy_forward_mj_, Unit::MJ, u); }, - "Energy forward.", - PrintProperty::JSON); - - addPrint("energy_returned", Quantity::Energy, - [&](Unit u){ assertQuantity(u, Quantity::Energy); return convert(energy_returned_mj_, Unit::MJ, u); }, - "Energy returned.", - PrintProperty::JSON); -} - -shared_ptr createMultical803(MeterInfo &mi) { - return shared_ptr(new MeterMultical803(mi)); -} - -double MeterMultical803::totalEnergyConsumption(Unit u) -{ - assertQuantity(u, Quantity::Energy); - return convert(total_energy_mj_, Unit::MJ, u); -} - -double MeterMultical803::totalVolume(Unit u) -{ - assertQuantity(u, Quantity::Volume); - return convert(total_volume_m3_, Unit::M3, u); -} - -double MeterMultical803::t1Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t1_temperature_c_, Unit::C, u); -} - -bool MeterMultical803::hasT1Temperature() -{ - return has_t1_temperature_; -} - -double MeterMultical803::t2Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t2_temperature_c_, Unit::C, u); -} - -bool MeterMultical803::hasT2Temperature() -{ - return has_t2_temperature_; -} - -double MeterMultical803::volumeFlow(Unit u) -{ - assertQuantity(u, Quantity::Flow); - return convert(volume_flow_m3h_, Unit::M3H, u); -} - -void MeterMultical803::processContent(Telegram *t) -{ - /* - (wmbus) 14: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 15: 0F vif (Energy 10⁷ J) - (wmbus) 16: 00000000 - (wmbus) 1a: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 1b: FF vif (Vendor extension) - (wmbus) 1c: 07 vife (?) - (wmbus) 1d: 00000000 - (wmbus) 21: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 22: FF vif (Vendor extension) - (wmbus) 23: 08 vife (?) - (wmbus) 24: 00000000 - (wmbus) 28: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 29: 14 vif (Volume 10⁻² m³) - (wmbus) 2a: 00000000 - (wmbus) 2e: 84 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 2f: 40 dife (subunit=1 tariff=0 storagenr=0) - (wmbus) 30: 14 vif (Volume 10⁻² m³) - (wmbus) 31: 00000000 - (wmbus) 35: 84 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 36: 80 dife (subunit=0 tariff=0 storagenr=0) - (wmbus) 37: 40 dife (subunit=2 tariff=0 storagenr=0) - (wmbus) 38: 14 vif (Volume 10⁻² m³) - (wmbus) 39: 00000000 - (wmbus) 3d: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 3e: 3B vif (Volume flow l/h) - (wmbus) 3f: 00000000 - (wmbus) 43: 02 dif (16 Bit Integer/Binary Instantaneous value) - (wmbus) 44: 59 vif (Flow temperature 10⁻² °C) - (wmbus) 45: 0000 - (wmbus) 47: 02 dif (16 Bit Integer/Binary Instantaneous value) - (wmbus) 48: 5D vif (Return temperature 10⁻² °C) - (wmbus) 49: 0000 - (wmbus) 4b: 14 dif (32 Bit Integer/Binary Maximum value) - (wmbus) 4c: 2D vif (Power 10² W) - (wmbus) 4d: 00000000 - (wmbus) 51: 84 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 52: 10 dife (subunit=0 tariff=1 storagenr=0) - (wmbus) 53: 0F vif (Energy 10⁷ J) - (wmbus) 54: 00000000 - (wmbus) 58: 84 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 59: 20 dife (subunit=0 tariff=2 storagenr=0) - (wmbus) 5a: 0F vif (Energy 10⁷ J) - (wmbus) 5b: 00000000 - (wmbus) 5f: 04 dif (32 Bit Integer/Binary Instantaneous value) - (wmbus) 60: FF vif (Vendor extension) - (wmbus) 61: 22 vife (per hour) - (wmbus) 62: 60000100 - (wmbus) 66: 02 dif (16 Bit Integer/Binary Instantaneous value) - (wmbus) 67: 6C vif (Date type G) - (wmbus) 68: 892B - (wmbus) 6a: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (wmbus) 6b: 0F vif (Energy 10⁷ J) - (wmbus) 6c: 00000000 - (wmbus) 70: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (wmbus) 71: 14 vif (Volume 10⁻² m³) - (wmbus) 72: 00000000 - (wmbus) 76: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (wmbus) 77: 40 dife (subunit=1 tariff=0 storagenr=1) - (wmbus) 78: 14 vif (Volume 10⁻² m³) - (wmbus) 79: 00000000 - (wmbus) 7d: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1) - (wmbus) 7e: 80 dife (subunit=0 tariff=0 storagenr=1) - (wmbus) 7f: 40 dife (subunit=2 tariff=0 storagenr=1) - (wmbus) 80: 14 vif (Volume 10⁻² m³) - (wmbus) 81: 00000000 - (wmbus) 85: 42 dif (16 Bit Integer/Binary Instantaneous value storagenr=1) - (wmbus) 86: 6C vif (Date type G) - (wmbus) 87: 812B - */ - - int offset; - string key; - - extractDVuint8(&t->dv_entries, "04FF22", &offset, &info_codes_); - t->addMoreExplanation(offset, " info codes (%s)", status().c_str()); - - extractDVuint32(&t->dv_entries, "04FF07", &offset, &energy_forward_mj_); - t->addMoreExplanation(offset, " energy forward mj (%zu)", energy_forward_mj_); - - extractDVuint32(&t->dv_entries, "04FF08", &offset, &energy_returned_mj_); - t->addMoreExplanation(offset, " energy returned mj (%zu)", energy_returned_mj_); - - if(findKey(MeasurementType::Instantaneous, VIFRange::EnergyMJ, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_energy_mj_); - t->addMoreExplanation(offset, " total energy consumption (%f MJ)", total_energy_mj_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &total_volume_m3_); - t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::VolumeFlow, 0, 0, &key, &t->dv_entries)) { - extractDVdouble(&t->dv_entries, key, &offset, &volume_flow_m3h_); - t->addMoreExplanation(offset, " volume flow (%f m3/h)", volume_flow_m3h_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::FlowTemperature, 0, 0, &key, &t->dv_entries)) { - has_t1_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t1_temperature_c_); - t->addMoreExplanation(offset, " T1 flow temperature (%f °C)", t1_temperature_c_); - } - - if(findKey(MeasurementType::Instantaneous, VIFRange::ReturnTemperature, 0, 0, &key, &t->dv_entries)) { - has_t2_temperature_ = extractDVdouble(&t->dv_entries, key, &offset, &t2_temperature_c_); - t->addMoreExplanation(offset, " T2 flow temperature (%f °C)", t2_temperature_c_); - } - - if (findKey(MeasurementType::Instantaneous, VIFRange::Date, 0, 0, &key, &t->dv_entries)) { - struct tm datetime; - extractDVdate(&t->dv_entries, key, &offset, &datetime); - target_date_ = strdatetime(&datetime); - t->addMoreExplanation(offset, " target date (%s)", target_date_.c_str()); - } -} - -string MeterMultical803::status() -{ - string s; - if (info_codes_ & INFO_CODE_VOLTAGE_INTERRUPTED) s.append("VOLTAGE_INTERRUPTED "); - if (info_codes_ & INFO_CODE_LOW_BATTERY_LEVEL) s.append("LOW_BATTERY_LEVEL "); - if (info_codes_ & INFO_CODE_EXTERNAL_ALARM) s.append("EXTERNAL_ALARM "); - if (info_codes_ & INFO_CODE_SENSOR_T1_ABOVE_MEASURING_RANGE) s.append("SENSOR_T1_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_ABOVE_MEASURING_RANGE) s.append("SENSOR_T2_ABOVE_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T1_BELOW_MEASURING_RANGE) s.append("SENSOR_T1_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_SENSOR_T2_BELOW_MEASURING_RANGE) s.append("SENSOR_T2_BELOW_MEASURING_RANGE "); - if (info_codes_ & INFO_CODE_TEMP_DIFF_WRONG_POLARITY) s.append("TEMP_DIFF_WRONG_POLARITY "); - if (s.length() > 0) { - s.pop_back(); // Remove final space - return s; - } - return s; -} diff --git a/src/metermanager.cc b/src/metermanager.cc index 1907a56..9038f0f 100644 --- a/src/metermanager.cc +++ b/src/metermanager.cc @@ -18,7 +18,6 @@ #include"bus.h" #include"config.h" #include"meters.h" -#include"meter_detection.h" #include"meters_common_implementation.h" #include"units.h" #include"wmbus.h" @@ -174,11 +173,11 @@ public: meter_info.ids = tmp_ids; meter_info.idsc = t.ids.back(); - if (meter_info.driver == MeterDriver::AUTO) + if (meter_info.driverName().str() == "auto") { // Look up the proper meter driver! DriverInfo di = pickMeterDriver(&t); - if (di.driver() == MeterDriver::UNKNOWN && di.name().str() == "") + if (di.name().str() == "") { if (should_analyze_ == false) { @@ -188,7 +187,6 @@ public: } else { - meter_info.driver = di.driver(); meter_info.driver_name = di.name(); } } @@ -199,7 +197,7 @@ public: verbose("(meter) used meter template %s %s %s to match %s\n", mi.name.c_str(), mi.idsc.c_str(), - toString(mi.driver).c_str(), + mi.driverName().str().c_str(), idsc.c_str()); if (is_daemon_) @@ -208,15 +206,15 @@ public: meter->index(), mi.name.c_str(), meter_info.idsc.c_str(), - toString(mi.driver).c_str()); + mi.driverName().str().c_str()); } else { verbose("(meter) started meter %d (%s %s %s)\n", - meter->index(), - mi.name.c_str(), - meter_info.idsc.c_str(), - toString(mi.driver).c_str()); + meter->index(), + mi.name.c_str(), + meter_info.idsc.c_str(), + mi.driverName().str().c_str()); } bool match = false; @@ -286,79 +284,6 @@ public: analyze_verbose_ = verbose; } - string findBestOldStyleDriver(MeterInfo &mi, - int *best_length, - int *best_understood, - Telegram &t, - AboutTelegram &about, - vector &input_frame, - bool simulated, - string force) - { - vector old_drivers; -#define X(mname,linkmode,info,type,cname) old_drivers.push_back(MeterDriver::type); -LIST_OF_METERS -#undef X - - string best_driver = ""; - for (MeterDriver odr : old_drivers) - { - if (odr == MeterDriver::AUTO) continue; - if (odr == MeterDriver::UNKNOWN) continue; - string driver_name = toString(odr); - if (force != "") - { - if (driver_name != force) continue; - return driver_name; - } - - if (force == "" && - !isMeterDriverReasonableForMedia(odr, "", t.dll_type) && - !isMeterDriverReasonableForMedia(odr, "", t.tpl_type)) - { - // Sanity check, skip this driver since it is not relevant for this media. - continue; - } - - debug("Testing old style driver %s...\n", driver_name.c_str()); - mi.driver = odr; - mi.driver_name = DriverName(""); - - auto meter = createMeter(&mi); - - bool match = false; - string id; - bool h = meter->handleTelegram(about, input_frame, simulated, &id, &match, &t); - if (!match) - { - debug("no match!\n"); - } - else if (!h) - { - // Oups, we added a new meter object tailored for this telegram - // but it still did not handle it! This can happen if the wrong - // decryption key was used. But it is ok if analyzing.... - debug("Newly created meter (%s %s %s) did not handle telegram!\n", - meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str()); - } - else - { - int l = 0; - int u = 0; - t.analyzeParse(OutputFormat::NONE, &l, &u); - if (analyze_verbose_ && force == "") printf("(verbose) old %02d/%02d %s\n", u, l, driver_name.c_str()); - if (u > *best_understood) - { - *best_understood = u; - *best_length = l; - best_driver = driver_name; - if (analyze_verbose_ && force == "") printf("(verbose) old best so far: %s %02d/%02d\n", best_driver.c_str(), u, l); - } - } - } - return best_driver; - } - string findBestNewStyleDriver(MeterInfo &mi, int *best_length, int *best_understood, @@ -380,15 +305,14 @@ LIST_OF_METERS } if (only == "" && - !isMeterDriverReasonableForMedia(MeterDriver::AUTO, driver_name, t.dll_type) && - !isMeterDriverReasonableForMedia(MeterDriver::AUTO, driver_name, t.tpl_type)) + !isMeterDriverReasonableForMedia(driver_name, t.dll_type) && + !isMeterDriverReasonableForMedia(driver_name, t.tpl_type)) { // Sanity check, skip this driver since it is not relevant for this media. continue; } - debug("Testing new style driver %s...\n", driver_name.c_str()); - mi.driver = MeterDriver::UNKNOWN; + debug("Testing driver %s...\n", driver_name.c_str()); mi.driver_name = driver_name; auto meter = createMeter(&mi); @@ -465,32 +389,15 @@ LIST_OF_METERS int using_understood = 0; // Driver that understands most of the telegram content. - string best_driver = ""; int best_length = 0; int best_understood = 0; + string best_driver = findBestNewStyleDriver(mi, &best_length, &best_understood, t, about, input_frame, simulated, ""); - int old_best_length = 0; - int old_best_understood = 0; - string best_old_driver = findBestOldStyleDriver(mi, &old_best_length, &old_best_understood, t, about, input_frame, simulated, ""); - - int new_best_length = 0; - int new_best_understood = 0; - string best_new_driver = findBestNewStyleDriver(mi, &new_best_length, &new_best_understood, t, about, input_frame, simulated, ""); - - mi.driver = MeterDriver::UNKNOWN; mi.driver_name = DriverName(""); // Use the existing mapping from mfct/media/version to driver. DriverInfo auto_di = pickMeterDriver(&t); string auto_driver = auto_di.name().str(); - if (auto_driver == "") - { - auto_driver = toString(auto_di.driver()); - if (auto_driver == "unknown") - { - auto_driver = ""; - } - } // Will be non-empty if an explicit driver has been selected. string force_driver = analyze_driver_; @@ -505,55 +412,14 @@ LIST_OF_METERS if (force_driver != "") { - using_driver = findBestOldStyleDriver(mi, &force_length, &force_understood, t, about, input_frame, simulated, + using_driver = findBestNewStyleDriver(mi, &force_length, &force_understood, t, about, input_frame, simulated, force_driver); + mi.driver_name = using_driver; - if (using_driver != "") - { - mi.driver = toMeterDriver(using_driver); - mi.driver_name = DriverName(""); - using_driver += "(driver should be upgraded)"; - } - else - { - using_driver = findBestNewStyleDriver(mi, &force_length, &force_understood, t, about, input_frame, simulated, - force_driver); - mi.driver_name = using_driver; - mi.driver = MeterDriver::UNKNOWN; - } using_length = force_length; using_understood = force_understood; } - if (old_best_understood > new_best_understood) - { - best_length = old_best_length; - best_understood = old_best_understood; - best_driver = best_old_driver+"(driver should be upgraded)"; - if (using_driver == "") - { - mi.driver = toMeterDriver(best_old_driver); - mi.driver_name = DriverName(""); - using_driver = best_driver; - using_length = best_length; - using_understood = best_understood; - } - } - else if (new_best_understood >= old_best_understood) - { - best_length = new_best_length; - best_understood = new_best_understood; - best_driver = best_new_driver; - if (using_driver == "") - { - mi.driver_name = best_new_driver; - mi.driver = MeterDriver::UNKNOWN; - using_driver = best_new_driver; - using_length = best_length; - using_understood = best_understood; - } - } - auto meter = createMeter(&mi); bool match = false; diff --git a/src/meters.cc b/src/meters.cc index 711ac12..9d787e6 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -18,7 +18,6 @@ #include"bus.h" #include"config.h" #include"meters.h" -#include"meter_detection.h" #include"meters_common_implementation.h" #include"units.h" #include"wmbus.h" @@ -167,7 +166,7 @@ bool lookupDriverInfo(const string& driver, DriverInfo *out_di) MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, string driver) : - driver_(driver), bus_(mi.bus), name_(mi.name), waiting_for_poll_response_sem_("waiting_for_poll_response") + driver_name_(driver), bus_(mi.bus), name_(mi.name), waiting_for_poll_response_sem_("waiting_for_poll_response") { ids_ = mi.ids; idsc_ = toIdsCommaSeparated(ids_); @@ -190,7 +189,6 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, DriverInfo &di) : type_(di.type()), - driver_(di.name().str()), driver_name_(di.name()), bus_(mi.bus), name_(mi.name), @@ -273,17 +271,8 @@ vector &MeterCommonImplementation::meterExtraConstantFields() return extra_constant_fields_; } -MeterDriver MeterCommonImplementation::driver() -{ - return toMeterDriver(driver_); -} - DriverName MeterCommonImplementation::driverName() { - if (driver_name_.str() == "") - { - return DriverName(toString(driver())); - } return driver_name_; } @@ -899,16 +888,8 @@ bool MeterCommonImplementation::usesPolling() link_modes_.has(LinkMode::S2); } -bool driverNeedsPolling(MeterDriver d, DriverName& dn) +bool driverNeedsPolling(DriverName& dn) { - if (d != MeterDriver::UNKNOWN && d != MeterDriver::AUTO) - { -#define X(mname,linkmodes,info,driver,cname) if (d == MeterDriver::driver && 0 != ((linkmodes) & MBUS_bit)) return true; -LIST_OF_METERS -#undef X - return false; - } - DriverInfo *di = lookupDriver(dn.str()); if (di == NULL) return false; @@ -928,51 +909,17 @@ LIST_OF_METER_TYPES return "unknown"; } -string toString(MeterDriver mt) -{ -#define X(mname,link,info,type,cname) if (mt == MeterDriver::type) return #mname; -LIST_OF_METERS -#undef X - return "unknown"; -} - string toString(DriverInfo &di) { - if (di.driver() != MeterDriver::UNKNOWN && - di.driver() != MeterDriver::AUTO) return toString(di.driver()); return di.name().str(); } -MeterDriver toMeterDriver(const string& t) -{ -#define X(mname,linkmodes,info,type,cname) if (t == #mname) return MeterDriver::type; -LIST_OF_METERS -#undef X - return MeterDriver::UNKNOWN; -} - -LinkModeSet toMeterLinkModeSet(const string& t) -{ -#define X(mname,linkmodes,info,type,cname) if (t == #mname) return LinkModeSet(linkmodes); -LIST_OF_METERS -#undef X - return LinkModeSet(); -} - -LinkModeSet toMeterLinkModeSet(MeterDriver d) -{ -#define X(mname,linkmodes,info,driver,cname) if (d == MeterDriver::driver) return LinkModeSet(linkmodes); -LIST_OF_METERS -#undef X - return LinkModeSet(); -} - bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi) { string name; vector ids; string idsc; - MeterDriver driver; + string driver_name; assert((meter && !mi) || (!meter && mi)); @@ -982,14 +929,14 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me name = meter->name(); ids = meter->ids(); idsc = meter->idsc(); - driver = meter->driver(); + driver_name = meter->driverName().str(); } else { name = mi->name; ids = mi->ids; idsc = mi->idsc; - driver = mi->driver; + driver_name = mi->driver_name.str(); } debug("(meter) %s: for me? %s in %s\n", name.c_str(), t->idsc.c_str(), idsc.c_str()); @@ -1003,13 +950,13 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me return false; } - bool valid_driver = isMeterDriverValid(driver, t->dll_mfct, t->dll_type, t->dll_version); + bool valid_driver = isMeterDriverValid(driver_name, t->dll_mfct, t->dll_type, t->dll_version); if (!valid_driver && t->tpl_id_found) { - valid_driver = isMeterDriverValid(driver, t->tpl_mfct, t->tpl_type, t->tpl_version); + valid_driver = isMeterDriverValid(driver_name, t->tpl_mfct, t->tpl_type, t->tpl_version); } - if (!valid_driver && driver != MeterDriver::AUTO) + if (!valid_driver) { // Are we using the right driver? Perhaps not since // this particular driver, mfct, media, version combo @@ -1020,8 +967,8 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me // The match for the id was not exact, thus the user is listening using a wildcard // to many meters and some received matched meter telegrams are not from the right meter type, // ie their driver does not match. Lets just ignore telegrams that probably cannot be decoded properly. - verbose("(meter) ignoring telegram from %s since it matched a wildcard id rule but driver does not match.\n", - t->idsc.c_str()); + verbose("(meter) ignoring telegram from %s since it matched a wildcard id rule but driver (%s) does not match.\n", + t->idsc.c_str(), driver_name.c_str()); return false; } @@ -1036,7 +983,7 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me warning("(meter) %s: meter detection did not match the selected driver %s! correct driver is: %s\n" "(meter) Not printing this warning again for id: %02x%02x%02x%02x mfct: (%s) %s (0x%02x) type: %s (0x%02x) ver: 0x%02x\n", name.c_str(), - toString(driver).c_str(), + driver_name.c_str(), possible_drivers.c_str(), t->dll_id_b[3], t->dll_id_b[2], t->dll_id_b[1], t->dll_id_b[0], manufacturerFlag(t->dll_mfct).c_str(), @@ -1313,7 +1260,7 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vectorids.size() > 0) { @@ -1967,7 +1914,7 @@ void MeterCommonImplementation::printMeter(Telegram *t, } envs->push_back(string("METER_NAME=")+name()); envs->push_back(string("METER_MEDIA=")+media); - envs->push_back(string("METER_TYPE=")+meterDriver()); + envs->push_back(string("METER_TYPE=")+driverName().str()); envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot()); envs->push_back(string("METER_TIMESTAMP_UTC=")+datetimeOfUpdateRobot()); envs->push_back(string("METER_TIMESTAMP_UT=")+unixTimestampOfUpdate()); @@ -2032,10 +1979,6 @@ ELLSecurityMode MeterCommonImplementation::expectedELLSecurityMode() void detectMeterDrivers(int manufacturer, int media, int version, vector *drivers) { -#define X(TY,MA,ME,VE) { if (manufacturer == MA && (media == ME || ME == -1) && (version == VE || VE == -1)) { drivers->push_back(toString(MeterDriver::TY)); }} -METER_DETECTION -#undef X - for (DriverInfo *p : allDrivers()) { if (p->detect(manufacturer, media, version)) @@ -2045,32 +1988,22 @@ METER_DETECTION } } -bool isMeterDriverValid(MeterDriver type, int manufacturer, int media, int version) +bool isMeterDriverValid(DriverName driver_name, int manufacturer, int media, int version) { -#define X(TY,MA,ME,VE) { if (type == MeterDriver::TY && manufacturer == MA && (media == ME || ME == -1) && (version == VE || VE == -1)) { return true; }} -METER_DETECTION -#undef X - for (DriverInfo *p : allDrivers()) { if (p->detect(manufacturer, media, version)) { - return true; + if (p->hasDriverName(driver_name)) return true; } } return false; } -bool isMeterDriverReasonableForMedia(MeterDriver type, string driver_name, int media) +bool isMeterDriverReasonableForMedia(string driver_name, int media) { if (media == 0x37) return false; // Skip converter meter side since they do not give any useful information. - if (driver_name == "") - { -#define X(TY,MA,ME,VE) { if (type == MeterDriver::TY && isCloseEnough(media, ME)) { return true; }} -METER_DETECTION -#undef X - } for (DriverInfo *p : allDrivers()) { @@ -2083,6 +2016,8 @@ METER_DETECTION return false; } +DriverInfo driver_unknown_; + DriverInfo pickMeterDriver(Telegram *t) { int manufacturer = t->dll_mfct; @@ -2096,10 +2031,6 @@ DriverInfo pickMeterDriver(Telegram *t) version = t->tpl_version; } -#define X(TY,MA,ME,VE) { if (manufacturer == MA && (media == ME || ME == -1) && (version == VE || VE == -1)) { return MeterDriver::TY; }} -METER_DETECTION -#undef X - for (DriverInfo *p : allDrivers()) { if (p->detect(manufacturer, media, version)) @@ -2108,7 +2039,7 @@ METER_DETECTION } } - return MeterDriver::UNKNOWN; + return driver_unknown_; } shared_ptr createMeter(MeterInfo *mi) @@ -2143,25 +2074,10 @@ shared_ptr createMeter(MeterInfo *mi) return newm; } - switch (mi->driver) - { -#define X(mname,link,info,driver,cname) \ - case MeterDriver::driver: \ - { \ - newm = create##cname(*mi); \ - newm->setPollInterval(mi->poll_interval); \ - verbose("(meter) created %s " #mname " %s %s\n", \ - mi->name.c_str(), mi->idsc.c_str(), keymsg); \ - return newm; \ - } \ - break; -LIST_OF_METERS -#undef X - } return newm; } -bool is_driver_and_extras(const string& t, MeterDriver *out_driver, DriverName *out_driver_name, string *out_extras) +bool is_driver_and_extras(const string& t, DriverName *out_driver_name, string *out_extras) { // piigth(jump=foo) // multical21 @@ -2179,13 +2095,9 @@ bool is_driver_and_extras(const string& t, MeterDriver *out_driver, DriverName * { *out_driver_name = di.name(); // We found a registered driver. - *out_driver = MeterDriver::AUTO; // To go away! *out_extras = ""; return true; } - MeterDriver md = toMeterDriver(t); - if (md == MeterDriver::UNKNOWN) return false; - *out_driver = md; *out_extras = ""; return true; } @@ -2198,16 +2110,9 @@ bool is_driver_and_extras(const string& t, MeterDriver *out_driver, DriverName * bool found = lookupDriverInfo(type, &di); - MeterDriver md = toMeterDriver(type); if (found) { *out_driver_name = di.name(); - *out_driver = MeterDriver::AUTO; // To go away! - } - else - { - if (md == MeterDriver::UNKNOWN) return false; - *out_driver = md; } string extras = t.substr(ps+1, pe-ps-1); @@ -2219,7 +2124,7 @@ bool is_driver_and_extras(const string& t, MeterDriver *out_driver, DriverName * string MeterInfo::str() { string r; - r += toString(driver); + r += driver_name.str(); if (extras != "") { r += "("+extras+")"; @@ -2256,7 +2161,7 @@ bool MeterInfo::parse(string n, string d, string i, string k) for (auto& p : parts) { - if (!driverextras_checked && is_driver_and_extras(p, &driver, &driver_name, &extras)) + if (!driverextras_checked && is_driver_and_extras(p, &driver_name, &extras)) { driverextras_checked = true; } @@ -2292,7 +2197,7 @@ bool MeterInfo::parse(string n, string d, string i, string k) { // No explicit link mode set, set to the default link modes // that the meter can transmit on. - link_modes = toMeterLinkModeSet(driver); + // link_modes = toMeterLinkModeSet(driver); } return true; @@ -2386,10 +2291,6 @@ string FieldInfo::str() DriverName MeterInfo::driverName() { - if (driver_name.str() == "") - { - return DriverName(toString(driver)); - } return driver_name; } diff --git a/src/meters.h b/src/meters.h index 45516a4..d686ca0 100644 --- a/src/meters.h +++ b/src/meters.h @@ -53,52 +53,25 @@ LIST_OF_METER_TYPES #undef X }; -// This is the old style meter list. Drivers are succesively rewritten -// from meter_xyz.cc to driver_xyz.cc only old style drivers are listed here. -// The new driver_xyz.cc file format is selfcontained so eventually this -// macro LIST_OF_METERS will be empty and go away. - -#define LIST_OF_METERS \ - X(auto, 0, AutoMeter, AUTO, Auto) \ - X(unknown, 0, UnknownMeter, UNKNOWN, Unknown) \ - X(multical302,C1_bit|T1_bit, HeatMeter, MULTICAL302, Multical302) \ - X(multical403,C1_bit, HeatMeter, MULTICAL403, Multical403) \ - X(multical602,C1_bit, HeatMeter, MULTICAL602, Multical602) \ - X(multical803,C1_bit, HeatMeter, MULTICAL803, Multical803) \ - - -enum class MeterDriver { -#define X(mname,linkmode,info,type,cname) type, -LIST_OF_METERS -#undef X -}; - struct DriverName { DriverName() {}; DriverName(string s) : name_(s) {}; - string str() { return name_; } + const string &str() const { return name_; } + bool operator==(const DriverName &dn) const { return name_ == dn.name_; } private: string name_; }; -struct MeterMatch -{ - MeterDriver driver; - int manufacturer; - int media; - int version; -}; - // Return a list of matching drivers, like: multical21 void detectMeterDrivers(int manufacturer, int media, int version, std::vector *drivers); // When entering the driver, check that the telegram is indeed known to be // compatible with the driver(type), if not then print a warning. -bool isMeterDriverValid(MeterDriver type, int manufacturer, int media, int version); +bool isMeterDriverValid(DriverName driver_name, int manufacturer, int media, int version); // For an unknown telegram, when analyzing check if the media type is reasonable in relation to the driver. // Ie. do not try to decode a door sensor telegram with a water meter driver. -bool isMeterDriverReasonableForMedia(MeterDriver type, string driver_name, int media); +bool isMeterDriverReasonableForMedia(string driver_name, int media); struct MeterInfo; bool isValidKey(const string& key, MeterInfo &mt); @@ -128,7 +101,6 @@ struct MeterInfo // A bus can be an mbus or a wmbus dongle. // The bus can be the empty string, which means that it will fallback to the first defined bus. string name; // User specified name of this (group of) meters. - MeterDriver driver {}; // Requested driver for decoding telegrams from this meter. DriverName driver_name; // Will replace MeterDriver. string extras; // Extra driver specific settings. vector ids; // Match expressions for ids. @@ -151,11 +123,10 @@ struct MeterInfo string str(); DriverName driverName(); - MeterInfo(string b, string n, MeterDriver d, string e, vector i, string k, LinkModeSet lms, int baud, vector &s, vector &j, vector &calcfs) + MeterInfo(string b, string n, string e, vector i, string k, LinkModeSet lms, int baud, vector &s, vector &j, vector &calcfs) { bus = b; name = n; - driver = d; extras = e, ids = i; idsc = toIdsCommaSeparated(ids); @@ -171,7 +142,6 @@ struct MeterInfo { bus = ""; name = ""; - driver = MeterDriver::UNKNOWN; ids.clear(); idsc = ""; key = ""; @@ -203,7 +173,6 @@ struct DriverInfo { private: - MeterDriver driver_ {}; // Old driver enum, to go away. DriverName name_; // auto, unknown, amiplus, lse_07_17, multical21 etc vector name_aliases_; // Secondary names that will map to this driver. LinkModeSet linkmodes_; // C1, T1, S1 or combinations thereof. @@ -216,7 +185,6 @@ private: public: DriverInfo() {}; - DriverInfo(MeterDriver mt) : driver_(mt) {}; void setName(std::string n) { name_ = n; } void addNameAlias(std::string n) { name_aliases_.push_back(n); } void setMeterType(MeterType t) { type_ = t; } @@ -228,9 +196,14 @@ public: void addDetection(uint16_t mfct, uchar type, uchar ver) { detect_.push_back({ mfct, type, ver }); } vector &detect() { return detect_; } - MeterDriver driver() { return driver_; } DriverName name() { return name_; } vector& nameAliases() { return name_aliases_; } + bool hasDriverName(DriverName dn) { + if (name_ == dn) return true; + for (auto &i : name_aliases_) if (i == dn) return true; + return false; + } + MeterType type() { return type_; } vector& defaultFields() { return default_fields_; } LinkModeSet linkModes() { return linkmodes_; } @@ -247,7 +220,7 @@ bool lookupDriverInfo(const string& driver, DriverInfo *di = NULL); // Return the best driver match for a telegram. DriverInfo pickMeterDriver(Telegram *t); // Return true for mbus and S2/C2/T2 drivers. -bool driverNeedsPolling(MeterDriver driver, DriverName& dn); +bool driverNeedsPolling(DriverName& dn); vector& allDrivers(); @@ -410,10 +383,8 @@ struct Meter // Either the default fields specified in the driver, or override fields in the meter configuration file. virtual vector &selectedFields() = 0; virtual void setSelectedFields(vector &f) = 0; - virtual string meterDriver() = 0; virtual string name() = 0; - virtual MeterDriver driver() = 0; - virtual DriverName driverName() = 0; + virtual DriverName driverName() = 0; virtual string datetimeOfUpdateHumanReadable() = 0; virtual string datetimeOfUpdateRobot() = 0; @@ -485,15 +456,8 @@ struct MeterManager shared_ptr createMeterManager(bool daemon); const char *toString(MeterType type); -string toString(MeterDriver driver); string toString(DriverInfo &driver); -MeterDriver toMeterDriver(const string& driver); LinkModeSet toMeterLinkModeSet(const string& driver); -LinkModeSet toMeterLinkModeSet(MeterDriver driver); - -#define X(mname,linkmode,info,type,cname) shared_ptr create##cname(MeterInfo &m); -LIST_OF_METERS -#undef X struct Configuration; struct MeterInfo; diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 9327cbb..69cd6dc 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -62,7 +62,6 @@ struct MeterCommonImplementation : public virtual Meter vector &fieldInfos(); vector &extraConstantFields(); string name(); - MeterDriver driver(); DriverName driverName(); ELLSecurityMode expectedELLSecurityMode(); @@ -88,8 +87,6 @@ struct MeterCommonImplementation : public virtual Meter ~MeterCommonImplementation() = default; - string meterDriver() { return driver_; } - protected: void triggerUpdate(Telegram *t); @@ -287,7 +284,6 @@ private: int index_ {}; MeterType type_ {}; - string driver_ {}; DriverName driver_name_; string bus_ {}; MeterKeys meter_keys_ {}; diff --git a/src/testinternals.cc b/src/testinternals.cc index 937a54a..9e575bb 100644 --- a/src/testinternals.cc +++ b/src/testinternals.cc @@ -920,7 +920,7 @@ void testm(string arg, bool xok, } if (ok == false) return; - bool driver_ok = toString(mi.driver) == xdriver || mi.driverName().str() == xdriver; + bool driver_ok = mi.driverName().str() == xdriver; bool extras_ok = mi.extras == xextras; bool bus_ok = mi.bus == xbus; bool bps_ok = to_string(mi.bps) == xbps; @@ -929,13 +929,13 @@ void testm(string arg, bool xok, if (!driver_ok || !extras_ok || !bus_ok || !bps_ok || !link_modes_ok) { printf("ERROR in meterc parsing parts \"%s\" got\n" - "driver: \"%s\"/\"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n" + "driver: \"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n" "but expected\n" "driver: \"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n", arg.c_str(), - toString(mi.driver).c_str(), mi.driverName().str().c_str(), + mi.driverName().str().c_str(), mi.extras.c_str(), mi.bus.c_str(), to_string(mi.bps).c_str(), @@ -965,20 +965,20 @@ void testc(string file, string file_content, mi = c.meters.back(); - if ((toString(mi.driver) != xdriver && mi.driverName().str() != xdriver) || + if (mi.driverName().str() != xdriver || mi.extras != xextras || mi.bus != xbus || to_string(mi.bps) != xbps || mi.link_modes.hr() != xlm) { printf("ERROR in meterc parsing parts \"%s\" got\n" - "driver: \"%s\"/\"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n" + "driver: \"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n" "but expected\n" "driver: \"%s\", extras: \"%s\", bus: \"%s\", bbps: \"%s\", linkmodes: \"%s\"\n", file.c_str(), - toString(mi.driver).c_str(), mi.driverName().str().c_str(), + mi.driverName().str().c_str(), mi.extras.c_str(), mi.bus.c_str(), to_string(mi.bps).c_str(), diff --git a/tests/test_anyid.sh b/tests/test_anyid.sh index 88c2891..eeed9bf 100755 --- a/tests/test_anyid.sh +++ b/tests/test_anyid.sh @@ -13,7 +13,7 @@ cat < $TEST/test_expected.txt EOF $PROG --format=json 2A442D2C998734761B168D2091D37CAC21576C7802FF207100041308190000441308190000615B7F616713 \ - Vatten auto ANYID NOKEY 2>&1 | jq --sort-keys . > $TEST/test_output.txt + Vatten multical21 ANYID NOKEY 2>&1 | jq --sort-keys . > $TEST/test_output.txt if [ "$?" = "0" ] then cat $TEST/test_output.txt | sed 's/"timestamp": "....-..-..T..:..:..Z"/"timestamp": "1111-11-11T11:11:11Z"/' > $TEST/test_responses.txt @@ -27,6 +27,17 @@ then fi fi +# Now test that anyid and auto does not work... +$PROG --verbose 2A442D2C998734761B168D2091D37CAC21576C7802FF207100041308190000441308190000615B7F616713 \ + Vatten auto ANYID NOKEY > $TEST/test_output.txt 2>&1 + +if ! grep -o "ignoring telegram from 76348799" $TEST/test_output.txt > /dev/null +then + echo "Expected telegram to be ignored with auto + ANYID is used!" + TESTRESULT="ERROR" +else + echo "OK: Ignoring auto + ANYID" +fi if [ "$TESTRESULT" = "ERROR" ] then diff --git a/tests/test_c1_meters.sh b/tests/test_c1_meters.sh index 39624eb..cec88b8 100755 --- a/tests/test_c1_meters.sh +++ b/tests/test_c1_meters.sh @@ -37,6 +37,11 @@ then then echo OK: $TESTNAME TESTRESULT="OK" + else + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected.txt $TEST/test_responses.txt + fi fi else echo "wmbusmeters returned error code: $?" diff --git a/tests/test_drivers.sh b/tests/test_drivers.sh index 9ee1173..011ae1c 100755 --- a/tests/test_drivers.sh +++ b/tests/test_drivers.sh @@ -65,6 +65,10 @@ do TESTRESULT="OK" else TESTRESULT="ERROR" + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected_fields.txt $TEST/test_response_fields.txt + fi fi else echo "wmbusmeters returned error code: $?" diff --git a/tests/test_key_warnings.sh b/tests/test_key_warnings.sh index 98636a8..482000b 100755 --- a/tests/test_key_warnings.sh +++ b/tests/test_key_warnings.sh @@ -13,6 +13,7 @@ $PROG --format=json simulations/simulation_bad_keys.txt room fhkvdataiv 03065716 cat > $TEST/expected_err.txt < $TEST/expected_err.txt < $TEST/test_output.txt 2> $TEST/test_stderr.txt