From 781b084260e60445c67218449f71712e5e2bb1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Thu, 31 Dec 2020 10:18:43 +0100 Subject: [PATCH] Add error message detecting missing pidfile argument to daemon. --- src/cmdline.cc | 11 +- src/meter_hydrocalm3.cc | 251 +++++++--------------------------------- src/util.cc | 3 +- 3 files changed, 55 insertions(+), 210 deletions(-) diff --git a/src/cmdline.cc b/src/cmdline.cc index a3b4c20..bcd58e0 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -34,13 +34,15 @@ shared_ptr parseCommandLine(int argc, char **argv) { } else { filename = argv[0]; } - if (!strcmp(filename, "wmbusmetersd")) { + if (!strcmp(filename, "wmbusmetersd")) + { c->daemon = true; if (argc < 2) { error("Usage error: wmbusmetersd must have at least a single argument to the pid file.\n" "But you can also supply --device= and --listento= to override the config files.\n"); } int i = 1; + bool pid_file_found = false; for (;;) { if (argv[i] == NULL) break; @@ -58,9 +60,14 @@ shared_ptr parseCommandLine(int argc, char **argv) { i++; continue; } + c->pid_file = argv[i]; + pid_file_found = true; break; } - c->pid_file = argv[i]; + if (!pid_file_found) + { + error("Usage error: you must supply the pid file as the argument to wmbusmetersd.\n"); + } return shared_ptr(c); } if (argc < 2) { diff --git a/src/meter_hydrocalm3.cc b/src/meter_hydrocalm3.cc index e89572f..ef481aa 100644 --- a/src/meter_hydrocalm3.cc +++ b/src/meter_hydrocalm3.cc @@ -35,32 +35,19 @@ struct MeterHydrocalM3 : public virtual HeatMeter, public virtual MeterCommonImplementation { MeterHydrocalM3(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(); + double totalHeatingEnergyConsumption(Unit u); + double totalHeatingVolume(Unit u); + double totalCoolingEnergyConsumption(Unit u); + double totalCoolingVolume(Unit u); 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_ {}; + double total_heating_energy_kwh_ {}; + double total_heating_volume_m3_ {}; + double total_cooling_energy_kwh_ {}; + double total_cooling_volume_m3_ {}; + string device_date_time_ {}; }; MeterHydrocalM3::MeterHydrocalM3(MeterInfo &mi) : @@ -75,224 +62,74 @@ MeterHydrocalM3::MeterHydrocalM3(MeterInfo &mi) : "The total energy consumption recorded by this meter.", true, true); + addPrint("device_date_time", Quantity::Text, + [&](){ return device_date_time_; }, + "Date when total energy consumption was recorded.", + false, true); + addPrint("total_volume", Quantity::Volume, [&](Unit u){ return totalVolume(u); }, "Total volume of media.", true, true); - - addPrint("volume_flow", Quantity::Flow, - [&](Unit u){ return volumeFlow(u); }, - "The current flow.", - true, true); - - addPrint("t1_temperature", Quantity::Temperature, - [&](Unit u){ return t1Temperature(u); }, - "The T1 temperature.", - true, true); - - addPrint("t2_temperature", Quantity::Temperature, - [&](Unit u){ return t2Temperature(u); }, - "The T2 temperature.", - true, true); - - addPrint("at_date", Quantity::Text, - [&](){ return target_date_; }, - "Date when total energy consumption was recorded.", - false, true); - - addPrint("current_status", Quantity::Text, - [&](){ return status(); }, - "Status of meter.", - true, true); - - addPrint("energy_forward_kwh", Quantity::Text, - [&](){ return to_string(energy_forward_kwh_); }, - "Energy forward.", - false, true); - - addPrint("energy_returned_kwh", Quantity::Text, - [&](){ return to_string(energy_returned_kwh_); }, - "Energy returned.", - false, true); - } shared_ptr createHydrocalM3(MeterInfo &mi) { return shared_ptr(new MeterHydrocalM3(mi)); } -double MeterHydrocalM3::totalEnergyConsumption(Unit u) +double MeterHydrocalM3::totalHeatingEnergyConsumption(Unit u) { assertQuantity(u, Quantity::Energy); - return convert(total_energy_kwh_, Unit::KWH, u); + return convert(total_heating_energy_kwh_, Unit::KWH, u); } -double MeterHydrocalM3::totalVolume(Unit u) +double MeterHydrocalM3::totalHeatingVolume(Unit u) { assertQuantity(u, Quantity::Volume); - return convert(total_volume_m3_, Unit::M3, u); + return convert(total_heating_volume_m3_, Unit::M3, u); } -double MeterHydrocalM3::t1Temperature(Unit u) +double MeterHydrocalM3::totalCoolingEnergyConsumption(Unit u) { - assertQuantity(u, Quantity::Temperature); - return convert(t1_temperature_c_, Unit::C, u); + assertQuantity(u, Quantity::Energy); + return convert(total_cooling_energy_kwh_, Unit::KWH, u); } -bool MeterHydrocalM3::hasT1Temperature() +double MeterHydrocalM3::totalCoolingVolume(Unit u) { - return has_t1_temperature_; -} - -double MeterHydrocalM3::t2Temperature(Unit u) -{ - assertQuantity(u, Quantity::Temperature); - return convert(t2_temperature_c_, Unit::C, u); -} - -bool MeterHydrocalM3::hasT2Temperature() -{ - return has_t2_temperature_; -} - -double MeterHydrocalM3::volumeFlow(Unit u) -{ - assertQuantity(u, Quantity::Flow); - return convert(volume_flow_m3h_, Unit::M3H, u); + assertQuantity(u, Quantity::Volume); + return convert(total_cooling_volume_m3_, Unit::M3, u); } void MeterHydrocalM3::processContent(Telegram *t) { - /* - (multical603) 13: 78 tpl-ci-field (EN 13757-3 Application Layer (no tplh)) - (multical603) 14: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 15: 06 vif (Energy kWh) - (multical603) 16: * A5000000 total energy consumption (165.000000 kWh) - (multical603) 1a: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 1b: FF vif (Vendor extension) - (multical603) 1c: 07 vife (?) - (multical603) 1d: 2B010000 - (multical603) 21: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 22: FF vif (Vendor extension) - (multical603) 23: 08 vife (?) - (multical603) 24: 9C000000 - (multical603) 28: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 29: 14 vif (Volume 10⁻² m³) - (multical603) 2a: * 21020000 total volume (5.450000 m3) - (multical603) 2e: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 2f: 3B vif (Volume flow l/h) - (multical603) 30: * 12000000 volume flow (0.018000 m3/h) - (multical603) 34: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical603) 35: 59 vif (Flow temperature 10⁻² °C) - (multical603) 36: * D014 T1 flow temperature (53.280000 °C) - (multical603) 38: 02 dif (16 Bit Integer/Binary Instantaneous value) - (multical603) 39: 5D vif (Return temperature 10⁻² °C) - (multical603) 3a: * 0009 T2 flow temperature (23.040000 °C) - (multical603) 3c: 04 dif (32 Bit Integer/Binary Instantaneous value) - (multical603) 3d: FF vif (Vendor extension) - (multical603) 3e: 22 vife (per hour) - (multical603) 3f: * 00000000 info codes () - - (supercom587) 00: 8e length (142 bytes) - (supercom587) 01: 44 dll-c (from meter SND_NR) - (supercom587) 02: b409 dll-mfct (BMT) - (supercom587) 04: 71493602 dll-id (02364971) - (supercom587) 08: 0b dll-version - (supercom587) 09: 0d dll-type (Heat/Cooling load meter) - (supercom587) 0a: 7a tpl-ci-field (EN 13757-3 Application Layer (short tplh)) - (supercom587) 0b: b6 tpl-acc-field - (supercom587) 0c: 00 tpl-sts-field - (supercom587) 0d: 8005 tpl-cfg 0580 (AES_CBC_IV nb=8 cntn=0 ra=0 hc=0 ) - (supercom587) 0f: 2f2f decrypt check bytes - (supercom587) 11: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 12: 0E vif (Energy MJ) - (supercom587) 13: 00000000 - (supercom587) 17: 04 dif (32 Bit Integer/Binary Instantaneous value) - (supercom587) 18: 6D vif (Date and time type) - (supercom587) 19: 112D872C - (supercom587) 1d: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 1e: 13 vif (Volume l) - (supercom587) 1f: * 00000000 total consumption (0.000000 m3) - (supercom587) 23: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 24: 0E vif (Energy MJ) - (supercom587) 25: 00000000 - (supercom587) 29: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 2a: 13 vif (Volume l) - (supercom587) 2b: 00000000 - (supercom587) 2f: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 30: 13 vif (Volume l) - (supercom587) 31: 00000000 - (supercom587) 35: 0C dif (8 digit BCD Instantaneous value) - (supercom587) 36: 13 vif (Volume l) - (supercom587) 37: 00000000 - (supercom587) 3b: 0A dif (4 digit BCD Instantaneous value) - (supercom587) 3c: 5A vif (Flow temperature 10⁻¹ °C) - (supercom587) 3d: 9400 - (supercom587) 3f: 0A dif (4 digit BCD Instantaneous value) - (supercom587) 40: 5E vif (Return temperature 10⁻¹ °C) - (supercom587) 41: 9500 - (supercom587) 43: 0F manufacturer specific data - -*/ int offset; string key; - extractDVuint8(&t->values, "04FF22", &offset, &info_codes_); - t->addMoreExplanation(offset, " info codes (%s)", status().c_str()); - - extractDVuint32(&t->values, "04FF07", &offset, &energy_forward_kwh_); - t->addMoreExplanation(offset, " something A (%zu)", energy_forward_kwh_); - - extractDVuint32(&t->values, "04FF08", &offset, &energy_returned_kwh_); - t->addMoreExplanation(offset, " something B (%zu)", energy_returned_kwh_); - + // The meter either sends the total energy consumed as kWh or as MJ. + // First look for kwh if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) { - extractDVdouble(&t->values, key, &offset, &total_energy_kwh_); - t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_energy_kwh_); + extractDVdouble(&t->values, key, &offset, &total_heating_energy_kwh_); + t->addMoreExplanation(offset, " total heating energy consumption (%f kWh)", total_heating_energy_kwh_); + } + // Then look for mj. + if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyMJ, 0, 0, &key, &t->values)) { + double mj; + extractDVdouble(&t->values, key, &offset, &mj); + total_heating_energy_kwh_ = convert(mj, Unit::MJ, Unit::KWH); + t->addMoreExplanation(offset, " total heating_energy consumption (%f MJ = %f kWh)", mj, total_heating_energy_kwh_); + } + + if (findKey(MeasurementType::Instantaneous, ValueInformation::DateTime, 0, 0, &key, &t->values)) { + struct tm datetime; + extractDVdate(&t->values, key, &offset, &datetime); + device_date_time_ = strdatetime(&datetime); + t->addMoreExplanation(offset, " device date time (%s)", device_date_time_.c_str()); } if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, 0, &key, &t->values)) { - extractDVdouble(&t->values, key, &offset, &total_volume_m3_); - t->addMoreExplanation(offset, " total volume (%f m3)", total_volume_m3_); + extractDVdouble(&t->values, key, &offset, &total_heating_volume_m3_); + t->addMoreExplanation(offset, " total heating_volume (%f m3)", total_heating_volume_m3_); } - if(findKey(MeasurementType::Unknown, ValueInformation::VolumeFlow, 0, 0, &key, &t->values)) { - extractDVdouble(&t->values, key, &offset, &volume_flow_m3h_); - t->addMoreExplanation(offset, " volume flow (%f m3/h)", volume_flow_m3h_); - } - - if(findKey(MeasurementType::Instantaneous, ValueInformation::FlowTemperature, 0, 0, &key, &t->values)) { - has_t1_temperature_ = extractDVdouble(&t->values, key, &offset, &t1_temperature_c_); - t->addMoreExplanation(offset, " T1 flow temperature (%f °C)", t1_temperature_c_); - } - - if(findKey(MeasurementType::Instantaneous, ValueInformation::ReturnTemperature, 0, 0, &key, &t->values)) { - has_t2_temperature_ = extractDVdouble(&t->values, key, &offset, &t2_temperature_c_); - t->addMoreExplanation(offset, " T2 flow temperature (%f °C)", t2_temperature_c_); - } - - if (findKey(MeasurementType::Unknown, ValueInformation::Date, 0, 0, &key, &t->values)) { - struct tm datetime; - extractDVdate(&t->values, key, &offset, &datetime); - target_date_ = strdatetime(&datetime); - t->addMoreExplanation(offset, " target date (%s)", target_date_.c_str()); - } -} - -string MeterHydrocalM3::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/util.cc b/src/util.cc index d45f651..2039b70 100644 --- a/src/util.cc +++ b/src/util.cc @@ -18,6 +18,7 @@ #include"util.h" #include"meters.h" #include"shell.h" +#include"version.h" #include #include @@ -307,7 +308,7 @@ bool enableLogfile(string logfile, bool daemon) strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&now)); int n = 0; if (daemon) { - n = fprintf(output, "(wmbusmeters) logging started %s\n", buf); + n = fprintf(output, "(wmbusmeters) logging started %s using " VERSION "\n", buf); if (n == 0) { logfile_enabled_ = false; return false;