kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add error message detecting missing pidfile argument to daemon.
rodzic
cde87b9698
commit
781b084260
|
@ -34,13 +34,15 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
||||||
} else {
|
} else {
|
||||||
filename = argv[0];
|
filename = argv[0];
|
||||||
}
|
}
|
||||||
if (!strcmp(filename, "wmbusmetersd")) {
|
if (!strcmp(filename, "wmbusmetersd"))
|
||||||
|
{
|
||||||
c->daemon = true;
|
c->daemon = true;
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
error("Usage error: wmbusmetersd must have at least a single argument to the pid file.\n"
|
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");
|
"But you can also supply --device= and --listento= to override the config files.\n");
|
||||||
}
|
}
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
bool pid_file_found = false;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (argv[i] == NULL) break;
|
if (argv[i] == NULL) break;
|
||||||
|
@ -58,9 +60,14 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
c->pid_file = argv[i];
|
||||||
|
pid_file_found = true;
|
||||||
break;
|
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<Configuration>(c);
|
return shared_ptr<Configuration>(c);
|
||||||
}
|
}
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
|
|
|
@ -35,32 +35,19 @@
|
||||||
struct MeterHydrocalM3 : public virtual HeatMeter, public virtual MeterCommonImplementation {
|
struct MeterHydrocalM3 : public virtual HeatMeter, public virtual MeterCommonImplementation {
|
||||||
MeterHydrocalM3(MeterInfo &mi);
|
MeterHydrocalM3(MeterInfo &mi);
|
||||||
|
|
||||||
double totalEnergyConsumption(Unit u);
|
double totalHeatingEnergyConsumption(Unit u);
|
||||||
string status();
|
double totalHeatingVolume(Unit u);
|
||||||
double totalVolume(Unit u);
|
double totalCoolingEnergyConsumption(Unit u);
|
||||||
double volumeFlow(Unit u);
|
double totalCoolingVolume(Unit u);
|
||||||
|
|
||||||
// Water temperatures
|
|
||||||
double t1Temperature(Unit u);
|
|
||||||
bool hasT1Temperature();
|
|
||||||
double t2Temperature(Unit u);
|
|
||||||
bool hasT2Temperature();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processContent(Telegram *t);
|
void processContent(Telegram *t);
|
||||||
|
|
||||||
uchar info_codes_ {};
|
double total_heating_energy_kwh_ {};
|
||||||
double total_energy_kwh_ {};
|
double total_heating_volume_m3_ {};
|
||||||
double total_volume_m3_ {};
|
double total_cooling_energy_kwh_ {};
|
||||||
double volume_flow_m3h_ {};
|
double total_cooling_volume_m3_ {};
|
||||||
double t1_temperature_c_ { 127 };
|
string device_date_time_ {};
|
||||||
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_ {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MeterHydrocalM3::MeterHydrocalM3(MeterInfo &mi) :
|
MeterHydrocalM3::MeterHydrocalM3(MeterInfo &mi) :
|
||||||
|
@ -75,224 +62,74 @@ MeterHydrocalM3::MeterHydrocalM3(MeterInfo &mi) :
|
||||||
"The total energy consumption recorded by this meter.",
|
"The total energy consumption recorded by this meter.",
|
||||||
true, true);
|
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,
|
addPrint("total_volume", Quantity::Volume,
|
||||||
[&](Unit u){ return totalVolume(u); },
|
[&](Unit u){ return totalVolume(u); },
|
||||||
"Total volume of media.",
|
"Total volume of media.",
|
||||||
true, true);
|
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<HeatMeter> createHydrocalM3(MeterInfo &mi) {
|
shared_ptr<HeatMeter> createHydrocalM3(MeterInfo &mi) {
|
||||||
return shared_ptr<HeatMeter>(new MeterHydrocalM3(mi));
|
return shared_ptr<HeatMeter>(new MeterHydrocalM3(mi));
|
||||||
}
|
}
|
||||||
|
|
||||||
double MeterHydrocalM3::totalEnergyConsumption(Unit u)
|
double MeterHydrocalM3::totalHeatingEnergyConsumption(Unit u)
|
||||||
{
|
{
|
||||||
assertQuantity(u, Quantity::Energy);
|
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);
|
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);
|
assertQuantity(u, Quantity::Energy);
|
||||||
return convert(t1_temperature_c_, Unit::C, u);
|
return convert(total_cooling_energy_kwh_, Unit::KWH, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeterHydrocalM3::hasT1Temperature()
|
double MeterHydrocalM3::totalCoolingVolume(Unit u)
|
||||||
{
|
{
|
||||||
return has_t1_temperature_;
|
assertQuantity(u, Quantity::Volume);
|
||||||
}
|
return convert(total_cooling_volume_m3_, Unit::M3, u);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeterHydrocalM3::processContent(Telegram *t)
|
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;
|
int offset;
|
||||||
string key;
|
string key;
|
||||||
|
|
||||||
extractDVuint8(&t->values, "04FF22", &offset, &info_codes_);
|
// The meter either sends the total energy consumed as kWh or as MJ.
|
||||||
t->addMoreExplanation(offset, " info codes (%s)", status().c_str());
|
// First look for kwh
|
||||||
|
|
||||||
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_);
|
|
||||||
|
|
||||||
if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) {
|
if(findKey(MeasurementType::Instantaneous, ValueInformation::EnergyWh, 0, 0, &key, &t->values)) {
|
||||||
extractDVdouble(&t->values, key, &offset, &total_energy_kwh_);
|
extractDVdouble(&t->values, key, &offset, &total_heating_energy_kwh_);
|
||||||
t->addMoreExplanation(offset, " total energy consumption (%f kWh)", total_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)) {
|
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, 0, &key, &t->values)) {
|
||||||
extractDVdouble(&t->values, key, &offset, &total_volume_m3_);
|
extractDVdouble(&t->values, key, &offset, &total_heating_volume_m3_);
|
||||||
t->addMoreExplanation(offset, " total volume (%f m3)", total_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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include"util.h"
|
#include"util.h"
|
||||||
#include"meters.h"
|
#include"meters.h"
|
||||||
#include"shell.h"
|
#include"shell.h"
|
||||||
|
#include"version.h"
|
||||||
|
|
||||||
#include<algorithm>
|
#include<algorithm>
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
|
@ -307,7 +308,7 @@ bool enableLogfile(string logfile, bool daemon)
|
||||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&now));
|
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (daemon) {
|
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) {
|
if (n == 0) {
|
||||||
logfile_enabled_ = false;
|
logfile_enabled_ = false;
|
||||||
return false;
|
return false;
|
||||||
|
|
Ładowanie…
Reference in New Issue