kopia lustrzana https://github.com/weetmuts/wmbusmeters
Ignoreduplices enabled by defailt. New C++ object create for each unique meter, despite wildcards.
rodzic
73c4085a00
commit
301c91ea68
18
CHANGES
18
CHANGES
|
@ -1,4 +1,20 @@
|
||||||
Version 1.0.6: 2021-02-20
|
|
||||||
|
Ignore duplicates is now enabled by default. Turn it off with --ignoreduplicates=false
|
||||||
|
|
||||||
|
Fixed problem with state maintaining meter drivers and wildcard ids.
|
||||||
|
A HCA driver was producing telegrams with values that jumped up and down.
|
||||||
|
This was due to the fact that the meter state in the driver was updated
|
||||||
|
through multiple different telegrams (this is how the meter works).
|
||||||
|
Clearly a single state object could not properly maintain the state for all
|
||||||
|
possible meters matching the wildcard, the state became a random mix
|
||||||
|
of whater telegrams arrived.
|
||||||
|
|
||||||
|
The fix now, is that a meter C++ object for a uniqe id (not wildcard)
|
||||||
|
is created only when the first telegram arrives that matches the wildcard.
|
||||||
|
Thus each meter will have its own C++ object, in which the correct state
|
||||||
|
is maintained.
|
||||||
|
|
||||||
|
Version 1.1.0: 2021-02-20
|
||||||
|
|
||||||
Vincent Privat added code for properly decoding several types of izar meter.
|
Vincent Privat added code for properly decoding several types of izar meter.
|
||||||
He also added full support for the heat meter sharky 775!
|
He also added full support for the heat meter sharky 775!
|
||||||
|
|
38
Makefile
38
Makefile
|
@ -119,7 +119,26 @@ METER_OBJS:=\
|
||||||
$(BUILD)/dvparser.o \
|
$(BUILD)/dvparser.o \
|
||||||
$(BUILD)/mbus_rawtty.o \
|
$(BUILD)/mbus_rawtty.o \
|
||||||
$(BUILD)/meters.o \
|
$(BUILD)/meters.o \
|
||||||
|
$(BUILD)/manufacturer_specificities.o \
|
||||||
|
$(BUILD)/printer.o \
|
||||||
|
$(BUILD)/rtlsdr.o \
|
||||||
|
$(BUILD)/serial.o \
|
||||||
|
$(BUILD)/shell.o \
|
||||||
|
$(BUILD)/sha256.o \
|
||||||
|
$(BUILD)/threads.o \
|
||||||
|
$(BUILD)/util.o \
|
||||||
|
$(BUILD)/units.o \
|
||||||
|
$(BUILD)/wmbus.o \
|
||||||
$(BUILD)/meter_amiplus.o \
|
$(BUILD)/meter_amiplus.o \
|
||||||
|
$(BUILD)/wmbus_amb8465.o \
|
||||||
|
$(BUILD)/wmbus_im871a.o \
|
||||||
|
$(BUILD)/wmbus_cul.o \
|
||||||
|
$(BUILD)/wmbus_rtlwmbus.o \
|
||||||
|
$(BUILD)/wmbus_rtl433.o \
|
||||||
|
$(BUILD)/wmbus_simulator.o \
|
||||||
|
$(BUILD)/wmbus_rawtty.o \
|
||||||
|
$(BUILD)/wmbus_rc1180.o \
|
||||||
|
$(BUILD)/wmbus_utils.o \
|
||||||
$(BUILD)/meter_apator08.o \
|
$(BUILD)/meter_apator08.o \
|
||||||
$(BUILD)/meter_apator162.o \
|
$(BUILD)/meter_apator162.o \
|
||||||
$(BUILD)/meter_cma12w.o \
|
$(BUILD)/meter_cma12w.o \
|
||||||
|
@ -170,25 +189,6 @@ METER_OBJS:=\
|
||||||
$(BUILD)/meter_whe5x.o \
|
$(BUILD)/meter_whe5x.o \
|
||||||
$(BUILD)/meter_sensostar.o \
|
$(BUILD)/meter_sensostar.o \
|
||||||
$(BUILD)/meter_gransystems_ccx01.o \
|
$(BUILD)/meter_gransystems_ccx01.o \
|
||||||
$(BUILD)/manufacturer_specificities.o \
|
|
||||||
$(BUILD)/printer.o \
|
|
||||||
$(BUILD)/rtlsdr.o \
|
|
||||||
$(BUILD)/serial.o \
|
|
||||||
$(BUILD)/shell.o \
|
|
||||||
$(BUILD)/sha256.o \
|
|
||||||
$(BUILD)/threads.o \
|
|
||||||
$(BUILD)/util.o \
|
|
||||||
$(BUILD)/units.o \
|
|
||||||
$(BUILD)/wmbus.o \
|
|
||||||
$(BUILD)/wmbus_amb8465.o \
|
|
||||||
$(BUILD)/wmbus_im871a.o \
|
|
||||||
$(BUILD)/wmbus_cul.o \
|
|
||||||
$(BUILD)/wmbus_rtlwmbus.o \
|
|
||||||
$(BUILD)/wmbus_rtl433.o \
|
|
||||||
$(BUILD)/wmbus_simulator.o \
|
|
||||||
$(BUILD)/wmbus_rawtty.o \
|
|
||||||
$(BUILD)/wmbus_rc1180.o \
|
|
||||||
$(BUILD)/wmbus_utils.o
|
|
||||||
|
|
||||||
all: $(BUILD)/wmbusmeters $(BUILD)/wmbusmeters-admin $(BUILD)/testinternals
|
all: $(BUILD)/wmbusmeters $(BUILD)/wmbusmeters-admin $(BUILD)/testinternals
|
||||||
@$(STRIP_BINARY)
|
@$(STRIP_BINARY)
|
||||||
|
|
|
@ -76,7 +76,7 @@ shell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters/$METER_ID -m "$METER_JS
|
||||||
alarmshell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters_alarm -m "$ALARM_TYPE $ALARM_MESSAGE"
|
alarmshell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters_alarm -m "$ALARM_TYPE $ALARM_MESSAGE"
|
||||||
alarmtimeout=1h
|
alarmtimeout=1h
|
||||||
alarmexpectedactivity=mon-sun(00-23)
|
alarmexpectedactivity=mon-sun(00-23)
|
||||||
ignoreduplicates=false
|
ignoreduplicates=true
|
||||||
```
|
```
|
||||||
|
|
||||||
Then add a meter file in /etc/wmbusmeters.d/MyTapWater
|
Then add a meter file in /etc/wmbusmeters.d/MyTapWater
|
||||||
|
@ -172,7 +172,7 @@ As <options> you can use:
|
||||||
--listmeters=<search> list all meter types containing the text <search>
|
--listmeters=<search> list all meter types containing the text <search>
|
||||||
--logfile=<file> use this file instead of stdout
|
--logfile=<file> use this file instead of stdout
|
||||||
--logtelegrams log the contents of the telegrams for easy replay
|
--logtelegrams log the contents of the telegrams for easy replay
|
||||||
--ignoreduplicates ignore duplicate telegrams, remember the last 10 telegrams
|
--ignoreduplicates=<bool> ignore duplicate telegrams, remember the last 10 telegrams
|
||||||
--meterfiles=<dir> store meter readings in dir
|
--meterfiles=<dir> store meter readings in dir
|
||||||
--meterfilesaction=(overwrite|append) overwrite or append to the meter readings file
|
--meterfilesaction=(overwrite|append) overwrite or append to the meter readings file
|
||||||
--meterfilesnaming=(name|id|name-id) the meter file is the meter's: name, id or name-id
|
--meterfilesnaming=(name|id|name-id) the meter file is the meter's: name, id or name-id
|
||||||
|
|
|
@ -374,7 +374,25 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--ignoreduplicates", 18)) {
|
if (!strncmp(argv[i], "--ignoreduplicates", 18)) {
|
||||||
c->ignore_duplicate_telegrams = true;
|
if (argv[i][18] == 0)
|
||||||
|
{
|
||||||
|
c->ignore_duplicate_telegrams = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!strcmp(argv[i]+18, "=true"))
|
||||||
|
{
|
||||||
|
c->ignore_duplicate_telegrams = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[i]+18, "=false"))
|
||||||
|
{
|
||||||
|
c->ignore_duplicate_telegrams = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error("You must specify true or false after --ignoreduplicates=\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -564,7 +582,8 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
||||||
if (!isValidMatchExpressions(id, true)) error("Not a valid id nor a valid meter match expression \"%s\"\n", id.c_str());
|
if (!isValidMatchExpressions(id, true)) error("Not a valid id nor a valid meter match expression \"%s\"\n", id.c_str());
|
||||||
if (!isValidKey(key, mt)) error("Not a valid meter key \"%s\"\n", key.c_str());
|
if (!isValidKey(key, mt)) error("Not a valid meter key \"%s\"\n", key.c_str());
|
||||||
vector<string> no_meter_shells, no_meter_jsons;
|
vector<string> no_meter_shells, no_meter_jsons;
|
||||||
c->meters.push_back(MeterInfo(bus, name, type, id, key, modes, bps, no_meter_shells, no_meter_jsons));
|
vector<string> ids = splitMatchExpressions(id);
|
||||||
|
c->meters.push_back(MeterInfo(bus, name, mt, ids, key, modes, bps, no_meter_shells, no_meter_jsons));
|
||||||
}
|
}
|
||||||
|
|
||||||
return shared_ptr<Configuration>(c);
|
return shared_ptr<Configuration>(c);
|
||||||
|
|
|
@ -177,7 +177,8 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
||||||
use = false;
|
use = false;
|
||||||
}
|
}
|
||||||
if (use) {
|
if (use) {
|
||||||
c->meters.push_back(MeterInfo(bus, name, type, id, key, modes, bps, telegram_shells, jsons));
|
vector<string> ids = splitMatchExpressions(id);
|
||||||
|
c->meters.push_back(MeterInfo(bus, name, mt, ids, key, modes, bps, telegram_shells, jsons));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -659,7 +660,7 @@ LinkModeCalculationResult calculateLinkModes(Configuration *config, WMBus *wmbus
|
||||||
{
|
{
|
||||||
meters_union.unionLinkModeSet(m.link_modes);
|
meters_union.unionLinkModeSet(m.link_modes);
|
||||||
string meter = m.link_modes.hr();
|
string meter = m.link_modes.hr();
|
||||||
debug("(config) meter %s link mode(s): %s\n", m.type.c_str(), meter.c_str());
|
debug("(config) meter %s link mode(s): %s\n", toMeterName(m.type).c_str(), meter.c_str());
|
||||||
}
|
}
|
||||||
string metersu = meters_union.hr();
|
string metersu = meters_union.hr();
|
||||||
debug("(config) all possible link modes that the meters might transmit on: %s\n", metersu.c_str());
|
debug("(config) all possible link modes that the meters might transmit on: %s\n", metersu.c_str());
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct Configuration
|
||||||
MeterFileTimestamp meterfiles_timestamp {}; // Default is never.
|
MeterFileTimestamp meterfiles_timestamp {}; // Default is never.
|
||||||
bool use_logfile {};
|
bool use_logfile {};
|
||||||
bool use_stderr_for_log = true; // Default is to use stderr for logging.
|
bool use_stderr_for_log = true; // Default is to use stderr for logging.
|
||||||
bool ignore_duplicate_telegrams = false; // Default is to report all telegrams.
|
bool ignore_duplicate_telegrams = true; // Default is to ignore duplicates.
|
||||||
std::string logfile;
|
std::string logfile;
|
||||||
bool json {};
|
bool json {};
|
||||||
bool fields {};
|
bool fields {};
|
||||||
|
|
34
src/main.cc
34
src/main.cc
|
@ -691,7 +691,8 @@ void list_shell_envs(Configuration *config, string meter_type)
|
||||||
vector<string> envs;
|
vector<string> envs;
|
||||||
Telegram t;
|
Telegram t;
|
||||||
MeterInfo mi;
|
MeterInfo mi;
|
||||||
shared_ptr<Meter> meter = createMeter(config, toMeterType(meter_type), &mi);
|
mi.type = toMeterType(meter_type);
|
||||||
|
shared_ptr<Meter> meter = createMeter(&mi);
|
||||||
meter->printMeter(&t,
|
meter->printMeter(&t,
|
||||||
&ignore1,
|
&ignore1,
|
||||||
&ignore2, config->separator,
|
&ignore2, config->separator,
|
||||||
|
@ -711,7 +712,8 @@ void list_shell_envs(Configuration *config, string meter_type)
|
||||||
void list_fields(Configuration *config, string meter_type)
|
void list_fields(Configuration *config, string meter_type)
|
||||||
{
|
{
|
||||||
MeterInfo mi;
|
MeterInfo mi;
|
||||||
shared_ptr<Meter> meter = createMeter(config, toMeterType(meter_type), &mi);
|
mi.type = toMeterType(meter_type);
|
||||||
|
shared_ptr<Meter> meter = createMeter(&mi);
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
for (auto &p : meter->prints())
|
for (auto &p : meter->prints())
|
||||||
|
@ -1112,8 +1114,8 @@ void setup_meters(Configuration *config, MeterManager *manager)
|
||||||
{
|
{
|
||||||
for (auto &m : config->meters)
|
for (auto &m : config->meters)
|
||||||
{
|
{
|
||||||
auto meter = createMeter(config, toMeterType(m.type), &m);
|
m.conversions = config->conversions;
|
||||||
manager->addMeter(meter);
|
manager->addMeterTemplate(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,24 +1156,20 @@ bool start(Configuration *config)
|
||||||
// or sent to shell invocations.
|
// or sent to shell invocations.
|
||||||
printer_ = create_printer(config);
|
printer_ = create_printer(config);
|
||||||
|
|
||||||
meter_manager_ = createMeterManager();
|
meter_manager_ = createMeterManager(config->daemon);
|
||||||
|
|
||||||
|
// When a meter is updated, print it, shell it, log it, etc.
|
||||||
|
meter_manager_->whenMeterUpdated(
|
||||||
|
[&](Telegram *t,Meter *meter)
|
||||||
|
{
|
||||||
|
printer_->print(t, meter, &config->jsons, &config->selected_fields);
|
||||||
|
oneshot_check(config, t, meter);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Create the Meter objects from the configuration.
|
// Create the Meter objects from the configuration.
|
||||||
setup_meters(config, meter_manager_.get());
|
setup_meters(config, meter_manager_.get());
|
||||||
|
|
||||||
// Attach a received-telegram-callback from the meter and
|
|
||||||
// attach it to the printer.
|
|
||||||
meter_manager_->forEachMeter(
|
|
||||||
[&](Meter *meter)
|
|
||||||
{
|
|
||||||
meter->onUpdate([&](Telegram *t,Meter *meter)
|
|
||||||
{
|
|
||||||
printer_->print(t, meter, &config->jsons, &config->selected_fields);
|
|
||||||
oneshot_check(config, t, meter);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Detect and initialize any devices.
|
// Detect and initialize any devices.
|
||||||
// Future changes are triggered through this callback.
|
// Future changes are triggered through this callback.
|
||||||
printed_warning_ = true;
|
printed_warning_ = true;
|
||||||
|
|
209
src/meters.cc
209
src/meters.cc
|
@ -30,9 +30,23 @@
|
||||||
|
|
||||||
struct MeterManagerImplementation : public virtual MeterManager
|
struct MeterManagerImplementation : public virtual MeterManager
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
bool is_daemon_ {};
|
||||||
|
vector<MeterInfo> meter_templates_;
|
||||||
|
vector<shared_ptr<Meter>> meters_;
|
||||||
|
function<void(AboutTelegram&,vector<uchar>)> on_telegram_;
|
||||||
|
function<void(Telegram*t,Meter*)> on_meter_updated_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addMeterTemplate(MeterInfo &mi)
|
||||||
|
{
|
||||||
|
meter_templates_.push_back(mi);
|
||||||
|
}
|
||||||
|
|
||||||
void addMeter(shared_ptr<Meter> meter)
|
void addMeter(shared_ptr<Meter> meter)
|
||||||
{
|
{
|
||||||
meters_.push_back(meter);
|
meters_.push_back(meter);
|
||||||
|
meter->setIndex(meters_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
Meter *lastAddedMeter()
|
Meter *lastAddedMeter()
|
||||||
|
@ -65,28 +79,115 @@ struct MeterManagerImplementation : public virtual MeterManager
|
||||||
|
|
||||||
bool hasMeters()
|
bool hasMeters()
|
||||||
{
|
{
|
||||||
return meters_.size() != 0;
|
return meters_.size() != 0 || meter_templates_.size() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleTelegram(AboutTelegram &about, vector<uchar> data, bool simulated)
|
bool handleTelegram(AboutTelegram &about, vector<uchar> input_frame, bool simulated)
|
||||||
{
|
{
|
||||||
if (!hasMeters())
|
if (!hasMeters())
|
||||||
{
|
{
|
||||||
if (on_telegram_)
|
if (on_telegram_)
|
||||||
{
|
{
|
||||||
on_telegram_(about, data);
|
on_telegram_(about, input_frame);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
bool exact_id_match = false;
|
||||||
|
|
||||||
string ids;
|
string ids;
|
||||||
for (auto &m : meters_)
|
for (auto &m : meters_)
|
||||||
{
|
{
|
||||||
bool h = m->handleTelegram(about, data, simulated, &ids);
|
bool h = m->handleTelegram(about, input_frame, simulated, &ids, &exact_id_match);
|
||||||
if (h) handled = true;
|
if (h) handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not properly handled, and there was no exact id match.
|
||||||
|
// then lets check if there is a template that can create a meter for it.
|
||||||
|
if (!handled && !exact_id_match)
|
||||||
|
{
|
||||||
|
debug("(meter) no meter handled %s checking %d templates.\n", ids.c_str(), meter_templates_.size());
|
||||||
|
// Not handled, maybe we have a template to create a new meter instance for this telegram?
|
||||||
|
Telegram t;
|
||||||
|
t.about = about;
|
||||||
|
bool ok = t.parseHeader(input_frame);
|
||||||
|
if (simulated) t.markAsSimulated();
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
ids = t.idsc;
|
||||||
|
for (auto &mi : meter_templates_)
|
||||||
|
{
|
||||||
|
if (MeterCommonImplementation::isTelegramForMeter(&t, NULL, &mi))
|
||||||
|
{
|
||||||
|
// We found a match, make a copy of the meter info.
|
||||||
|
MeterInfo tmp = mi;
|
||||||
|
// Overwrite the wildcard pattern with the highest level id.
|
||||||
|
// The last id in the t.ids is the highest level id.
|
||||||
|
// For example: a telegram can have dll_id,tpl_id
|
||||||
|
// This will pick the tpl_id.
|
||||||
|
// Or a telegram can have a single dll_id,
|
||||||
|
// then the dll_id will be picked.
|
||||||
|
vector<string> tmp_ids;
|
||||||
|
tmp_ids.push_back(t.ids.back());
|
||||||
|
tmp.ids = tmp_ids;
|
||||||
|
tmp.idsc = t.ids.back();
|
||||||
|
// Now build a meter object with for this exact id.
|
||||||
|
auto meter = createMeter(&tmp);
|
||||||
|
meter->onUpdate(on_meter_updated_);
|
||||||
|
|
||||||
|
addMeter(meter);
|
||||||
|
string idsc = toIdsCommaSeparated(t.ids);
|
||||||
|
verbose("(meter) used meter template %s %s %s to match %s\n",
|
||||||
|
mi.name.c_str(),
|
||||||
|
mi.idsc.c_str(),
|
||||||
|
toMeterName(mi.type).c_str(),
|
||||||
|
idsc.c_str());
|
||||||
|
|
||||||
|
if (is_daemon_)
|
||||||
|
{
|
||||||
|
notice("(wmbusmeters) started meter %d (%s %s %s)\n",
|
||||||
|
meter->index(),
|
||||||
|
mi.name.c_str(),
|
||||||
|
tmp.idsc.c_str(),
|
||||||
|
toMeterName(mi.type).c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verbose("(meter) started meter %d (%s %s %s)\n",
|
||||||
|
meter->index(),
|
||||||
|
mi.name.c_str(),
|
||||||
|
tmp.idsc.c_str(),
|
||||||
|
toMeterName(mi.type).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match = false;
|
||||||
|
bool h = meter->handleTelegram(about, input_frame, simulated, &ids, &match);
|
||||||
|
if (!match)
|
||||||
|
{
|
||||||
|
// Oups, we added a new meter object tailored for this telegram
|
||||||
|
// but it still did not match! This is probably an error in wmbusmeters!
|
||||||
|
warning("(meter) newly created meter (%s %s %s) did not match telegram! ",
|
||||||
|
"Please open an issue at https://github.com/weetmuts/wmbusmeters/\n",
|
||||||
|
meter->name().c_str(), meter->idsc().c_str(), toMeterName(meter->type()).c_str());
|
||||||
|
}
|
||||||
|
else if (!h)
|
||||||
|
{
|
||||||
|
// Oups, we added a new meter object tailored for this telegram
|
||||||
|
// but it still did not handle it! This can happen if the wrong
|
||||||
|
// decryption key was used.
|
||||||
|
warning("(meter) newly created meter (%s %s %s) did not handle telegram!\n",
|
||||||
|
meter->name().c_str(), meter->idsc().c_str(), toMeterName(meter->type()).c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isVerboseEnabled() && !handled)
|
if (isVerboseEnabled() && !handled)
|
||||||
{
|
{
|
||||||
verbose("(wmbus) telegram from %s ignored by all configured meters!\n", ids.c_str());
|
verbose("(wmbus) telegram from %s ignored by all configured meters!\n", ids.c_str());
|
||||||
|
@ -98,32 +199,31 @@ struct MeterManagerImplementation : public virtual MeterManager
|
||||||
{
|
{
|
||||||
on_telegram_ = cb;
|
on_telegram_ = cb;
|
||||||
}
|
}
|
||||||
|
void whenMeterUpdated(std::function<void(Telegram*t,Meter*)> cb)
|
||||||
|
{
|
||||||
|
on_meter_updated_ = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeterManagerImplementation(bool daemon) : is_daemon_(daemon) {}
|
||||||
~MeterManagerImplementation() {}
|
~MeterManagerImplementation() {}
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
vector<shared_ptr<Meter>> meters_;
|
|
||||||
function<void(AboutTelegram&,vector<uchar>)> on_telegram_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
shared_ptr<MeterManager> createMeterManager()
|
shared_ptr<MeterManager> createMeterManager(bool daemon)
|
||||||
{
|
{
|
||||||
return shared_ptr<MeterManager>(new MeterManagerImplementation);
|
return shared_ptr<MeterManager>(new MeterManagerImplementation(daemon));
|
||||||
}
|
}
|
||||||
|
|
||||||
MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
|
MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
|
||||||
MeterType type) :
|
MeterType type) :
|
||||||
type_(type), name_(mi.name)
|
type_(type), name_(mi.name)
|
||||||
{
|
{
|
||||||
ids_ = splitMatchExpressions(mi.id);
|
ids_ = mi.ids;
|
||||||
|
idsc_ = toIdsCommaSeparated(ids_);
|
||||||
|
|
||||||
if (mi.key.length() > 0)
|
if (mi.key.length() > 0)
|
||||||
{
|
{
|
||||||
hex2bin(mi.key, &meter_keys_.confidentiality_key);
|
hex2bin(mi.key, &meter_keys_.confidentiality_key);
|
||||||
}
|
}
|
||||||
/*if (bus->type() == DEVICE_SIMULATION)
|
|
||||||
{
|
|
||||||
meter_keys_.simulation = true;
|
|
||||||
}*/
|
|
||||||
for (auto s : mi.shells) {
|
for (auto s : mi.shells) {
|
||||||
addShell(s);
|
addShell(s);
|
||||||
}
|
}
|
||||||
|
@ -195,11 +295,16 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity,
|
||||||
prints_.push_back( { vname, vquantity, defaultUnitForQuantity(vquantity), NULL, getValueFunc, help, field, json, vname } );
|
prints_.push_back( { vname, vquantity, defaultUnitForQuantity(vquantity), NULL, getValueFunc, help, field, json, vname } );
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> MeterCommonImplementation::ids()
|
vector<string>& MeterCommonImplementation::ids()
|
||||||
{
|
{
|
||||||
return ids_;
|
return ids_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string MeterCommonImplementation::idsc()
|
||||||
|
{
|
||||||
|
return idsc_;
|
||||||
|
}
|
||||||
|
|
||||||
vector<string> MeterCommonImplementation::fields()
|
vector<string> MeterCommonImplementation::fields()
|
||||||
{
|
{
|
||||||
return fields_;
|
return fields_;
|
||||||
|
@ -266,23 +371,46 @@ LIST_OF_METERS
|
||||||
return LinkModeSet();
|
return LinkModeSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeterCommonImplementation::isTelegramForMe(Telegram *t)
|
bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi)
|
||||||
{
|
{
|
||||||
debug("(meter) %s: for me? %s\n", name_.c_str(), t->idsc.c_str());
|
string name;
|
||||||
|
vector<string> ids;
|
||||||
|
string idsc;
|
||||||
|
MeterType type;
|
||||||
|
|
||||||
|
assert((meter && !mi) ||
|
||||||
|
(!meter && mi));
|
||||||
|
|
||||||
|
if (meter)
|
||||||
|
{
|
||||||
|
name = meter->name();
|
||||||
|
ids = meter->ids();
|
||||||
|
idsc = meter->idsc();
|
||||||
|
type = meter->type();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = mi->name;
|
||||||
|
ids = mi->ids;
|
||||||
|
idsc = mi->idsc;
|
||||||
|
type = mi->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("(meter) %s: for me? %s\n", name.c_str(), idsc.c_str());
|
||||||
|
|
||||||
bool used_wildcard = false;
|
bool used_wildcard = false;
|
||||||
bool id_match = doesIdsMatchExpressions(t->ids, ids_, &used_wildcard);
|
bool id_match = doesIdsMatchExpressions(t->ids, ids, &used_wildcard);
|
||||||
|
|
||||||
if (!id_match) {
|
if (!id_match) {
|
||||||
// The id must match.
|
// The id must match.
|
||||||
debug("(meter) %s: not for me: not my id\n", name_.c_str());
|
debug("(meter) %s: not for me: not my id\n", name.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid_driver = isMeterDriverValid(type_, t->dll_mfct, t->dll_type, t->dll_version);
|
bool valid_driver = isMeterDriverValid(type, t->dll_mfct, t->dll_type, t->dll_version);
|
||||||
if (!valid_driver && t->tpl_id_found)
|
if (!valid_driver && t->tpl_id_found)
|
||||||
{
|
{
|
||||||
valid_driver = isMeterDriverValid(type_, t->tpl_mfct, t->tpl_type, t->tpl_version);
|
valid_driver = isMeterDriverValid(type, t->tpl_mfct, t->tpl_type, t->tpl_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_driver)
|
if (!valid_driver)
|
||||||
|
@ -309,8 +437,8 @@ bool MeterCommonImplementation::isTelegramForMe(Telegram *t)
|
||||||
string possible_drivers = t->autoDetectPossibleDrivers();
|
string possible_drivers = t->autoDetectPossibleDrivers();
|
||||||
warning("(meter) %s: meter detection did not match the selected driver %s! correct driver is: %s\n"
|
warning("(meter) %s: meter detection did not match the selected driver %s! correct driver is: %s\n"
|
||||||
"(meter) Not printing this warning agin for id: %02x%02x%02x%02x mfct: (%s) %s (0x%02x) type: %s (0x%02x) ver: 0x%02x\n",
|
"(meter) Not printing this warning agin for id: %02x%02x%02x%02x mfct: (%s) %s (0x%02x) type: %s (0x%02x) ver: 0x%02x\n",
|
||||||
name_.c_str(),
|
name.c_str(),
|
||||||
toMeterName(type()).c_str(),
|
toMeterName(type).c_str(),
|
||||||
possible_drivers.c_str(),
|
possible_drivers.c_str(),
|
||||||
t->dll_id_b[3], t->dll_id_b[2], t->dll_id_b[1], t->dll_id_b[0],
|
t->dll_id_b[3], t->dll_id_b[2], t->dll_id_b[1], t->dll_id_b[0],
|
||||||
manufacturerFlag(t->dll_mfct).c_str(),
|
manufacturerFlag(t->dll_mfct).c_str(),
|
||||||
|
@ -327,7 +455,7 @@ bool MeterCommonImplementation::isTelegramForMe(Telegram *t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("(meter) %s: yes for me\n", name_.c_str());
|
debug("(meter) %s: yes for me\n", name.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +484,16 @@ uint16_t MeterCommonImplementation::getRecordAsUInt16(string record)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MeterCommonImplementation::index()
|
||||||
|
{
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeterCommonImplementation::setIndex(int i)
|
||||||
|
{
|
||||||
|
index_ = i;
|
||||||
|
}
|
||||||
|
|
||||||
void MeterCommonImplementation::triggerUpdate(Telegram *t)
|
void MeterCommonImplementation::triggerUpdate(Telegram *t)
|
||||||
{
|
{
|
||||||
datetime_of_update_ = time(NULL);
|
datetime_of_update_ = time(NULL);
|
||||||
|
@ -486,7 +624,7 @@ string concatFields(Meter *m, Telegram *t, char c, vector<Print> &prints, vector
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<uchar> input_frame, bool simulated, string *ids)
|
bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<uchar> input_frame, bool simulated, string *ids, bool *id_match)
|
||||||
{
|
{
|
||||||
Telegram t;
|
Telegram t;
|
||||||
t.about = about;
|
t.about = about;
|
||||||
|
@ -496,12 +634,13 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
|
||||||
|
|
||||||
*ids = t.idsc;
|
*ids = t.idsc;
|
||||||
|
|
||||||
if (!ok || !isTelegramForMe(&t))
|
if (!ok || !isTelegramForMeter(&t, this, NULL))
|
||||||
{
|
{
|
||||||
// This telegram is not intended for this meter.
|
// This telegram is not intended for this meter.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*id_match = true;
|
||||||
verbose("(meter) %s %s handling telegram from %s\n", name().c_str(), meterName().c_str(), t.ids.back().c_str());
|
verbose("(meter) %s %s handling telegram from %s\n", name().c_str(), meterName().c_str(), t.ids.back().c_str());
|
||||||
|
|
||||||
if (isDebugEnabled())
|
if (isDebugEnabled())
|
||||||
|
@ -738,28 +877,28 @@ METER_DETECTION
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Meter> createMeter(Configuration *config, MeterType type, MeterInfo *mi)
|
shared_ptr<Meter> createMeter(MeterInfo *mi)
|
||||||
{
|
{
|
||||||
shared_ptr<Meter> newm;
|
shared_ptr<Meter> newm;
|
||||||
|
|
||||||
const char *keymsg = (mi->key[0] == 0) ? "not-encrypted" : "encrypted";
|
const char *keymsg = (mi->key[0] == 0) ? "not-encrypted" : "encrypted";
|
||||||
|
|
||||||
switch (type)
|
switch (mi->type)
|
||||||
{
|
{
|
||||||
#define X(mname,link,info,type,cname) \
|
#define X(mname,link,info,type,cname) \
|
||||||
case MeterType::type: \
|
case MeterType::type: \
|
||||||
{ \
|
{ \
|
||||||
newm = create##cname(*mi); \
|
newm = create##cname(*mi); \
|
||||||
newm->addConversions(config->conversions); \
|
newm->addConversions(mi->conversions); \
|
||||||
verbose("(main) configured \"%s\" \"" #mname "\" \"%s\" %s\n", \
|
verbose("(meter) created \"%s\" \"" #mname "\" \"%s\" %s\n", \
|
||||||
mi->name.c_str(), mi->id.c_str(), keymsg); \
|
mi->name.c_str(), mi->idsc.c_str(), keymsg); \
|
||||||
return newm; \
|
return newm; \
|
||||||
} \
|
} \
|
||||||
break;
|
break;
|
||||||
LIST_OF_METERS
|
LIST_OF_METERS
|
||||||
#undef X
|
#undef X
|
||||||
case MeterType::UNKNOWN:
|
case MeterType::UNKNOWN:
|
||||||
error("No such meter type \"%s\"\n", mi->type.c_str());
|
error("No such meter type \"%s\"\n", toMeterName(mi->type).c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return newm;
|
return newm;
|
||||||
|
|
33
src/meters.h
33
src/meters.h
|
@ -22,8 +22,9 @@
|
||||||
#include"units.h"
|
#include"units.h"
|
||||||
#include"wmbus.h"
|
#include"wmbus.h"
|
||||||
|
|
||||||
#include<string>
|
|
||||||
#include<functional>
|
#include<functional>
|
||||||
|
#include<numeric>
|
||||||
|
#include<string>
|
||||||
#include<vector>
|
#include<vector>
|
||||||
|
|
||||||
#define LIST_OF_METERS \
|
#define LIST_OF_METERS \
|
||||||
|
@ -201,24 +202,27 @@ struct MeterInfo
|
||||||
// A bus can be an mbus or a wmbus dongle.
|
// A bus can be an mbus or a wmbus dongle.
|
||||||
// The bus can be the empty string, which means that it will fallback to the first defined bus.
|
// The bus can be the empty string, which means that it will fallback to the first defined bus.
|
||||||
string name; // User specified name of this (group of) meters.
|
string name; // User specified name of this (group of) meters.
|
||||||
string type; // Driver
|
MeterType type {}; // Driver
|
||||||
string id; // How to identify the meter on the bus.
|
vector<string> ids; // Match expressions for ids.
|
||||||
|
string idsc; // Comma separated ids.
|
||||||
string key; // Decryption key.
|
string key; // Decryption key.
|
||||||
LinkModeSet link_modes;
|
LinkModeSet link_modes;
|
||||||
int bps {}; // For mbus communication you need to know the baud rate.
|
int bps {}; // For mbus communication you need to know the baud rate.
|
||||||
vector<string> shells;
|
vector<string> shells;
|
||||||
vector<string> jsons; // Additional static jsons that are added to each message.
|
vector<string> jsons; // Additional static jsons that are added to each message.
|
||||||
|
vector<Unit> conversions; // Additional units desired in json.
|
||||||
|
|
||||||
MeterInfo()
|
MeterInfo()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MeterInfo(string b, string n, string t, string i, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &j)
|
MeterInfo(string b, string n, MeterType t, vector<string> i, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &j)
|
||||||
{
|
{
|
||||||
bus = b;
|
bus = b;
|
||||||
name = n;
|
name = n;
|
||||||
type = t;
|
type = t;
|
||||||
id = i;
|
ids = i;
|
||||||
|
idsc = toIdsCommaSeparated(ids);
|
||||||
key = k;
|
key = k;
|
||||||
shells = s;
|
shells = s;
|
||||||
jsons = j;
|
jsons = j;
|
||||||
|
@ -242,8 +246,14 @@ struct Print
|
||||||
|
|
||||||
struct Meter
|
struct Meter
|
||||||
{
|
{
|
||||||
|
// Meters are instantiated on the fly from a template, when a telegram arrives
|
||||||
|
// and no exact meter exists. Index 1 is the first meter created etc.
|
||||||
|
virtual int index() = 0;
|
||||||
|
virtual void setIndex(int i) = 0;
|
||||||
// This meter listens to these ids.
|
// This meter listens to these ids.
|
||||||
virtual vector<string> ids() = 0;
|
virtual vector<string> &ids() = 0;
|
||||||
|
// Comma separated ids.
|
||||||
|
virtual string idsc() = 0;
|
||||||
// This meter can report these fields, like total_m3, temp_c.
|
// This meter can report these fields, like total_m3, temp_c.
|
||||||
virtual vector<string> fields() = 0;
|
virtual vector<string> fields() = 0;
|
||||||
virtual vector<Print> prints() = 0;
|
virtual vector<Print> prints() = 0;
|
||||||
|
@ -267,8 +277,8 @@ struct Meter
|
||||||
|
|
||||||
// The handleTelegram expects an input_frame where the DLL crcs have been removed.
|
// The handleTelegram expects an input_frame where the DLL crcs have been removed.
|
||||||
// Returns true of this meter handled this telegram!
|
// Returns true of this meter handled this telegram!
|
||||||
virtual bool handleTelegram(AboutTelegram &about, vector<uchar> input_frame, bool simulated, string *id) = 0;
|
// Sets id_match to true, if there was an id match, even though the telegram could not be properly handled.
|
||||||
virtual bool isTelegramForMe(Telegram *t) = 0;
|
virtual bool handleTelegram(AboutTelegram &about, vector<uchar> input_frame, bool simulated, string *id, bool *id_match) = 0;
|
||||||
virtual MeterKeys *meterKeys() = 0;
|
virtual MeterKeys *meterKeys() = 0;
|
||||||
|
|
||||||
// Dynamically access all data received for the meter.
|
// Dynamically access all data received for the meter.
|
||||||
|
@ -285,6 +295,7 @@ struct Meter
|
||||||
|
|
||||||
struct MeterManager
|
struct MeterManager
|
||||||
{
|
{
|
||||||
|
virtual void addMeterTemplate(MeterInfo &mi) = 0;
|
||||||
virtual void addMeter(shared_ptr<Meter> meter) = 0;
|
virtual void addMeter(shared_ptr<Meter> meter) = 0;
|
||||||
virtual Meter*lastAddedMeter() = 0;
|
virtual Meter*lastAddedMeter() = 0;
|
||||||
virtual void removeAllMeters() = 0;
|
virtual void removeAllMeters() = 0;
|
||||||
|
@ -293,10 +304,12 @@ struct MeterManager
|
||||||
virtual bool hasAllMetersReceivedATelegram() = 0;
|
virtual bool hasAllMetersReceivedATelegram() = 0;
|
||||||
virtual bool hasMeters() = 0;
|
virtual bool hasMeters() = 0;
|
||||||
virtual void onTelegram(function<void(AboutTelegram&,vector<uchar>)> cb) = 0;
|
virtual void onTelegram(function<void(AboutTelegram&,vector<uchar>)> cb) = 0;
|
||||||
|
virtual void whenMeterUpdated(std::function<void(Telegram*t,Meter*)> cb) = 0;
|
||||||
|
|
||||||
virtual ~MeterManager() = default;
|
virtual ~MeterManager() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
shared_ptr<MeterManager> createMeterManager();
|
shared_ptr<MeterManager> createMeterManager(bool daemon);
|
||||||
|
|
||||||
struct WaterMeter : public virtual Meter
|
struct WaterMeter : public virtual Meter
|
||||||
{
|
{
|
||||||
|
@ -401,6 +414,6 @@ Generic *createGeneric(WMBus *bus, MeterInfo &m);
|
||||||
|
|
||||||
struct Configuration;
|
struct Configuration;
|
||||||
struct MeterInfo;
|
struct MeterInfo;
|
||||||
shared_ptr<Meter> createMeter(Configuration *config, MeterType type, MeterInfo *mi);
|
shared_ptr<Meter> createMeter(MeterInfo *mi);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,9 +26,12 @@
|
||||||
|
|
||||||
struct MeterCommonImplementation : public virtual Meter
|
struct MeterCommonImplementation : public virtual Meter
|
||||||
{
|
{
|
||||||
vector<string> ids();
|
int index();
|
||||||
vector<string> fields();
|
void setIndex(int i);
|
||||||
vector<Print> prints();
|
vector<string>& ids();
|
||||||
|
string idsc();
|
||||||
|
vector<string> fields();
|
||||||
|
vector<Print> prints();
|
||||||
string name();
|
string name();
|
||||||
MeterType type();
|
MeterType type();
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ struct MeterCommonImplementation : public virtual Meter
|
||||||
void onUpdate(function<void(Telegram*,Meter*)> cb);
|
void onUpdate(function<void(Telegram*,Meter*)> cb);
|
||||||
int numUpdates();
|
int numUpdates();
|
||||||
|
|
||||||
bool isTelegramForMe(Telegram *t);
|
static bool isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi);
|
||||||
MeterKeys *meterKeys();
|
MeterKeys *meterKeys();
|
||||||
|
|
||||||
std::vector<std::string> getRecords();
|
std::vector<std::string> getRecords();
|
||||||
|
@ -74,7 +77,7 @@ protected:
|
||||||
// Print the dimensionless Text quantity, no unit is needed.
|
// Print the dimensionless Text quantity, no unit is needed.
|
||||||
void addPrint(string vname, Quantity vquantity,
|
void addPrint(string vname, Quantity vquantity,
|
||||||
function<std::string()> getValueFunc, string help, bool field, bool json);
|
function<std::string()> getValueFunc, string help, bool field, bool json);
|
||||||
bool handleTelegram(AboutTelegram &about, vector<uchar> frame, bool simulated, string *id);
|
bool handleTelegram(AboutTelegram &about, vector<uchar> frame, bool simulated, string *id, bool *id_match);
|
||||||
void printMeter(Telegram *t,
|
void printMeter(Telegram *t,
|
||||||
string *human_readable,
|
string *human_readable,
|
||||||
string *fields, char separator,
|
string *fields, char separator,
|
||||||
|
@ -87,12 +90,14 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
int index_ {};
|
||||||
MeterType type_ {};
|
MeterType type_ {};
|
||||||
MeterKeys meter_keys_ {};
|
MeterKeys meter_keys_ {};
|
||||||
ELLSecurityMode expected_ell_sec_mode_ {};
|
ELLSecurityMode expected_ell_sec_mode_ {};
|
||||||
TPLSecurityMode expected_tpl_sec_mode_ {};
|
TPLSecurityMode expected_tpl_sec_mode_ {};
|
||||||
string name_;
|
string name_;
|
||||||
vector<string> ids_;
|
vector<string> ids_;
|
||||||
|
string idsc_;
|
||||||
vector<function<void(Telegram*,Meter*)>> on_update_;
|
vector<function<void(Telegram*,Meter*)>> on_update_;
|
||||||
int num_updates_ {};
|
int num_updates_ {};
|
||||||
time_t datetime_of_update_ {};
|
time_t datetime_of_update_ {};
|
||||||
|
|
|
@ -263,11 +263,16 @@ int test_linkmodes()
|
||||||
|
|
||||||
Configuration apator_config;
|
Configuration apator_config;
|
||||||
string apator162 = "apator162";
|
string apator162 = "apator162";
|
||||||
apator_config.meters.push_back(MeterInfo("", "m1", apator162, "12345678", "",
|
vector<string> ids = { "12345678" };
|
||||||
toMeterLinkModeSet(apator162),
|
apator_config.meters.push_back(MeterInfo("", // bus
|
||||||
0,
|
"m1", // name
|
||||||
no_meter_shells,
|
MeterType::APATOR162, // driver/type
|
||||||
no_meter_jsons));
|
ids, // ids
|
||||||
|
"", // Key
|
||||||
|
toMeterLinkModeSet(apator162), // link mode set
|
||||||
|
0, // baud
|
||||||
|
no_meter_shells, // shells
|
||||||
|
no_meter_jsons)); // jsons
|
||||||
|
|
||||||
// Check that if no explicit link modes are provided to apator162, then
|
// Check that if no explicit link modes are provided to apator162, then
|
||||||
// automatic deduction will fail, since apator162 can be configured to transmit
|
// automatic deduction will fail, since apator162 can be configured to transmit
|
||||||
|
@ -301,12 +306,13 @@ int test_linkmodes()
|
||||||
Configuration multical21_and_supercom587_config;
|
Configuration multical21_and_supercom587_config;
|
||||||
string multical21 = "multical21";
|
string multical21 = "multical21";
|
||||||
string supercom587 = "supercom587";
|
string supercom587 = "supercom587";
|
||||||
multical21_and_supercom587_config.meters.push_back(MeterInfo("", "m1", multical21, "12345678", "",
|
|
||||||
|
multical21_and_supercom587_config.meters.push_back(MeterInfo("", "m1", MeterType::MULTICAL21, ids, "",
|
||||||
toMeterLinkModeSet(multical21),
|
toMeterLinkModeSet(multical21),
|
||||||
0,
|
0,
|
||||||
no_meter_shells,
|
no_meter_shells,
|
||||||
no_meter_jsons));
|
no_meter_jsons));
|
||||||
multical21_and_supercom587_config.meters.push_back(MeterInfo("", "m2", supercom587, "12345678", "",
|
multical21_and_supercom587_config.meters.push_back(MeterInfo("", "m2", MeterType::SUPERCOM587, ids, "",
|
||||||
toMeterLinkModeSet(supercom587),
|
toMeterLinkModeSet(supercom587),
|
||||||
0,
|
0,
|
||||||
no_meter_shells,
|
no_meter_shells,
|
||||||
|
|
12
src/util.cc
12
src/util.cc
|
@ -725,6 +725,18 @@ bool doesIdMatchExpressions(string id, vector<string>& mes, bool *used_wildcard)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string toIdsCommaSeparated(std::vector<std::string> &ids)
|
||||||
|
{
|
||||||
|
string cs;
|
||||||
|
for (string& s: ids)
|
||||||
|
{
|
||||||
|
cs += s;
|
||||||
|
cs += ",";
|
||||||
|
}
|
||||||
|
if (cs.length() > 0) cs.pop_back();
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
bool isValidKey(string& key, MeterType mt)
|
bool isValidKey(string& key, MeterType mt)
|
||||||
{
|
{
|
||||||
if (key.length() == 0) return true;
|
if (key.length() == 0) return true;
|
||||||
|
|
|
@ -108,6 +108,8 @@ bool isValidMatchExpressions(std::string ids, bool non_compliant);
|
||||||
bool doesIdMatchExpression(std::string id, std::string match_rule);
|
bool doesIdMatchExpression(std::string id, std::string match_rule);
|
||||||
bool doesIdMatchExpressions(std::string id, std::vector<std::string>& match_rules, bool *used_wildcard);
|
bool doesIdMatchExpressions(std::string id, std::vector<std::string>& match_rules, bool *used_wildcard);
|
||||||
bool doesIdsMatchExpressions(std::vector<std::string> &ids, std::vector<std::string>& match_rules, bool *used_wildcard);
|
bool doesIdsMatchExpressions(std::vector<std::string> &ids, std::vector<std::string>& match_rules, bool *used_wildcard);
|
||||||
|
std::string toIdsCommaSeparated(std::vector<std::string> &ids);
|
||||||
|
|
||||||
bool isValidId(std::string id, bool accept_non_compliant);
|
bool isValidId(std::string id, bool accept_non_compliant);
|
||||||
|
|
||||||
bool isValidKey(std::string& key, MeterType mt);
|
bool isValidKey(std::string& key, MeterType mt);
|
||||||
|
|
|
@ -14,3 +14,4 @@ alarmtimeout=4s
|
||||||
# expected to be transmitting. Some meters disable transmissions during nights
|
# expected to be transmitting. Some meters disable transmissions during nights
|
||||||
# and weekends. Change this to mon-fri(08-19)
|
# and weekends. Change this to mon-fri(08-19)
|
||||||
alarmexpectedactivity=mon-sun(00-23)
|
alarmexpectedactivity=mon-sun(00-23)
|
||||||
|
ignoreduplicates=false
|
|
@ -26,6 +26,7 @@ fi
|
||||||
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
|
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TESTNAME="Test additional shell envs from cmdline"
|
TESTNAME="Test additional shell envs from cmdline"
|
||||||
TESTRESULT="ERROR"
|
TESTRESULT="ERROR"
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ if [ ! -z "$REST" ]
|
||||||
then
|
then
|
||||||
echo ERROR TELEGRAMS: $TESTNAME
|
echo ERROR TELEGRAMS: $TESTNAME
|
||||||
echo -----------------
|
echo -----------------
|
||||||
diff /tmp/wmbusmeters_telegram_expected /tmp/wmbusmeters_telegram
|
diff /tmp/wmbusmeters_telegram_expected /tmp/wmbusmeters_telegram_output
|
||||||
echo -----------------
|
echo -----------------
|
||||||
TESTRESULT="ERROR"
|
TESTRESULT="ERROR"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -43,7 +43,7 @@ cat > $TEST/test_expected.txt <<EOF
|
||||||
{"media":"smoke detector","meter":"lansensm","name":"Rummet","id":"01000273","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
{"media":"smoke detector","meter":"lansensm","name":"Rummet","id":"01000273","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
$PROG --format=json simulations/simulation_duplicates.txt \
|
$PROG --format=json --ignoreduplicates=false simulations/simulation_duplicates.txt \
|
||||||
Rummet lansensm 01000273 "" \
|
Rummet lansensm 01000273 "" \
|
||||||
| grep Rummet > $TEST/test_output.txt
|
| grep Rummet > $TEST/test_output.txt
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ cat > $TEST/test_expected.txt <<EOF
|
||||||
{"media":"reserved","meter":"lansensm","name":"Forren","id":"00010206","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
{"media":"reserved","meter":"lansensm","name":"Forren","id":"00010206","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
$PROG --format=json --usestdoutforlogging simulations/simulation_unknown.txt $METERS > $TEST/test_output.txt
|
$PROG --format=json --ignoreduplicates=false --usestdoutforlogging simulations/simulation_unknown.txt $METERS > $TEST/test_output.txt
|
||||||
if [ "$?" = "0" ]
|
if [ "$?" = "0" ]
|
||||||
then
|
then
|
||||||
cat $TEST/test_output.txt | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/' > $TEST/test_responses.txt
|
cat $TEST/test_output.txt | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/' > $TEST/test_responses.txt
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
PROG="$1"
|
PROG="$1"
|
||||||
|
|
||||||
TEST=testaes
|
TEST=testoutput
|
||||||
|
|
||||||
rm -rf $TEST
|
rm -rf $TEST
|
||||||
mkdir -p $TEST
|
mkdir -p $TEST
|
||||||
|
@ -29,8 +29,11 @@ fi
|
||||||
cat <<EOF > $TEST/test_expected.txt
|
cat <<EOF > $TEST/test_expected.txt
|
||||||
Started config rtlwmbus on stdin listening on any
|
Started config rtlwmbus on stdin listening on any
|
||||||
(wmbus) decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 88888888 mfct: (APA) Apator, Poland (0x601) type: Water meter (0x07) ver: 0x05
|
(wmbus) decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 88888888 mfct: (APA) Apator, Poland (0x601) type: Water meter (0x07) ver: 0x05
|
||||||
|
(meter) newly created meter (ApWater 88888888 apator162) did not handle telegram!
|
||||||
(wmbus) decrypted payload crc failed check, did you use the correct decryption key? 979f payload crc (calculated 3431) Permanently ignoring telegrams from id: 76348799 mfct: (KAM) Kamstrup Energi (0x2c2d) type: Cold water meter (0x16) ver: 0x1b
|
(wmbus) decrypted payload crc failed check, did you use the correct decryption key? 979f payload crc (calculated 3431) Permanently ignoring telegrams from id: 76348799 mfct: (KAM) Kamstrup Energi (0x2c2d) type: Cold water meter (0x16) ver: 0x1b
|
||||||
|
(meter) newly created meter (Vatten 76348799 multical21) did not handle telegram!
|
||||||
(wmbus) decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 77777777 mfct: (SON) Sontex, Switzerland (0x4dee) type: Water meter (0x07) ver: 0x3c
|
(wmbus) decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 77777777 mfct: (SON) Sontex, Switzerland (0x4dee) type: Water meter (0x07) ver: 0x3c
|
||||||
|
(meter) newly created meter (Wasser 77777777 supercom587) did not handle telegram!
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
diff $TEST/test_expected.txt $TEST/test_stderr.txt
|
diff $TEST/test_expected.txt $TEST/test_stderr.txt
|
||||||
|
|
Ładowanie…
Reference in New Issue