diff --git a/CHANGES b/CHANGES index 55e4d0d..31dfbc2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +ATTENTION! The microclima driver has been refactored. The field device_date_time has been renamed +to meter_datetime. Also two fields related to tariffs do not occur in the actual telegrams so these +fields have been removed. The fields output has therefore been drastically changed. Use --selectfields= +to reset your setup. Historical data is now decoded and added to the json. + +ATTENTION! The qwater driver has been refactored. The field device_date_time has been renamed +to meter_datetime also the due 17 date fields have been renamed. The error_code field has +disappeared since it was broken anyway and replaced with status. ATTENTION! The sharky774 driver had a bug that triggered when the meter used Joules instead of kWh. Also the calculated temperature difference had to be removed. You can re-add the temperature difference diff --git a/simulations/simulation_t1.txt b/simulations/simulation_t1.txt index e2f3280..54f4b28 100644 --- a/simulations/simulation_t1.txt +++ b/simulations/simulation_t1.txt @@ -285,8 +285,8 @@ telegram=|19442423850798160018A2410100133EBBD44081053F243A82A3| # Test Aventies Water Meter telegram=76442104710007612507727100076121042507B5006005E2E95A3C2A1279A5415E6732679B43369FD5FDDDD783EEEBB48236D34E7C94AF0A18A5FDA5F7D64111EB42D4D891622139F2952F9D12A20088DFA4CF8123871123EE1F6C1DCEA414879DDB4E05E508F1826D7EFBA6964DF804C9261EA23BBF03 -{"media":"water","meter":"aventieswm","name":"Votten","id":"61070071","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"error_flags":"","timestamp":"1111-11-11T11:11:11Z"} -|Votten;61070071;466.472000;;1111-11-11 11:11.11 +{"media":"water","meter":"aventieswm","name":"Votten","id":"61070071","status":"OK","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"error_flags":"","timestamp":"1111-11-11T11:11:11Z"} +|Votten;61070071;466.472;;1111-11-11 11:11.11 # Test Unismart Gas Meter telegram=|6044B8059430040001037A1D005085E2B670BCF1A5C87E0C1A51DA18924EF984613DA2A9CD39D8F4C7208326C76D42DBEADF80D574192B71BD7C4F56A7F1513151768A9DB804883B28CB085CA2D0F7438C361CB9E2734712ED9BFBB2A14EF55208| diff --git a/src/driver_aventieshca.cc b/src/driver_aventieshca.cc index fce313e..c1b961e 100644 --- a/src/driver_aventieshca.cc +++ b/src/driver_aventieshca.cc @@ -17,116 +17,118 @@ #include"meters_common_implementation.h" -struct MeterAventiesHCA : public virtual MeterCommonImplementation +namespace { - MeterAventiesHCA(MeterInfo &mi, DriverInfo &di); - -private: - - double current_consumption_hca_ {}; - double consumption_at_set_date_hca_[17] {}; // storagenr 1 to 17 are stored in index 0 to 16 - string error_flags_; -}; - -static bool ok = registerDriver([](DriverInfo&di) -{ - di.setName("aventieshca"); - di.setMeterType(MeterType::HeatCostAllocationMeter); - di.addLinkMode(LinkMode::T1); - di.addDetection(MANUFACTURER_AAA, 0x08, 0x55); - di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new MeterAventiesHCA(mi, di)); }); -}); - -MeterAventiesHCA::MeterAventiesHCA(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) -{ - addNumericFieldWithExtractor( - "current_consumption", - Quantity::HCA, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::HeatCostAllocation, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - "The current heat cost allocation.", - SET_FUNC(current_consumption_hca_, Unit::HCA), - GET_FUNC(current_consumption_hca_, Unit::HCA)); - - addNumericFieldWithExtractor( - "consumption_at_set_date", - Quantity::HCA, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::HeatCostAllocation, - StorageNr(1), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "Heat cost allocation at the most recent billing period date.", - SET_FUNC(consumption_at_set_date_hca_[0], Unit::HCA), - GET_FUNC(consumption_at_set_date_hca_[0], Unit::HCA)); - - for (int i=2; i<=17; ++i) + struct Driver : public virtual MeterCommonImplementation { - string key, info; - strprintf(&key, "consumption_at_set_date_%d", i); - strprintf(&info, "Heat cost allocation at the %d billing period date.", i); + Driver(MeterInfo &mi, DriverInfo &di); + }; + + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("aventieshca"); + di.setDefaultFields("name,id,current_consumption_hca,error_flags,timestamp"); + di.setMeterType(MeterType::HeatCostAllocationMeter); + di.addLinkMode(LinkMode::T1); + di.addDetection(MANUFACTURER_AAA, 0x08, 0x55); + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); + + Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) + { + addStringFieldWithExtractorAndLookup( + "status", + "Meter status from error flags and tpl status field.", + PrintProperty::JSON | PrintProperty::IMPORTANT | + PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ErrorFlags), + Translate::Lookup( + { + { + { + "ERROR_FLAGS", + Translate::Type::BitToString, + AlwaysTrigger, MaskBits(0xffff), + "OK", + { + { 0x01, "MEASUREMENT", TestBit::Set }, + { 0x02, "SABOTAGE" }, + { 0x04, "BATTERY" }, + { 0x08, "CS" }, + { 0x10, "HF" }, + { 0x20, "RESET" } + } + }, + }, + })); + + addStringFieldWithExtractorAndLookup( + "error_flags", + "Deprecated.", + PrintProperty::JSON | PrintProperty::DEPRECATED, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ErrorFlags), + Translate::Lookup( + { + { + { + "ERROR_FLAGS", + Translate::Type::BitToString, + AlwaysTrigger, MaskBits(0xffff), + "", + { + { 0x01, "MEASUREMENT", TestBit::Set }, + { 0x02, "SABOTAGE" }, + { 0x04, "BATTERY" }, + { 0x08, "CS" }, + { 0x10, "HF" }, + { 0x20, "RESET" } + } + }, + }, + })); addNumericFieldWithExtractor( - key, + "current_consumption", + "The current heat cost allocation.", + PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, Quantity::HCA, - NoDifVifKey, VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::HeatCostAllocation, - StorageNr(i), - TariffNr(0), - IndexNr(1), + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::HeatCostAllocation) + ); + + addNumericFieldWithExtractor( + "consumption_at_set_date", + "Heat cost allocation at the most recent billing period date.", PrintProperty::JSON, - info, - SET_FUNC(consumption_at_set_date_hca_[i-1], Unit::HCA), - GET_FUNC(consumption_at_set_date_hca_[i-1], Unit::HCA)); + Quantity::HCA, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::HeatCostAllocation) + .set(StorageNr(1)) + ); + + addNumericFieldWithExtractor( + "consumption_at_set_date_{storage_counter}", + "The heat cost allocation at set date #.", + PrintProperty::JSON, + Quantity::HCA, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::HeatCostAllocation) + .set(StorageNr(2),StorageNr(17)) + ); } - - addStringFieldWithExtractorAndLookup( - "error_flags", - Quantity::Text, - DifVifKey("02FD17"), - MeasurementType::Instantaneous, - VIFRange::Any, - AnyStorageNr, - AnyTariffNr, - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "Error flags.", - SET_STRING_FUNC(error_flags_), - GET_STRING_FUNC(error_flags_), - { - { - { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffff), - "", - { - { 0x01, "MEASUREMENT", TestBit::Set }, - { 0x02, "SABOTAGE" }, - { 0x04, "BATTERY" }, - { 0x08, "CS" }, - { 0x10, "HF" }, - { 0x20, "RESET" } - } - }, - }, - } - ); - } // Test: HCA aventieshca 60900126 NOKEY // telegram=|76442104260190605508722601906021045508060060052F2F#0B6E660100426EA60082016EA600C2016E9E0082026E7E00C2026E5B0082036E4200C2036E770182046E5B01C2046E4C0182056E4701C2056E3E0182066E3B01C2066E3B0182076E3B01C2076E3B0182086E1301C2086E9C0002FD170000| -// {"media":"heat cost allocation","meter":"aventieshca","name":"HCA","id":"60900126","current_consumption_hca":166,"consumption_at_set_date_hca":166,"consumption_at_set_date_2_hca":166,"consumption_at_set_date_3_hca":158,"consumption_at_set_date_4_hca":126,"consumption_at_set_date_5_hca":91,"consumption_at_set_date_6_hca":66,"consumption_at_set_date_7_hca":375,"consumption_at_set_date_8_hca":347,"consumption_at_set_date_9_hca":332,"consumption_at_set_date_10_hca":327,"consumption_at_set_date_11_hca":318,"consumption_at_set_date_12_hca":315,"consumption_at_set_date_13_hca":315,"consumption_at_set_date_14_hca":315,"consumption_at_set_date_15_hca":315,"consumption_at_set_date_16_hca":275,"consumption_at_set_date_17_hca":156,"error_flags":"","timestamp":"1111-11-11T11:11:11Z"} -// |HCA;60900126;166.000000;;1111-11-11 11:11.11 +// {"media":"heat cost allocation","meter":"aventieshca","name":"HCA","id":"60900126","status":"OK","current_consumption_hca":166,"consumption_at_set_date_hca":166,"consumption_at_set_date_2_hca":166,"consumption_at_set_date_3_hca":158,"consumption_at_set_date_4_hca":126,"consumption_at_set_date_5_hca":91,"consumption_at_set_date_6_hca":66,"consumption_at_set_date_7_hca":375,"consumption_at_set_date_8_hca":347,"consumption_at_set_date_9_hca":332,"consumption_at_set_date_10_hca":327,"consumption_at_set_date_11_hca":318,"consumption_at_set_date_12_hca":315,"consumption_at_set_date_13_hca":315,"consumption_at_set_date_14_hca":315,"consumption_at_set_date_15_hca":315,"consumption_at_set_date_16_hca":275,"consumption_at_set_date_17_hca":156,"error_flags":"","timestamp":"1111-11-11T11:11:11Z"} +// |HCA;60900126;166;;1111-11-11 11:11.11 diff --git a/src/driver_aventieswm.cc b/src/driver_aventieswm.cc index 55859a3..e4083bc 100644 --- a/src/driver_aventieswm.cc +++ b/src/driver_aventieswm.cc @@ -17,107 +17,114 @@ #include"meters_common_implementation.h" -using namespace std; - -struct MeterAventiesWM : public virtual MeterCommonImplementation +namespace { - MeterAventiesWM(MeterInfo &mi, DriverInfo &di); - -private: - - double total_water_consumption_m3_ {}; - double consumption_at_set_date_m3_[14]; - string error_flags_; -}; - -static bool ok = registerDriver([](DriverInfo&di) -{ - di.setName("aventieswm"); - di.setMeterType(MeterType::WaterMeter); - di.addLinkMode(LinkMode::T1); - di.addDetection(MANUFACTURER_AAA, 0x07, 0x25); - di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new MeterAventiesWM(mi, di)); }); -}); - -MeterAventiesWM::MeterAventiesWM(MeterInfo &mi, DriverInfo &di) : - MeterCommonImplementation(mi, di) -{ - addNumericFieldWithExtractor( - "total", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - "The total water consumption recorded by this meter.", - SET_FUNC(total_water_consumption_m3_, Unit::M3), - GET_FUNC(total_water_consumption_m3_, Unit::M3)); - - for (int i=1; i<=14; ++i) + struct Driver : public virtual MeterCommonImplementation { - string msg, info; - strprintf(&msg, "consumption_at_set_date_%d", i); - strprintf(&info, "Water consumption at the %d billing period date.", i); - addNumericFieldWithExtractor( - msg, - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(i), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - info, - SET_FUNC(consumption_at_set_date_m3_[i-1], Unit::M3), - GET_FUNC(consumption_at_set_date_m3_[i-1], Unit::M3)); - } + Driver(MeterInfo &mi, DriverInfo &di); + }; - addStringFieldWithExtractorAndLookup( - "error_flags", - Quantity::Text, - DifVifKey("02FD17"), - MeasurementType::Instantaneous, - VIFRange::Any, - AnyStorageNr, - AnyTariffNr, - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "Error flags.", - SET_STRING_FUNC(error_flags_), - GET_STRING_FUNC(error_flags_), - { - { + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("aventieswm"); + di.setDefaultFields("name,id,total_m3,error_flags,timestamp"); + di.setMeterType(MeterType::WaterMeter); + di.addLinkMode(LinkMode::T1); + di.addDetection(MANUFACTURER_AAA, 0x07, 0x25); + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); + + Driver::Driver(MeterInfo &mi, DriverInfo &di) : + MeterCommonImplementation(mi, di) + { + addStringFieldWithExtractorAndLookup( + "status", + "Meter status from error flags and tpl status field.", + PrintProperty::JSON | PrintProperty::IMPORTANT | + PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ErrorFlags), + Translate::Lookup( { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffff), - "", { - { 0x01, "MEASUREMENT" }, - { 0x02, "SABOTAGE" }, - { 0x04, "BATTERY" }, - { 0x08, "CS" }, - { 0x10, "HF" }, - { 0x20, "RESET" } - } - }, - }, - }); + { + "ERROR_FLAGS", + Translate::Type::BitToString, + AlwaysTrigger, MaskBits(0xffff), + "OK", + { + { 0x01, "MEASUREMENT", TestBit::Set }, + { 0x02, "SABOTAGE" }, + { 0x04, "BATTERY" }, + { 0x08, "CS" }, + { 0x10, "HF" }, + { 0x20, "RESET" } + } + }, + }, + })); + + addNumericFieldWithExtractor( + "total", + "The total water consumption recorded by this meter.", + PrintProperty::JSON | PrintProperty::IMPORTANT, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + ); + + addNumericFieldWithExtractor( + "consumption_at_set_date_{storage_counter}", + "Water consumption at the # billing period date.", + PrintProperty::JSON, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + .set(StorageNr(1),StorageNr(14)) + ); + + + addStringFieldWithExtractorAndLookup( + "error_flags", + "Deprecated.", + PrintProperty::JSON | PrintProperty::DEPRECATED, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ErrorFlags), + Translate::Lookup( + { + { + { + "ERROR_FLAGS", + Translate::Type::BitToString, + AlwaysTrigger, MaskBits(0xffff), + "", + { + { 0x01, "MEASUREMENT", TestBit::Set }, + { 0x02, "SABOTAGE" }, + { 0x04, "BATTERY" }, + { 0x08, "CS" }, + { 0x10, "HF" }, + { 0x20, "RESET" } + } + }, + }, + })); + } } // Test: Votten aventieswm 61070071 A004EB23329A477F1DD2D7820B56EB3D // telegram=76442104710007612507727100076121042507B5006005E2E95A3C2A1279A5415E6732679B43369FD5FDDDD783EEEBB48236D34E7C94AF0A18A5FDA5F7D64111EB42D4D891622139F2952F9D12A20088DFA4CF8123871123EE1F6C1DCEA414879DDB4E05E508F1826D7EFBA6964DF804C9261EA23BBF03 -// {"media":"water","meter":"aventieswm","name":"Votten","id":"61070071","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"error_flags":"","timestamp":"1111-11-11T11:11:11Z"} -// |Votten;61070071;466.472000;;1111-11-11 11:11.11 +// {"media":"water","meter":"aventieswm","name":"Votten","id":"61070071","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"status":"OK","error_flags":"","timestamp":"1111-11-11T11:11:11Z"} +// |Votten;61070071;466.472;;1111-11-11 11:11.11 // Test: Vatten aventieswm 61070072 NOKEY // telegram=76442104720007612507727200076121042507B50060052F2F0413281E0700431404B60083011440B300C30114A5AF00830214CBAC00C3021463A8008303149EA500C3031433A200830414C79F00C304148F9C00830514989900C30514CF9700830614269400C30614069100830714C88B0002FD171111 -// {"media":"water","meter":"aventieswm","name":"Vatten","id":"61070072","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"error_flags":"ERROR_FLAGS_1100 HF MEASUREMENT","timestamp":"1111-11-11T11:11:11Z"} -// |Vatten;61070072;466.472000;ERROR_FLAGS_1100 HF MEASUREMENT;1111-11-11 11:11.11 +// {"media":"water","meter":"aventieswm","name":"Vatten","id":"61070072","total_m3":466.472,"consumption_at_set_date_1_m3":465.96,"consumption_at_set_date_2_m3":458.88,"consumption_at_set_date_3_m3":449.65,"consumption_at_set_date_4_m3":442.35,"consumption_at_set_date_5_m3":431.07,"consumption_at_set_date_6_m3":423.98,"consumption_at_set_date_7_m3":415.23,"consumption_at_set_date_8_m3":409.03,"consumption_at_set_date_9_m3":400.79,"consumption_at_set_date_10_m3":393.2,"consumption_at_set_date_11_m3":388.63,"consumption_at_set_date_12_m3":379.26,"consumption_at_set_date_13_m3":371.26,"consumption_at_set_date_14_m3":357.84,"status":"ERROR_FLAGS_1100 HF MEASUREMENT","error_flags":"ERROR_FLAGS_1100 HF MEASUREMENT","timestamp":"1111-11-11T11:11:11Z"} +// |Vatten;61070072;466.472;ERROR_FLAGS_1100 HF MEASUREMENT;1111-11-11 11:11.11 diff --git a/src/driver_microclima.cc b/src/driver_microclima.cc index d49074b..82fd777 100644 --- a/src/driver_microclima.cc +++ b/src/driver_microclima.cc @@ -17,224 +17,157 @@ #include"meters_common_implementation.h" -struct MeterMicroClima : public virtual MeterCommonImplementation +namespace { - MeterMicroClima(MeterInfo &mi, DriverInfo &di); + struct Driver : public virtual MeterCommonImplementation + { + Driver(MeterInfo &mi, DriverInfo &di); + }; -private: - double total_energy_kwh_ {}; - double total_energy_tariff1_kwh_ {}; - double total_volume_m3_ {}; - double total_volume_tariff2_m3_ {}; - double volume_flow_m3h_ {}; - double power_kw_ {}; - double flow_temperature_c_ {}; - double return_temperature_c_ {}; - double temperature_difference_k_ {}; - string status_; - string device_date_time_; -}; + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("microclima"); + di.setDefaultFields("name,id,status,total_energy_consumption_kwh,total_volume_m3,timestamp"); + di.setMeterType(MeterType::HeatMeter); + di.addLinkMode(LinkMode::T1); + di.addDetection(MANUFACTURER_MAD, 0x04, 0x00); + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); -static bool ok = registerDriver([](DriverInfo&di) -{ - di.setName("microclima"); - di.setMeterType(MeterType::HeatMeter); - di.addLinkMode(LinkMode::T1); - di.addDetection(MANUFACTURER_MAD, 0x04, 0x00); - di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new MeterMicroClima(mi, di)); }); -}); + Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) + { + addOptionalCommonFields("meter_datetime,model_version,parameter_set"); + addOptionalFlowRelatedFields("flow_temperature_c,return_temperature_c"); -MeterMicroClima::MeterMicroClima(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) -{ - addNumericFieldWithExtractor( - "total_energy_consumption", - Quantity::Energy, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::EnergyWh, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - "The total heat energy consumption recorded by this meter.", - SET_FUNC(total_energy_kwh_, Unit::KWH), - GET_FUNC(total_energy_kwh_, Unit::KWH)); - - addNumericFieldWithExtractor( - "total_energy_consumption_tariff1", - Quantity::Energy, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::EnergyWh, - StorageNr(0), - TariffNr(1), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The total heat energy consumption recorded by this meter on tariff 1.", - SET_FUNC(total_energy_tariff1_kwh_, Unit::KWH), - GET_FUNC(total_energy_tariff1_kwh_, Unit::KWH)); - - addNumericFieldWithExtractor( - "total_volume", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The total heating media volume recorded by this meter.", - SET_FUNC(total_volume_m3_, Unit::M3), - GET_FUNC(total_volume_m3_, Unit::M3)); - - addNumericFieldWithExtractor( - "total_volume_tariff2", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(0), - TariffNr(2), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The total heating media volume recorded by this meter on tariff 2.", - SET_FUNC(total_volume_tariff2_m3_, Unit::M3), - GET_FUNC(total_volume_tariff2_m3_, Unit::M3)); - - addNumericFieldWithExtractor( - "volume_flow", - Quantity::Flow, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::VolumeFlow, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The current heat media volume flow.", - SET_FUNC(volume_flow_m3h_, Unit::M3H), - GET_FUNC(volume_flow_m3h_, Unit::M3H)); - - addNumericFieldWithExtractor( - "power", - Quantity::Power, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::PowerW, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The current power consumption.", - SET_FUNC(power_kw_, Unit::KW), - GET_FUNC(power_kw_, Unit::KW)); - - addNumericFieldWithExtractor( - "flow_temperature", - Quantity::Temperature, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::FlowTemperature, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The current forward heat media temperature.", - SET_FUNC(flow_temperature_c_, Unit::C), - GET_FUNC(flow_temperature_c_, Unit::C)); - - addNumericFieldWithExtractor( - "return_temperature", - Quantity::Temperature, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::ReturnTemperature, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The current return heat media temperature.", - SET_FUNC(return_temperature_c_, Unit::C), - GET_FUNC(return_temperature_c_, Unit::C)); - - addNumericFieldWithExtractor( - "temperature_difference", - Quantity::Temperature, - NoDifVifKey, - VifScaling::AutoSigned, - MeasurementType::Instantaneous, - VIFRange::TemperatureDifference, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The current return heat media temperature.", - SET_FUNC(temperature_difference_k_, Unit::K), - GET_FUNC(temperature_difference_k_, Unit::K)); - - addStringFieldWithExtractorAndLookup( - "status", - Quantity::Text, - DifVifKey("01FD17"), - MeasurementType::Instantaneous, - VIFRange::Any, - AnyStorageNr, - AnyTariffNr, - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "Error flags.", - SET_STRING_FUNC(status_), - GET_STRING_FUNC(status_), - { - { + addStringFieldWithExtractorAndLookup( + "status", + "Meter status from error flags and tpl status field.", + PrintProperty::JSON | PrintProperty::IMPORTANT | + PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ErrorFlags), + Translate::Lookup( { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffff), - "OK", { - { 0x01, "?" }, - } - }, - }, - }); + { + "ERROR_FLAGS", + Translate::Type::BitToString, + AlwaysTrigger, MaskBits(0xffff), + "OK", + { + } + }, + }, + })); - addStringFieldWithExtractor( - "device_date_time", - Quantity::Text, - NoDifVifKey, - MeasurementType::Instantaneous, - VIFRange::DateTime, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "Device date time.", - SET_STRING_FUNC(device_date_time_), - GET_STRING_FUNC(device_date_time_)); + addNumericFieldWithExtractor( + "total_energy_consumption", + "The total heat energy consumption recorded by this meter.", + PrintProperty::JSON | PrintProperty::IMPORTANT, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + ); + addNumericFieldWithExtractor( + "total_volume", + "The total heating media volume recorded by this meter.", + PrintProperty::JSON, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + ); + + addNumericFieldWithExtractor( + "volume_flow", + "The current heat media volume flow.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Flow, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::VolumeFlow) + ); + + addNumericFieldWithExtractor( + "power", + "The current power consumption.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Power, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::PowerW) + ); + + addNumericFieldWithExtractor( + "temperature_difference", + "The difference between flow and return media temperatures.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Temperature, + VifScaling::AutoSigned, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::TemperatureDifference) + ); + + addNumericFieldWithExtractor( + "set", + "The most recent billing period date.", + PrintProperty::JSON | PrintProperty::OPTIONAL | PrintProperty::HIDE, + Quantity::PointInTime, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Date) + .set(StorageNr(1)), + Unit::DateLT + ); + + addNumericFieldWithExtractor( + "consumption_at_set_date_{storage_counter}", + "The total water consumption at the historic date.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .set(StorageNr(1),StorageNr(31)) + ); + + addNumericFieldWithCalculatorAndMatcher( + "set_date_{storage_counter}", + "Unclear! What is the date really?", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::PointInTime, + "set_date - ((storage_counter-1counter) * 1 month)", + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .set(StorageNr(1),StorageNr(31)), + Unit::DateLT + ); + + } } // The meter sends two types of telegrams a shorter with current values. // Test: Heat microclima 93572431 NOKEY // telegram=|494424343124579300047a5a0000202f2f046d2720b62c04060d07000001fd170004130a8c0400043b00000000042b00000000025b1500025f15000261d0ff03fd0c05000002fd0b1011| -// {"media":"heat","meter":"microclima","name":"Heat","id":"93572431","total_energy_consumption_kwh":1805,"total_energy_consumption_tariff1_kwh":0,"total_volume_m3":297.994,"total_volume_tariff2_m3":0,"volume_flow_m3h":0,"power_kw":0,"flow_temperature_c":21,"return_temperature_c":21,"temperature_difference_c":-0.48,"status":"OK","device_date_time":"2021-12-22 00:39","timestamp":"1111-11-11T11:11:11Z"} -// |Heat;93572431;1805.000000;0.000000;297.994000;0.000000;0.000000;0.000000;21.000000;21.000000;-0.480000;OK;1111-11-11 11:11.11 +// {"flow_temperature_c":21,"id":"93572431","media":"heat","meter":"microclima","meter_datetime":"2021-12-22 00:39","model_version":"000005","name":"Heat","parameter_set":"1110","power_kw":0,"return_temperature_c":21,"status":"OK","temperature_difference_c":-0.48,"timestamp":"1111-11-11T11:11:11Z","total_energy_consumption_kwh":1805,"total_volume_m3":297.994,"volume_flow_m3h":0} +// |Heat;93572431;OK;1805;297.994;1111-11-11 11:11.11 // And a longer with historical values. This telegram is not yet properly decoded. // Test: Heat microclima 93573086 NOKEY // telegram=|A44424348630579300047ADD0000202F2F046D0721B62C04064708000004135DB0030001FD1700426C9F2C4406C6040000C40106C0070000C4020637070000C4030611070000C404060B070000C405060B070000C406060B070000C407060B070000C40806A5060000C40906F7050000C40A067A050000C40B060F050000C40C06C6040000C40D063F040000C40E06BB030000C40F06A502000003FD0C05000002FD0B1111| -// {"media":"heat","meter":"microclima","name":"Heat","id":"93573086","total_energy_consumption_kwh":2119,"total_energy_consumption_tariff1_kwh":0,"total_volume_m3":241.757,"total_volume_tariff2_m3":0,"volume_flow_m3h":0,"power_kw":0,"flow_temperature_c":0,"return_temperature_c":0,"temperature_difference_c":-273.15,"status":"OK","device_date_time":"2021-12-22 01:07","timestamp":"1111-11-11T11:11:11Z"} -// |Heat;93573086;2119.000000;0.000000;241.757000;0.000000;0.000000;0.000000;0.000000;0.000000;-273.150000;OK;1111-11-11 11:11.11 +// {"consumption_at_set_date_11_kwh":1803,"consumption_at_set_date_13_kwh":1803,"consumption_at_set_date_15_kwh":1803,"consumption_at_set_date_17_kwh":1701,"consumption_at_set_date_19_kwh":1527,"consumption_at_set_date_1_kwh":1222,"consumption_at_set_date_21_kwh":1402,"consumption_at_set_date_23_kwh":1295,"consumption_at_set_date_25_kwh":1222,"consumption_at_set_date_27_kwh":1087,"consumption_at_set_date_29_kwh":955,"consumption_at_set_date_31_kwh":677,"consumption_at_set_date_3_kwh":1984,"consumption_at_set_date_5_kwh":1847,"consumption_at_set_date_7_kwh":1809,"consumption_at_set_date_9_kwh":1803,"id":"93573086","media":"heat","meter":"microclima","meter_datetime":"2021-12-22 01:07","model_version":"000005","name":"Heat","parameter_set":"1111","set_date_11_date":"2020-02-29","set_date_13_date":"2019-12-31","set_date_15_date":"2019-10-31","set_date_17_date":"2019-08-31","set_date_19_date":"2019-06-30","set_date_1_date":"2020-12-31","set_date_21_date":"2019-04-30","set_date_23_date":"2019-02-28","set_date_25_date":"2018-12-31","set_date_27_date":"2018-10-31","set_date_29_date":"2018-08-31","set_date_31_date":"2018-06-30","set_date_3_date":"2020-10-31","set_date_5_date":"2020-08-31","set_date_7_date":"2020-06-30","set_date_9_date":"2020-04-30","status":"OK","timestamp":"1111-11-11T11:11:11Z","total_energy_consumption_kwh":2119,"total_volume_m3":241.757} +// |Heat;93573086;OK;2119;241.757;1111-11-11 11:11.11 diff --git a/src/driver_qwater.cc b/src/driver_qwater.cc index 7982d6b..fa72084 100644 --- a/src/driver_qwater.cc +++ b/src/driver_qwater.cc @@ -17,193 +17,140 @@ #include"meters_common_implementation.h" -using namespace std; - -struct MeterQWater : public virtual MeterCommonImplementation +namespace { - MeterQWater(MeterInfo &mi, DriverInfo &di); + struct Driver : public virtual MeterCommonImplementation + { + Driver(MeterInfo &mi, DriverInfo &di); + }; - double total_water_consumption_m3_ {}; + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("qwater"); + di.setDefaultFields("name,id,total_m3," + "due_date_m3," + "due_date," + "status," + "timestamp"); + di.setMeterType(MeterType::WaterMeter); + di.addLinkMode(LinkMode::S1); + di.addDetection(MANUFACTURER_QDS, 0x37, 0x33); + di.addDetection(MANUFACTURER_QDS, 0x06, 0x18); + di.addDetection(MANUFACTURER_QDS, 0x07, 0x18); + di.addDetection(MANUFACTURER_QDS, 0x06, 0x35); + di.addDetection(MANUFACTURER_QDS, 0x07, 0x35); - double due_date_water_consumption_m3_ {}; - string due_date_ {}; + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); - double due_date_17_water_consumption_m3_ {}; - string due_date_17_ {}; + Driver::Driver(MeterInfo &mi, DriverInfo &di) : + MeterCommonImplementation(mi, di) + { + addOptionalCommonFields("meter_datetime"); + addOptionalFlowRelatedFields("total_m3"); - string error_code_ {}; - string error_date_ {}; + addStringField( + "status", + "Meter status tpl status field.", + PrintProperty::JSON | PrintProperty::IMPORTANT | PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS); - string device_date_time_ {}; -}; + addNumericFieldWithExtractor( + "due_date", + "The water consumption at the due date.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + .set(StorageNr(1)) + ); -static bool ok = registerDriver([](DriverInfo&di) -{ - di.setName("qwater"); - di.setMeterType(MeterType::WaterMeter); - di.addLinkMode(LinkMode::S1); - di.addDetection(MANUFACTURER_QDS, 0x37, 0x33); - di.addDetection(MANUFACTURER_QDS, 0x06, 0x18); - di.addDetection(MANUFACTURER_QDS, 0x07, 0x18); - di.addDetection(MANUFACTURER_QDS, 0x06, 0x35); - di.addDetection(MANUFACTURER_QDS, 0x07, 0x35); + addNumericFieldWithExtractor( + "due", + "The due date for billing date.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::PointInTime, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Date) + .set(StorageNr(1)), + Unit::DateLT + ); - di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new MeterQWater(mi, di)); }); -}); + addNumericFieldWithExtractor( + "due_17_date", + "The water consumption at the 17 due date.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + .set(StorageNr(17)) + ); -MeterQWater::MeterQWater(MeterInfo &mi, DriverInfo &di) : - MeterCommonImplementation(mi, di) -{ - addNumericFieldWithExtractor( - "total", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - "The total water consumption recorded by this meter.", - SET_FUNC(total_water_consumption_m3_, Unit::M3), - GET_FUNC(total_water_consumption_m3_, Unit::M3)); + addNumericFieldWithExtractor( + "due_17", + "The due date for billing date.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::PointInTime, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Date) + .set(StorageNr(17)), + Unit::DateLT + ); - addNumericFieldWithExtractor( - "due_date", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(1), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT, - "The water consumption at the due date.", - SET_FUNC(due_date_water_consumption_m3_, Unit::M3), - GET_FUNC(due_date_water_consumption_m3_, Unit::M3)); + addNumericFieldWithExtractor( + "volume_flow", + "Media volume flow when duration exceeds lower last.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Flow, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::VolumeFlow) + .add(VIFCombinable::DurationExceedsLowerLast) + ); - addStringFieldWithExtractor( - "due_date", - Quantity::Text, - NoDifVifKey, - MeasurementType::Instantaneous, - VIFRange::Date, - StorageNr(1), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "The due date configured on the meter.", - SET_STRING_FUNC(due_date_), - GET_STRING_FUNC(due_date_)); - - addNumericFieldWithExtractor( - "due_date_17", - Quantity::Volume, - NoDifVifKey, - VifScaling::Auto, - MeasurementType::Instantaneous, - VIFRange::Volume, - StorageNr(17), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "The water consumption at the 17th historical due date.", - SET_FUNC(due_date_17_water_consumption_m3_, Unit::M3), - GET_FUNC(due_date_17_water_consumption_m3_, Unit::M3)); - - addStringFieldWithExtractor( - "due_date_17", - Quantity::Text, - NoDifVifKey, - MeasurementType::Instantaneous, - VIFRange::Date, - StorageNr(17), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "The due date configured for the 17th historical value.", - SET_STRING_FUNC(due_date_17_), - GET_STRING_FUNC(due_date_17_)); - - addStringFieldWithExtractorAndLookup( - "error_code", - Quantity::Text, - DifVifKey("02BB56"), - MeasurementType::Instantaneous, - VIFRange::Any, - AnyStorageNr, - AnyTariffNr, - IndexNr(1), - PrintProperty::JSON | PrintProperty::FIELD, - "Error code of the Meter, 0 means no error.", - SET_STRING_FUNC(error_code_), - GET_STRING_FUNC(error_code_), - { - { - { - "ERROR_FLAGS", - Translate::Type::BitToString, - AlwaysTrigger, MaskBits(0xffff), - "OK", - { - { 0x01, "?" }, - } - }, - }, - }); - - addStringFieldWithExtractor( - "error_date", - Quantity::Text, - NoDifVifKey, - MeasurementType::AtError, - VIFRange::Date, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "The date the error occured at. If no error, reads 2127-15-31 (FFFF).", - SET_STRING_FUNC(error_date_), - GET_STRING_FUNC(error_date_)); - - addStringFieldWithExtractor( - "device_date_time", - Quantity::Text, - NoDifVifKey, - MeasurementType::Instantaneous, - VIFRange::DateTime, - StorageNr(0), - TariffNr(0), - IndexNr(1), - PrintProperty::JSON, - "Date when measurement was recorded.", - SET_STRING_FUNC(device_date_time_), - GET_STRING_FUNC(device_date_time_)); + addNumericFieldWithExtractor( + "error", + "The date the error occured at. If no error, reads 2127-15-31 (FFFF).", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::PointInTime, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::AtError) + .set(VIFRange::Date), + Unit::DateLT + ); + } } // Test: MyQWater qwater 12353648 NOKEY // telegram=|374493444836351218067ac70000200c13911900004c1391170000426cbf2ccc081391170000c2086cbf2c02bb560000326cffff046d1e02de21fed0| -// {"media":"warm water","meter":"qwater","name":"MyQWater","id":"12353648","total_m3":1.991,"due_date_m3":1.791,"due_date":"2021-12-31","due_date_17_m3":1.791,"due_date_17":"2021-12-31","error_code":"OK","error_date":"2127-15-31","device_date_time":"2022-01-30 02:30","timestamp":"1111-11-11T11:11:11Z"} -// |MyQWater;12353648;1.991000;1.791000;2021-12-31;OK;1111-11-11 11:11.11 +// {"media":"warm water","meter":"qwater","name":"MyQWater","id":"12353648","status":"OK","total_m3":1.991,"due_date_m3":1.791,"due_date":"2021-12-31","due_17_date_m3":1.791,"due_17_date":"2021-12-31","error_date":"2128-03-31","volume_flow_m3h":0,"meter_datetime":"2022-01-30 02:30","timestamp":"1111-11-11T11:11:11Z"} +// |MyQWater;12353648;1.991;1.791;2021-12-31;OK;1111-11-11 11:11.11 // And a second telegram that only updates the device date time. // telegram=|47449344483635121806780dff5f350082da0000600107c113ffff48200000bf2c91170000df2120200000008001000000060019001000160018000d001300350017002f046d370cc422c759| -// {"media":"warm water","meter":"qwater","name":"MyQWater","id":"12353648","total_m3":1.991,"due_date_m3":1.791,"due_date":"2021-12-31","due_date_17_m3":1.791,"due_date_17":"2021-12-31","error_code":"OK","error_date":"2127-15-31","device_date_time":"2022-02-04 12:55","timestamp":"1111-11-11T11:11:11Z"} -// |MyQWater;12353648;1.991000;1.791000;2021-12-31;OK;1111-11-11 11:11.11 +// {"media":"warm water","meter":"qwater","name":"MyQWater","id":"12353648","status":"OK","total_m3":1.991,"due_date_m3":1.791,"due_date":"2021-12-31","due_17_date_m3":1.791,"due_17_date":"2021-12-31","error_date":"2128-03-31","volume_flow_m3h":0,"meter_datetime":"2022-02-04 12:55","timestamp":"1111-11-11T11:11:11Z"} +// |MyQWater;12353648;1.991;1.791;2021-12-31;OK;1111-11-11 11:11.11 // Test: AnotherQWater qwater 66666666 NOKEY -// telegram=3C449344682268363537726666666693443507720000200C13670512004C1361100300426CBF2CCC081344501100C2086CDF28326CFFFF046D0813CF29 -// {"media":"water","meter":"qwater","name":"AnotherQWater","id":"66666666","total_m3":120.567,"due_date_m3":31.061,"due_date":"2021-12-31","due_date_17_m3":115.044,"due_date_17":"2022-08-31","error_code":"","error_date":"2127-15-31","device_date_time":"2022-09-15 19:08","timestamp":"1111-11-11T11:11:11Z"} -// |AnotherQWater;66666666;120.567000;31.061000;2021-12-31;;1111-11-11 11:11.11 +// telegram=|3C449344682268363537726666666693443507720000200C13670512004C1361100300426CBF2CCC081344501100C2086CDF28326CFFFF046D0813CF29| +// {"media":"water","meter":"qwater","name":"AnotherQWater","id":"66666666","status":"OK","total_m3":120.567,"due_date_m3":31.061,"due_date":"2021-12-31","due_17_date_m3":115.044,"due_17_date":"2022-08-31","error_date":"2128-03-31","meter_datetime":"2022-09-15 19:08","timestamp":"1111-11-11T11:11:11Z"} +// |AnotherQWater;66666666;120.567;31.061;2021-12-31;OK;1111-11-11 11:11.11 // Test: YetAnoter qwater 33333333 NOKEY -// telegram=3C449344333333333537723333333393443506B8000020_0C13350000004C1300000000426CBF2CCC081300000000C2086CDF25326CFFFF046D0516CE26 -// {"media":"warm water","meter":"qwater","name":"YetAnoter","id":"33333333","total_m3":0.035,"due_date_m3":0,"due_date":"2021-12-31","due_date_17_m3":0,"due_date_17":"2022-05-31","error_code":"","error_date":"2127-15-31","device_date_time":"2022-06-14 22:05","timestamp":"1111-11-11T11:11:11Z"} -// |YetAnoter;33333333;0.035000;0.000000;2021-12-31;;1111-11-11 11:11.11 +// telegram=|3C449344333333333537723333333393443506B8000020_0C13350000004C1300000000426CBF2CCC081300000000C2086CDF25326CFFFF046D0516CE26| +// {"media":"warm water","meter":"qwater","name":"YetAnoter","id":"33333333","status":"OK","total_m3":0.035,"due_date_m3":0,"due_date":"2021-12-31","due_17_date_m3":0,"due_17_date":"2022-05-31","error_date":"2128-03-31","meter_datetime":"2022-06-14 22:05","timestamp":"1111-11-11T11:11:11Z"} +// |YetAnoter;33333333;0.035;0;2021-12-31;OK;1111-11-11 11:11.11 // Test: QWater-7-18 qwater 12230094 NOKEY -// telegram=394493449400231218077ad30000200c13536712004c1307920500426cBf2ccc081373621200c2086cde2B02BB560000326cffff046d3714c32c -// {"media":"water","meter":"qwater","name":"QWater-7-18","id":"12230094","total_m3":126.753,"due_date_m3":59.207,"due_date":"2021-12-31","due_date_17_m3":126.273,"due_date_17":"2022-11-30","error_code":"OK","error_date":"2127-15-31","device_date_time":"2022-12-03 20:55","timestamp":"1111-11-11T11:11:11Z"} -// |QWater-7-18;12230094;126.753000;59.207000;2021-12-31;OK;1111-11-11 11:11.11 +// telegram=|394493449400231218077ad30000200c13536712004c1307920500426cBf2ccc081373621200c2086cde2B02BB560000326cffff046d3714c32c| +// {"media":"water","meter":"qwater","name":"QWater-7-18","id":"12230094","status":"OK","total_m3":126.753,"due_date_m3":59.207,"due_date":"2021-12-31","due_17_date_m3":126.273,"due_17_date":"2022-11-30","error_date":"2128-03-31","volume_flow_m3h":0,"meter_datetime":"2022-12-03 20:55","timestamp":"1111-11-11T11:11:11Z"} +// |QWater-7-18;12230094;126.753;59.207;2021-12-31;OK;1111-11-11 11:11.11 diff --git a/src/meters.cc b/src/meters.cc index 0c675af..a1891f4 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -366,39 +366,6 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity, )); } -void MeterCommonImplementation::addNumericFieldWithExtractor( - string vname, - Quantity vquantity, - DifVifKey dif_vif_key, - VifScaling vif_scaling, - MeasurementType mt, - VIFRange vi, - StorageNr s, - TariffNr t, - IndexNr i, - PrintProperties print_properties, - string help, - function setValueFunc, - function getValueFunc) -{ - field_infos_.emplace_back( - FieldInfo(field_infos_.size(), - vname, - vquantity, - defaultUnitForQuantity(vquantity), - vif_scaling, - FieldMatcher::build().set(dif_vif_key).set(mt).set(vi).set(s).set(t).set(i), - help, - print_properties, - getValueFunc, - NULL, - setValueFunc, - NULL, - NoLookup, /* Lookup table */ - NULL /* Formula */ - )); -} - void MeterCommonImplementation::addNumericFieldWithExtractor(string vname, string help, PrintProperties print_properties, @@ -553,38 +520,6 @@ void MeterCommonImplementation::addNumericField( )); } -void MeterCommonImplementation::addStringFieldWithExtractor( - string vname, - Quantity vquantity, - DifVifKey dif_vif_key, - MeasurementType mt, - VIFRange vi, - StorageNr s, - TariffNr t, - IndexNr i, - PrintProperties print_properties, - string help, - function setValueFunc, - function getValueFunc) -{ - field_infos_.emplace_back( - FieldInfo(field_infos_.size(), - vname, - vquantity, - defaultUnitForQuantity(vquantity), - VifScaling::None, - FieldMatcher::build().set(dif_vif_key).set(mt).set(vi).set(s).set(t).set(i), - help, - print_properties, - NULL, - getValueFunc, - NULL, - setValueFunc, - NoLookup, /* Lookup table */ - NULL /* Formula */ - )); -} - void MeterCommonImplementation::addStringFieldWithExtractor(string vname, string help, PrintProperties print_properties, @@ -1104,44 +1039,44 @@ string findField(string key, vector *extra_constant_fields) } // Is the desired field one of the fields common to all meters and telegrams? -bool checkCommonField(string *buf, string field, Meter *m, Telegram *t, char c, bool human_readable) +bool checkCommonField(string *buf, string desired_field, Meter *m, Telegram *t, char c, bool human_readable) { - if (field == "name") + if (desired_field == "name") { *buf += m->name() + c; return true; } - if (field == "id") + if (desired_field == "id") { *buf += t->ids.back() + c; return true; } - if (field == "timestamp") + if (desired_field == "timestamp") { *buf += m->datetimeOfUpdateHumanReadable() + c; return true; } - if (field == "timestamp_lt") + if (desired_field == "timestamp_lt") { *buf += m->datetimeOfUpdateHumanReadable() + c; return true; } - if (field == "timestamp_utc") + if (desired_field == "timestamp_utc") { *buf += m->datetimeOfUpdateRobot() + c; return true; } - if (field == "timestamp_ut") + if (desired_field == "timestamp_ut") { *buf += m->unixTimestampOfUpdate() + c; return true; } - if (field == "device") + if (desired_field == "device") { *buf += t->about.device + c; return true; } - if (field == "rssi_dbm") + if (desired_field == "rssi_dbm") { *buf += to_string(t->about.rssi_dbm) + c; return true; @@ -1151,7 +1086,7 @@ bool checkCommonField(string *buf, string field, Meter *m, Telegram *t, char c, } // Is the desired field one of the meter printable fields? -bool checkPrintableField(string *buf, string desired_field_name, Meter *m, Telegram *t, char c, +bool checkPrintableField(string *buf, string desired_field, Meter *m, Telegram *t, char c, vector &fields, bool human_readable) { @@ -1160,7 +1095,7 @@ bool checkPrintableField(string *buf, string desired_field_name, Meter *m, Teleg if (fi.xuantity() == Quantity::Text) { // Strings are simply just print them. - if (desired_field_name == fi.vname()) + if (desired_field == fi.vname()) { *buf += m->getStringValue(&fi) + c; return true; @@ -1170,7 +1105,7 @@ bool checkPrintableField(string *buf, string desired_field_name, Meter *m, Teleg { string display_unit_s = unitToStringLowerCase(fi.displayUnit()); string var = fi.vname()+"_"+display_unit_s; - if (desired_field_name != var) continue; + if (desired_field != var) continue; // We have the correc field. if (fi.displayUnit() == Unit::DateLT) @@ -2729,6 +2664,18 @@ void MeterCommonImplementation::addOptionalCommonFields(string field_names) ); } + if (checkIf(fields,"parameter_set")) + { + addStringFieldWithExtractor( + "parameter_set", + "Parameter set for this meter.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ParameterSet) + ); + } + if (checkIf(fields,"customer")) { addStringFieldWithExtractor( diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 1614a3b..629e30f 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -123,21 +123,6 @@ protected: #define FIND_SFIELD_ST(TYPE,INFO,STORAGE,TARIFF) NoDifVifKey,TYPE,INFO,STORAGE,TARIFF,IndexNr(1) #define FIND_SFIELD_STI(TYPE,INFO,STORAGE,TARIFF,INDEX) NoDifVifKey,TYPE,INFO,STORAGE,TARIFF,INDEX - void addNumericFieldWithExtractor( - string vname, // Name of value without unit, eg total - Quantity vquantity, // Value belongs to this quantity. - DifVifKey dif_vif_key, // You can hardocde a dif vif header here or use NoDifVifKey - VifScaling vif_scaling, - MeasurementType mt, // If not using a hardcoded key, search for mt,vi,s,t and i instead. - VIFRange vi, - StorageNr s, - TariffNr t, - IndexNr i, - PrintProperties print_properties, // Should this be printed by default in fields,json and hr. - string help, - function setValueFunc, // Use the SET macro above. - function getValueFunc); // Use the GET macro above. - void addNumericFieldWithExtractor( string vname, // Name of value without unit, eg "total" "total_month{storagenr}" string help, // Information about this field. @@ -182,20 +167,6 @@ protected: #define SET_STRING_FUNC(varname) {[=](string s){varname = s;}} #define GET_STRING_FUNC(varname) {[=](){return varname; }} - void addStringFieldWithExtractor( - string vname, // Name of value without unit, eg total - Quantity vquantity, // Value belongs to this quantity. - DifVifKey dif_vif_key, // You can hardocde a dif vif header here or use NoDifVifKey - MeasurementType mt, // If not using a hardcoded key, search for mt,vi,s,t and i instead. - VIFRange vi, - StorageNr s, - TariffNr t, - IndexNr i, - PrintProperties print_properties, // Should this be printed by default in fields,json and hr. - string help, - function setValueFunc, // Use the SET_STRING macro above. - function getValueFunc); // Use the GET_STRING macro above. - void addStringFieldWithExtractor( string vname, string help, diff --git a/tests/test_calculate_dates.sh b/tests/test_calculate_dates.sh index 981ac0a..7ecdddb 100755 --- a/tests/test_calculate_dates.sh +++ b/tests/test_calculate_dates.sh @@ -43,6 +43,7 @@ cat > $TEST/test_expected.txt < 1671711132 # UTC time @@ -87,8 +88,10 @@ TZ=UTC+1 $PROG --format=json --ppjson \ --calculate_set_28_fromdhmsz_datetime="'2022-12-22T12:12:12Z' + 1 month" \ --calculate_set_29_fromdhmsz_datetime='1671711132 ut + 1 month'\ --calculate_set_30_from_setdate_datetime='set_date + 1 month'\ +\ + --calculate_set_31_from_setdate2_datetime="set_30_from_setdate_datetime + 1 month + 7 h + '00:33'"\ "$HEX" \ - GURKA sharky774 71942539 NOKEY | grep \"set_ > $TEST/test_output.txt + Moo sharky774 71942539 NOKEY | grep \"set_ > $TEST/test_output.txt if [ "$?" = "0" ] then