Added support for multiple comma separated ids.

pull/22/head
weetmuts 2019-03-05 21:19:05 +01:00
rodzic 87c4cb9256
commit 7e72fe0f3f
24 zmienionych plików z 266 dodań i 147 usunięć

Wyświetl plik

@ -45,6 +45,9 @@ check with `tail -f /var/log/syslog` and `tail -f /var/log/wmbusmeters/wmbusmete
The latest reading of the meter can also be found here: /var/log/wmbusmeters/meter_readings/MyTapWater
You can use several ids using `id=1111111,2222222,3333333` or you can listen to all
meters of a certain type `id=*`.
# Run using config files
If you cannot install as a daemon, then you can also start

Wyświetl plik

@ -0,0 +1,6 @@
telegram=|314493441234567835087a740000200b6e2701004b6e450100426c5f2ccb086e790000c2086c7f21326cffff046d200b7422|
{"media":"heat_cost_allocation","meter":"qcaloric","name":"Element","id":"78563412","current_consumption_hca":127.000000,"set_date":"2018-12-31","consumption_at_set_date_hca":145.000000,"set_date_17":"2019-01-31","consumption_at_set_date_17_hca":79.000000,"error_date":"2127-15-31","device_date_time":"2019-02-20 11:32","timestamp":"1111-11-11T11:11:11Z"}
telegram=|314493441334567835087a740000200b6e2701004b6e450100426c5f2ccb086e790000c2086c7f21326cffff046d200b7422|
{"media":"heat_cost_allocation","meter":"qcaloric","name":"Element","id":"78563413","current_consumption_hca":127.000000,"set_date":"2018-12-31","consumption_at_set_date_hca":145.000000,"set_date_17":"2019-01-31","consumption_at_set_date_17_hca":79.000000,"error_date":"2127-15-31","device_date_time":"2019-02-20 11:32","timestamp":"1111-11-11T11:11:11Z"}
telegram=|314493441434567835087a740000200b6e2701004b6e450100426c5f2ccb086e790000c2086c7f21326cffff046d200b7422|
{"media":"heat_cost_allocation","meter":"qcaloric","name":"Element","id":"78563414","current_consumption_hca":127.000000,"set_date":"2018-12-31","consumption_at_set_date_hca":145.000000,"set_date_17":"2019-01-31","consumption_at_set_date_17_hca":79.000000,"error_date":"2127-15-31","device_date_time":"2019-02-20 11:32","timestamp":"1111-11-11T11:11:11Z"}

Wyświetl plik

@ -37,7 +37,7 @@
using namespace std;
void oneshotCheck(Configuration *cmdline, SerialCommunicationManager *manager, Meter *meter, vector<unique_ptr<Meter>> &meters);
void oneshotCheck(Configuration *cmdline, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters);
void startUsingCommandline(Configuration *cmdline);
void startUsingConfigFiles(string root, bool is_daemon);
void startDaemon(string pid_file); // Will use config files.
@ -277,7 +277,8 @@ void startUsingCommandline(Configuration *config)
if (config->list_shell_envs) {
string ignore1, ignore2, ignore3;
vector<string> envs;
meters.back()->printMeter("",
Telegram t;
meters.back()->printMeter(&t,
&ignore1,
&ignore2, config->separator,
&ignore3,
@ -290,8 +291,8 @@ void startUsingCommandline(Configuration *config)
}
exit(0);
}
meters.back()->onUpdate([&](string id, Meter* meter) { output->print(id,meter); });
// meters.back()->onUpdate([&](string id, Meter* meter) { oneshotCheck(config, manager.get(), meter, meters); });
meters.back()->onUpdate([&](Telegram*t,Meter* meter) { output->print(t,meter); });
meters.back()->onUpdate([&](Telegram*t, Meter* meter) { oneshotCheck(config, manager.get(), t, meter, meters); });
}
} else {
notice("No meters configured. Printing id:s of all telegrams heard!\n\n");
@ -314,7 +315,7 @@ void startUsingCommandline(Configuration *config)
}
}
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Meter *meter, vector<unique_ptr<Meter>> &meters)
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters)
{
if (!config->oneshot) return;
@ -322,6 +323,7 @@ void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Me
if (m->numUpdates() == 0) return;
}
// All meters have received at least one update! Stop!
verbose("(main) all meters have received at least one update, stopping.\n");
manager->stop();
}

Wyświetl plik

@ -55,7 +55,7 @@ struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImpleme
string timeLeaking();
string timeBursting();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -70,8 +70,10 @@ private:
};
MeterIperl::MeterIperl(WMBus *bus, string& name, string& id, string& key) :
MeterCommonImplementation(bus, name, id, key, IPERL_METER, MANUFACTURER_SEN, 0x16, LinkModeT1)
MeterCommonImplementation(bus, name, id, key, IPERL_METER, MANUFACTURER_SEN, LinkModeT1)
{
addMedia(0x06);
addMedia(0x07);
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
}
@ -98,15 +100,7 @@ void MeterIperl::handleTelegram(Telegram *t)
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x07 && t->a_field_device_type != 0x06) {
warning("(%s) expected telegram for cold or warm water media, but got \"%s\"!\n", "iperl",
mediaType(t->m_field, t->a_field_device_type).c_str());
}
updateMedia(t->a_field_device_type);
if (t->m_field != manufacturer() ||
t->a_field_version != 0x68) {
if (t->a_field_version != 0x68) {
warning("(%s) expected telegram from SEN meter with version 0x%02x, "
"but got \"%s\" meter with version 0x%02x !\n", "iperl",
0x68,
@ -149,7 +143,7 @@ void MeterIperl::processContent(Telegram *t)
t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_);
}
void MeterIperl::printMeter(string id,
void MeterIperl::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -164,7 +158,7 @@ void MeterIperl::printMeter(string id,
"% 3.3f m3\t"
"%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
datetimeOfUpdateHumanReadable().c_str());
@ -176,7 +170,7 @@ void MeterIperl::printMeter(string id,
"%f%c"
"%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
totalWaterConsumption(), separator,
datetimeOfUpdateRobot().c_str());
@ -194,9 +188,9 @@ void MeterIperl::printMeter(string id,
Q(total_m3,%f)
QSE(timestamp,%s)
"}",
mediaType(manufacturer(), media()).c_str(),
mediaType(manufacturer(), t->a_field_device_type).c_str(),
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
datetimeOfUpdateRobot().c_str());
@ -204,7 +198,7 @@ void MeterIperl::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=iperl"));
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_TOTAL_M3=")+to_string(totalWaterConsumption()));
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());
}

Wyświetl plik

@ -77,7 +77,7 @@ struct MeterMultical21 : public virtual WaterMeter, public virtual MeterCommonIm
string timeLeaking();
string timeBursting();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -105,8 +105,10 @@ private:
};
MeterMultical21::MeterMultical21(WMBus *bus, string& name, string& id, string& key, MeterType mt) :
MeterCommonImplementation(bus, name, id, key, mt, MANUFACTURER_KAM, 0x16, LinkModeC1)
MeterCommonImplementation(bus, name, id, key, mt, MANUFACTURER_KAM, LinkModeC1)
{
addMedia(0x16); // Water media
if (type() == MULTICAL21_METER) {
expected_version_ = 0x1b;
meter_name_ = "multical21";
@ -200,13 +202,7 @@ void MeterMultical21::handleTelegram(Telegram *t)
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x16) {
warning("(%s) expected telegram for water media, but got \"%s\"!\n", meter_name_,
mediaType(t->m_field, t->a_field_device_type).c_str());
}
if (t->m_field != manufacturer() ||
t->a_field_version != expected_version_) {
if (t->a_field_version != expected_version_) {
warning("(%s) expected telegram from KAM meter with version 0x%02x, "
"but got \"%s\" meter with version 0x%02x !\n", meter_name_,
expected_version_,
@ -496,7 +492,7 @@ string MeterMultical21::decodeTime(int time)
}
}
void MeterMultical21::printMeter(string id,
void MeterMultical21::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -525,7 +521,7 @@ void MeterMultical21::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f m3\t% 3.3f m3\t% 3.3f m3/h\t%s°C\t%s°C\t%s\t%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
targetWaterConsumption(),
maxFlow(),
@ -538,7 +534,7 @@ void MeterMultical21::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s%c" "%s%c" "%f%c" "%f%c" "%f%c" "%.0f%c" "%.0f%c" "%s%c" "%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
totalWaterConsumption(), separator,
targetWaterConsumption(), separator,
maxFlow(), separator,
@ -570,10 +566,10 @@ void MeterMultical21::printMeter(string id,
QS(time_bursting,%s)
QSE(timestamp,%s)
"}",
mediaType(manufacturer(), media()).c_str(),
mediaType(manufacturer(), t->a_field_device_type).c_str(),
meter_name_,
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
targetWaterConsumption(),
maxFlow(),
@ -590,7 +586,7 @@ void MeterMultical21::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=")+meter_name_);
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_TOTAL_M3=")+to_string(totalWaterConsumption()));
envs->push_back(string("METER_TARGET_M3=")+to_string(targetWaterConsumption()));
envs->push_back(string("METER_MAX_FLOW_M3H=")+to_string(maxFlow()));

Wyświetl plik

@ -35,7 +35,7 @@ struct MeterMultical302 : public virtual HeatMeter, public virtual MeterCommonIm
double totalVolume();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -51,8 +51,9 @@ private:
};
MeterMultical302::MeterMultical302(WMBus *bus, string& name, string& id, string& key) :
MeterCommonImplementation(bus, name, id, key, MULTICAL302_METER, MANUFACTURER_KAM, 0x04, LinkModeC1)
MeterCommonImplementation(bus, name, id, key, MULTICAL302_METER, MANUFACTURER_KAM, LinkModeC1)
{
addMedia(0x04); // Heat media
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
}
@ -83,18 +84,6 @@ void MeterMultical302::handleTelegram(Telegram *t) {
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x04) {
warning("(multical302) expected telegram for heat media, but got \"%s\"!\n",
mediaType(t->m_field, t->a_field_device_type).c_str());
}
/*
if (t->m_field != manufacturer() ||
t->a_field_version != 0x1b) {
warning("(multical302) expected telegram from KAM meter with version 0x1b, but got \"%s\" version 0x2x !\n",
manufacturerFlag(t->m_field).c_str(), t->a_field_version);
}*/
if (useAes()) {
vector<uchar> aeskey = key();
decryptMode1_AES_CTR(t, aeskey);
@ -183,7 +172,7 @@ unique_ptr<HeatMeter> createMultical302(WMBus *bus, string& name, string& id, st
return unique_ptr<HeatMeter>(new MeterMultical302(bus,name,id,key));
}
void MeterMultical302::printMeter(string id,
void MeterMultical302::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -194,7 +183,7 @@ void MeterMultical302::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f kwh\t% 3.3f m3\t% 3.3f kwh\t%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalEnergyConsumption(),
totalVolume(),
currentPowerConsumption(),
@ -204,7 +193,7 @@ void MeterMultical302::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s%c%s%c%f%c%f%c%f%c%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
totalEnergyConsumption(), separator,
totalVolume(), separator,
currentPowerConsumption(), separator,
@ -227,7 +216,7 @@ void MeterMultical302::printMeter(string id,
QSE(timestamp,%s)
"}",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalEnergyConsumption(),
totalVolume(),
currentPowerConsumption(),
@ -237,7 +226,7 @@ void MeterMultical302::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=multical302"));
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_TOTAL_KWH=")+to_string(totalEnergyConsumption()));
envs->push_back(string("METER_TOTAL_VOLUME_M3=")+to_string(totalVolume()));
envs->push_back(string("METER_CURRENT_KW=")+to_string(currentPowerConsumption()));

Wyświetl plik

@ -35,7 +35,7 @@ struct MeterOmnipower : public virtual ElectricityMeter, public virtual MeterCom
double totalEnergyConsumption();
double currentPowerConsumption();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -50,8 +50,9 @@ private:
};
MeterOmnipower::MeterOmnipower(WMBus *bus, string& name, string& id, string& key) :
MeterCommonImplementation(bus, name, id, key, OMNIPOWER_METER, MANUFACTURER_KAM, 0x04, LinkModeC1)
MeterCommonImplementation(bus, name, id, key, OMNIPOWER_METER, MANUFACTURER_KAM, LinkModeC1)
{
addMedia(0x02);
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
}
@ -77,13 +78,7 @@ void MeterOmnipower::handleTelegram(Telegram *t) {
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x02) {
warning("(omnipower) expected telegram for electricity media, but got \"%s\"!\n",
mediaType(t->m_field, t->a_field_device_type).c_str());
}
if (t->m_field != manufacturer() ||
t->a_field_version != 0x01) {
if (t->a_field_version != 0x01) {
warning("(omnipower) expected telegram from KAM meter with version 0x01, but got \"%s\" version 0x2x !\n",
manufacturerFlag(t->m_field).c_str(), t->a_field_version);
}
@ -124,7 +119,7 @@ unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, string& name, string& i
return unique_ptr<ElectricityMeter>(new MeterOmnipower(bus,name,id,key));
}
void MeterOmnipower::printMeter(string id,
void MeterOmnipower::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -136,7 +131,7 @@ void MeterOmnipower::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f kwh\t% 3.3f kwh\t%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalEnergyConsumption(),
currentPowerConsumption(),
datetimeOfUpdateHumanReadable().c_str());
@ -145,7 +140,7 @@ void MeterOmnipower::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s%c%s%c%f%c%f%c%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
totalEnergyConsumption(), separator,
currentPowerConsumption(), separator,
datetimeOfUpdateRobot().c_str());
@ -166,7 +161,7 @@ void MeterOmnipower::printMeter(string id,
QSE(timestamp,%s)
"}",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalEnergyConsumption(),
currentPowerConsumption(),
datetimeOfUpdateRobot().c_str());
@ -175,7 +170,7 @@ void MeterOmnipower::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=omnipower"));
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_TOTAL_KWH=")+to_string(totalEnergyConsumption()));
envs->push_back(string("METER_CURRENT_KW=")+to_string(currentPowerConsumption()));
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());

Wyświetl plik

@ -36,7 +36,7 @@ struct MeterQCaloric : public virtual HeatCostMeter, public virtual MeterCommonI
string setDate();
double consumptionAtSetDate();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -60,8 +60,9 @@ private:
};
MeterQCaloric::MeterQCaloric(WMBus *bus, string& name, string& id, string& key) :
MeterCommonImplementation(bus, name, id, key, QCALORIC_METER, MANUFACTURER_QDS, 0x08, LinkModeC1)
MeterCommonImplementation(bus, name, id, key, QCALORIC_METER, MANUFACTURER_QDS, LinkModeC1)
{
addMedia(0x08);
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
}
@ -92,14 +93,8 @@ void MeterQCaloric::handleTelegram(Telegram *t) {
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x08) {
warning("(qcaloric) expected telegram for heat cost allocator, but got \"%s\"!\n",
mediaType(t->m_field, t->a_field_device_type).c_str());
}
if (t->m_field != manufacturer() ||
t->a_field_version != 0x35) {
warning("(qcaloric) expected telegram from QDS meter with version 0x01, but got \"%s\" version 0x%02x !\n",
if (t->a_field_version != 0x35) {
warning("(qcaloric) expected telegram from QDS meter with version 0x35, but got \"%s\" version 0x%02x !\n",
manufacturerFlag(t->m_field).c_str(), t->a_field_version);
}
@ -227,7 +222,7 @@ unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, string& name, string& id, s
return unique_ptr<HeatCostMeter>(new MeterQCaloric(bus,name,id,key));
}
void MeterQCaloric::printMeter(string id,
void MeterQCaloric::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -239,7 +234,7 @@ void MeterQCaloric::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.0f hca\t%s\t% 3.0f hca\t%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
currentConsumption(),
setDate().c_str(),
consumptionAtSetDate(),
@ -249,7 +244,7 @@ void MeterQCaloric::printMeter(string id,
snprintf(buf, sizeof(buf)-1, "%s%c%s%c%f%c%s%c%f%c%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
currentConsumption(), separator,
setDate().c_str(), separator,
consumptionAtSetDate(), separator,
@ -276,7 +271,7 @@ void MeterQCaloric::printMeter(string id,
QSE(timestamp,%s)
"}",
name().c_str(),
id.c_str(),
t->id.c_str(),
currentConsumption(),
setDate().c_str(),
consumptionAtSetDate(),
@ -290,7 +285,7 @@ void MeterQCaloric::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=qcaloric"));
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_CURRENT_CONSUMPTION_HCA=")+to_string(currentConsumption()));
envs->push_back(string("METER_SET_DATE=")+setDate());
envs->push_back(string("METER_CONSUMPTION_AT_SET_DATE_HCA=")+to_string(consumptionAtSetDate()));

Wyświetl plik

@ -54,7 +54,7 @@ struct MeterSupercom587 : public virtual WaterMeter, public virtual MeterCommonI
string timeLeaking();
string timeBursting();
void printMeter(string id,
void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -69,8 +69,10 @@ private:
};
MeterSupercom587::MeterSupercom587(WMBus *bus, string& name, string& id, string& key) :
MeterCommonImplementation(bus, name, id, key, SUPERCOM587_METER, MANUFACTURER_SON, 0x16, LinkModeT1)
MeterCommonImplementation(bus, name, id, key, SUPERCOM587_METER, MANUFACTURER_SON, LinkModeT1)
{
addMedia(0x06);
addMedia(0x07);
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
}
@ -97,15 +99,7 @@ void MeterSupercom587::handleTelegram(Telegram *t)
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
t->a_field_address[3]);
if (t->a_field_device_type != 0x07 && t->a_field_device_type != 0x06) {
warning("(%s) expected telegram for cold or warm water media, but got \"%s\"!\n", "supercom587",
mediaType(t->m_field, t->a_field_device_type).c_str());
}
updateMedia(t->a_field_device_type);
if (t->m_field != manufacturer() ||
t->a_field_version != 0x3c) {
if (t->a_field_version != 0x3c) {
warning("(%s) expected telegram from SON meter with version 0x%02x, "
"but got \"%s\" meter with version 0x%02x !\n", "supercom587",
0x3c,
@ -144,7 +138,7 @@ void MeterSupercom587::processContent(Telegram *t)
t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_);
}
void MeterSupercom587::printMeter(string id,
void MeterSupercom587::printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,
@ -159,7 +153,7 @@ void MeterSupercom587::printMeter(string id,
"% 3.3f m3\t"
"%s",
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
datetimeOfUpdateHumanReadable().c_str());
@ -171,7 +165,7 @@ void MeterSupercom587::printMeter(string id,
"%f%c"
"%s",
name().c_str(), separator,
id.c_str(), separator,
t->id.c_str(), separator,
totalWaterConsumption(), separator,
datetimeOfUpdateRobot().c_str());
@ -189,9 +183,9 @@ void MeterSupercom587::printMeter(string id,
Q(total_m3,%f)
QSE(timestamp,%s)
"}",
mediaType(manufacturer(), media()).c_str(),
mediaType(manufacturer(), t->a_field_device_type).c_str(),
name().c_str(),
id.c_str(),
t->id.c_str(),
totalWaterConsumption(),
datetimeOfUpdateRobot().c_str());
@ -199,7 +193,7 @@ void MeterSupercom587::printMeter(string id,
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_TYPE=supercom587"));
envs->push_back(string("METER_ID=")+id);
envs->push_back(string("METER_ID=")+t->id);
envs->push_back(string("METER_TOTAL_M3=")+to_string(totalWaterConsumption()));
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());
}

Wyświetl plik

@ -21,13 +21,13 @@
#include<memory.h>
MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, string& name, string& id, string& key,
MeterType type, int manufacturer, int media,
MeterType type, int manufacturer,
LinkMode required_link_mode) :
type_(type), manufacturer_(manufacturer), media_(media), name_(name), bus_(bus),
type_(type), manufacturer_(manufacturer), name_(name), bus_(bus),
required_link_mode_(required_link_mode)
{
use_aes_ = true;
id_ = id;
ids_ = splitIds(id);
if (key.length() == 0) {
use_aes_ = false;
} else {
@ -45,14 +45,19 @@ int MeterCommonImplementation::manufacturer()
return manufacturer_;
}
int MeterCommonImplementation::media()
vector<int> MeterCommonImplementation::media()
{
return media_;
}
string MeterCommonImplementation::id()
void MeterCommonImplementation::addMedia(int m)
{
return id_;
media_.push_back(m);
}
vector<string> MeterCommonImplementation::ids()
{
return ids_;
}
string MeterCommonImplementation::name()
@ -70,7 +75,7 @@ LinkMode MeterCommonImplementation::requiredLinkMode()
return required_link_mode_;
}
void MeterCommonImplementation::onUpdate(function<void(string,Meter*)> cb)
void MeterCommonImplementation::onUpdate(function<void(Telegram*,Meter*)> cb)
{
on_update_.push_back(cb);
}
@ -125,16 +130,46 @@ LinkMode toMeterLinkMode(string& type)
bool MeterCommonImplementation::isTelegramForMe(Telegram *t)
{
if (manufacturer_ != 0 && t->m_field != manufacturer_) {
debug("(meter) %s: for me? %s\n", name_.c_str(), t->id.c_str());
bool id_match = false;
for (auto id : ids_)
{
if (id == t->id) {
id_match = true;
break;
}
if (id == "*") {
id_match = true;
break;
}
}
if (!id_match) {
debug("(meter) %s: not for me: not my id\n", name_.c_str());
return false;
}
if (id_ == t->id) {
return true;
if (manufacturer_ != 0 && t->m_field != manufacturer_) {
debug("(meter) %s: not for me: manufacturer differs\n", name_.c_str());
return false;
}
if (id_ == "*") {
return true;
bool media_match = false;
for (auto m : media_) {
if (m == t->a_field_device_type) {
media_match = true;
break;
}
}
return false;
if (!media_match) {
debug("(meter) %s: not for me: no media match\n", name_.c_str());
return false;
}
debug("(meter) %s: yes for me\n", name_.c_str());
return true;
}
bool MeterCommonImplementation::useAes()
@ -171,11 +206,6 @@ void MeterCommonImplementation::triggerUpdate(Telegram *t)
{
datetime_of_update_ = time(NULL);
num_updates_++;
for (auto &cb : on_update_) if (cb) cb(t->id, this);
for (auto &cb : on_update_) if (cb) cb(t, this);
t->handled = true;
}
void MeterCommonImplementation::updateMedia(int media)
{
media_ = media;
}

Wyświetl plik

@ -37,21 +37,21 @@ using namespace std;
typedef unsigned char uchar;
struct Meter {
virtual string id() = 0;
virtual vector<string> ids() = 0;
virtual string name() = 0;
virtual MeterType type() = 0;
virtual int manufacturer() = 0;
virtual int media() = 0;
virtual vector<int> media() = 0;
virtual WMBus *bus() = 0;
virtual LinkMode requiredLinkMode() = 0;
virtual string datetimeOfUpdateHumanReadable() = 0;
virtual string datetimeOfUpdateRobot() = 0;
virtual void onUpdate(function<void(string id, Meter*)> cb) = 0;
virtual void onUpdate(function<void(Telegram*t,Meter*)> cb) = 0;
virtual int numUpdates() = 0;
virtual void printMeter(string id,
virtual void printMeter(Telegram *t,
string *human_readable,
string *fields, char separator,
string *json,

Wyświetl plik

@ -24,18 +24,18 @@
struct MeterCommonImplementation : public virtual Meter
{
string id();
vector<string> ids();
string name();
MeterType type();
int manufacturer();
int media();
vector<int> media();
WMBus *bus();
LinkMode requiredLinkMode();
string datetimeOfUpdateHumanReadable();
string datetimeOfUpdateRobot();
void onUpdate(function<void(string id, Meter*)> cb);
void onUpdate(function<void(Telegram*,Meter*)> cb);
int numUpdates();
bool isTelegramForMe(Telegram *t);
@ -47,7 +47,7 @@ struct MeterCommonImplementation : public virtual Meter
uint16_t getRecordAsUInt16(std::string record);
MeterCommonImplementation(WMBus *bus, string& name, string& id, string& key,
MeterType type, int manufacturer, int media,
MeterType type, int manufacturer,
LinkMode required_link_mode);
~MeterCommonImplementation() = default;
@ -55,18 +55,18 @@ struct MeterCommonImplementation : public virtual Meter
protected:
void triggerUpdate(Telegram *t);
void updateMedia(int media);
void addMedia(int media);
private:
MeterType type_ {};
int manufacturer_ {};
int media_ {};
vector<int> media_ {};
string name_;
string id_;
vector<string> ids_;
vector<uchar> key_;
WMBus *bus_ {};
vector<function<void(string,Meter*)>> on_update_;
vector<function<void(Telegram*,Meter*)>> on_update_;
int num_updates_ {};
bool use_aes_ {};
time_t datetime_of_update_ {};

Wyświetl plik

@ -36,13 +36,13 @@ Printer::Printer(bool json, bool fields, char separator,
overwrite_ = overwrite;
}
void Printer::print(string id, Meter *meter)
void Printer::print(Telegram *t, Meter *meter)
{
string human_readable, fields, json;
vector<string> envs;
bool printed = false;
meter->printMeter(id, &human_readable, &fields, separator_, &json, &envs);
meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs);
if (shell_cmdlines_.size() > 0) {
printShells(meter, envs);

Wyświetl plik

@ -29,7 +29,7 @@ struct Printer {
vector<string> shell_cmdlines,
bool overwrite);
void print(string id, Meter *meter);
void print(Telegram *t, Meter *meter);
private:

Wyświetl plik

@ -303,12 +303,17 @@ void debug(const char* fmt, ...) {
}
}
bool isValidId(string& id)
bool isValidId(string& ids)
{
if (id == "*") return true;
if (id.length() != 8) return false;
for (int i=0; i<8; ++i) {
if (id[i]<'0' || id[i]>'9') return false;
vector<string> v = splitIds(ids);
for (auto id : v)
{
if (id == "*") return true;
if (id.length() != 8) return false;
for (int i=0; i<8; ++i) {
if (id[i]<'0' || id[i]>'9') return false;
}
}
return true;
}
@ -332,6 +337,23 @@ bool isFrequency(std::string& fq)
return true;
}
vector<string> splitIds(string& ids)
{
vector<string> r;
bool eof, err;
vector<uchar> v (ids.begin(), ids.end());
auto i = v.begin();
for (;;) {
auto id = eatTo(v, i, ',', 16, &eof, &err);
if (err) break;
trimWhitespace(&id);
r.push_back(id);
if (eof) break;
}
return r;
}
void incrementIV(uchar *iv, size_t len) {
uchar *p = iv+len-1;
while (p >= iv) {
@ -444,7 +466,7 @@ string eatTo(vector<uchar> &v, vector<uchar>::iterator &i, int c, size_t max, bo
i++;
max--;
}
if (c != -1 && *i != c)
if (c != -1 && i != v.end() && *i != c)
{
*err = true;
}

Wyświetl plik

@ -69,6 +69,8 @@ bool isValidId(std::string& id);
bool isValidKey(std::string& key);
bool isFrequency(std::string& fq);
std::vector<std::string> splitIds(std::string& id);
void incrementIV(uchar *iv, size_t len);
bool checkCharacterDeviceExists(const char *tty, bool fail_if_not);

Wyświetl plik

@ -14,5 +14,6 @@ tests/test_shell.sh $PROG
tests/test_meterfiles.sh $PROG
tests/test_config1.sh $PROG
tests/test_logfile.sh $PROG
tests/test_listen_to_all.sh $PROG
tests/test_multiple_ids.sh $PROG
tests/test_oneshot.sh $PROG

Wyświetl plik

@ -25,4 +25,5 @@ then
fi
else
echo Failure.
exit 1
fi

Wyświetl plik

@ -17,5 +17,6 @@ then
echo Config1 OK
fi
else
Failure.
echo Failure.
exit 1
fi

Wyświetl plik

@ -0,0 +1,64 @@
#!/bin/bash
PROG="$1"
mkdir -p testoutput
TEST=testoutput
SIM=simulations/simulation_multiple_qcalorics.txt
cat $SIM | grep '^{' > $TEST/test_expected.txt
$PROG --format=json $SIM \
Element qcaloric '*' '' \
> $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
diff $TEST/test_expected.txt $TEST/test_responses.txt
if [ "$?" == "0" ]
then
echo Wildcard \'\*\' id OK
fi
else
echo Failure.
exit 1
fi
cat $SIM | grep '^{' | grep -v 78563414 > $TEST/test_expected.txt
$PROG --format=json $SIM \
Element qcaloric '78563412,78563413' '' \
> $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
diff $TEST/test_expected.txt $TEST/test_responses.txt
if [ "$?" == "0" ]
then
echo Multiple ids2 OK
fi
else
echo Failure.
exit 1
fi
cat $SIM | grep '^{' > $TEST/test_expected.txt
$PROG --format=json $SIM \
Element qcaloric '78563412,78563413,78563414' '' \
> $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
diff $TEST/test_expected.txt $TEST/test_responses.txt
if [ "$?" == "0" ]
then
echo Multiple ids3 OK
fi
else
echo Failure.
exit 1
fi

Wyświetl plik

@ -0,0 +1,22 @@
#!/bin/bash
PROG="$1"
mkdir -p testoutput
TEST=testoutput
SIM=simulations/simulation_c1.txt
cat $SIM | grep '^{' > $TEST/test_expected.txt
$PROG --oneshot --verbose $SIM MyHeater multical302 '*' '' MyTapWater multical21 76348799 '' > $TEST/test_output.txt
RES=$(cat $TEST/test_output.txt | grep -o "all meters have received at least one update, stopping.")
if [ "$RES" = "all meters have received at least one update, stopping." ]
then
echo Oneshot OK
else
echo Fail oneshot check!
exit 1
fi

Wyświetl plik

@ -17,5 +17,6 @@ then
echo SHELL OK
fi
else
Failure.
echo Failure.
exit 1
fi

Wyświetl plik

@ -21,5 +21,6 @@ then
echo T1 OK
fi
else
Failure.
echo Failure.
exit 1
fi

Wyświetl plik

@ -70,7 +70,7 @@ mqtt_publish) sent to a REST API (eg curl) or store it in a database
.TP
\fBmeter_type\fR multical21/flowiq3100/supercom587/iperl/multical302/omnipower/qcaloric
.TP
\fBmeter_id\fR an 8 digit number, usually printed on the meter
\fBmeter_id\fR one or more 8 digit numbers separated with commas, or a single '*' wildcard.
.TP
\fBmeter_key\fR a unique key for the meter, if meter telegrams are not encrypted, you must supply an empty key: ""