kopia lustrzana https://github.com/weetmuts/wmbusmeters
Make sure metershell is invoked together with the first telegram content.
rodzic
01c13ccfa5
commit
638894ac37
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Use this script like this:
|
||||
# ./build/wmbusmeters --shell='./drivers/send_ha_discovery.sh "$METER_DRIVER" "$METER_JSON"' 1844AE4C4455223368077A55000000_041389E20100023B0000 Vatten iperl 33225544 NOKEY
|
||||
|
||||
DRIVER=$(mktemp /tmp/send_ha_discovery.driver.XXXXXX)
|
||||
TELEGRAM=$(mktemp /tmp/send_ha_discovery.json.XXXXXX)
|
||||
|
||||
cat <<< "$1" > $DRIVER
|
||||
cat <<< "$2" > $TELEGRAM
|
||||
|
||||
echo // Telegram content /////////////////////////////////////////////
|
||||
./build/xmq $TELEGRAM for-each '/telegram/node()' --shell='echo "${..} ... ${.}"'
|
||||
echo // DRIVER as xmq /////////////////////////////////////////////
|
||||
xmq $DRIVER to-xmq --compact
|
||||
echo // DRIVER as json /////////////////////////////////////////////
|
||||
xmq $DRIVER to-json
|
||||
echo // DRIVER as xml /////////////////////////////////////////////
|
||||
xmq $DRIVER to-xml
|
||||
# Generate a HA meter config. Reads the first telegram but does not acutally use the content.
|
||||
echo // HA CONFIG //////////////////////////////////////////
|
||||
./build/xmq $DRIVER transform --stringparam=file=$TELEGRAM drivers/to-ha-discovery.xslq to-json
|
||||
echo ///////////////////////////////////////////////////////
|
||||
|
||||
# You can convert the driver to json, if you prefer this.
|
||||
# ./build/xmq $DRIVER to-json > ${DRIVER}.json
|
||||
|
||||
rm -f $DRIVER_XMQ
|
||||
rm -f $TELEGRAM_JSON
|
|
@ -4,6 +4,13 @@ xsl:stylesheet(version = 1.0
|
|||
xmlns:xsl = http://www.w3.org/1999/XSL/Transform
|
||||
xmlns:my = https://wmbusmeters.org)
|
||||
{
|
||||
xsl:param(name = file)
|
||||
xsl:variable(name = telegram
|
||||
select = 'document($file)')
|
||||
xsl:variable(name = meter_id
|
||||
select = $telegram/telegram/id)
|
||||
xsl:variable(name = meter_name
|
||||
select = $telegram/telegram/name)
|
||||
my:tounit {
|
||||
entry(key = Volume) = m3
|
||||
entry(key = Flow) = m3h
|
||||
|
@ -48,6 +55,11 @@ xsl:stylesheet(version = 1.0
|
|||
xsl:element(name = '{name}_{$unito}')
|
||||
{
|
||||
component = sensor
|
||||
meter_name_id {
|
||||
xsl:value-of(select = $meter_name)
|
||||
'_'
|
||||
xsl:value-of(select = $meter_id)
|
||||
}
|
||||
discovery_payload {
|
||||
device {
|
||||
identifiers(A)
|
||||
|
|
|
@ -518,7 +518,7 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
if (cmd == "") {
|
||||
error("The meter shell command cannot be empty.\n");
|
||||
}
|
||||
c->meter_shells.push_back(cmd);
|
||||
c->new_meter_shells.push_back(cmd);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
int poll_interval = 0;
|
||||
IdentityMode identity_mode {};
|
||||
vector<string> telegram_shells;
|
||||
vector<string> meter_shells;
|
||||
vector<string> new_meter_shells;
|
||||
vector<string> alarm_shells;
|
||||
vector<string> extra_constant_fields;
|
||||
vector<string> extra_calculated_fields;
|
||||
|
@ -144,7 +144,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
}
|
||||
else
|
||||
if (p.first == "metershell") {
|
||||
meter_shells.push_back(p.second);
|
||||
new_meter_shells.push_back(p.second);
|
||||
}
|
||||
else
|
||||
if (p.first == "alarmshell") {
|
||||
|
@ -207,7 +207,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
mi.extra_constant_fields = extra_constant_fields;
|
||||
mi.extra_calculated_fields = extra_calculated_fields;
|
||||
mi.shells = telegram_shells;
|
||||
mi.meter_shells = meter_shells;
|
||||
mi.new_meter_shells = new_meter_shells;
|
||||
mi.selected_fields = selected_fields;
|
||||
c->meters.push_back(mi);
|
||||
}
|
||||
|
@ -646,7 +646,7 @@ void handleShell(Configuration *c, string cmdline)
|
|||
|
||||
void handleMeterShell(Configuration *c, string cmdline)
|
||||
{
|
||||
c->meter_shells.push_back(cmdline);
|
||||
c->new_meter_shells.push_back(cmdline);
|
||||
}
|
||||
|
||||
void handleAlarmShell(Configuration *c, string cmdline)
|
||||
|
|
|
@ -103,7 +103,7 @@ struct Configuration
|
|||
bool fields {};
|
||||
char separator { ';' };
|
||||
std::vector<std::string> telegram_shells;
|
||||
std::vector<std::string> meter_shells;
|
||||
std::vector<std::string> new_meter_shells;
|
||||
std::vector<std::string> alarm_shells;
|
||||
int alarm_timeout {}; // Maximum number of seconds between dongle receiving two telegrams.
|
||||
std::string alarm_expected_activity; // Only warn when within these time periods.
|
||||
|
|
11
src/main.cc
11
src/main.cc
|
@ -194,6 +194,7 @@ shared_ptr<Printer> create_printer(Configuration *config)
|
|||
config->fields,
|
||||
config->separator, config->meterfiles, config->meterfiles_dir,
|
||||
config->use_logfile, config->logfile,
|
||||
config->meter_shells,
|
||||
config->telegram_shells,
|
||||
config->meterfiles_action == MeterFileType::Overwrite,
|
||||
config->meterfiles_naming,
|
||||
|
@ -578,14 +579,6 @@ bool start(Configuration *config)
|
|||
// to achive a nice shutdown.
|
||||
onExit(call(serial_manager_.get(),stop));
|
||||
|
||||
/*
|
||||
Detected d;
|
||||
d.specified_device.file = "/dev/ttyUSB0";
|
||||
d.found_file = "/dev/ttyUSB0";
|
||||
d.specified_device.type = BusDeviceType::DEVICE_IU880B;
|
||||
|
||||
detectIU880B(&d, serial_manager_);
|
||||
*/
|
||||
// Create the printer object that knows how to translate
|
||||
// telegrams into json, fields that are written into log files
|
||||
// or sent to shell invocations.
|
||||
|
@ -608,7 +601,7 @@ bool start(Configuration *config)
|
|||
|
||||
// When a meter is added, print it, shell it, log it, etc.
|
||||
meter_manager_->whenMeterAdded(
|
||||
[&](shared_ptr<Meter> meter)
|
||||
[&](Meter *meter)
|
||||
{
|
||||
vector<string> *shells = &config->meter_shells;
|
||||
if (meter->shellCmdlinesMeterAdded().size() > 0) {
|
||||
|
|
|
@ -47,7 +47,7 @@ private:
|
|||
vector<MeterInfo> meter_templates_;
|
||||
vector<shared_ptr<Meter>> meters_;
|
||||
vector<function<bool(AboutTelegram&,vector<uchar>)>> telegram_listeners_;
|
||||
function<void(shared_ptr<Meter>)> on_meter_added_;
|
||||
function<void(Meter *Meter)> on_meter_added_;
|
||||
function<void(Telegram*t,Meter*)> on_meter_updated_;
|
||||
|
||||
public:
|
||||
|
@ -61,10 +61,10 @@ public:
|
|||
meters_.push_back(meter);
|
||||
meter->setIndex(meters_.size());
|
||||
meter->onUpdate(on_meter_updated_);
|
||||
triggerMeterAdded(meter);
|
||||
meter->setMeterManager(this);
|
||||
}
|
||||
|
||||
void triggerMeterAdded(shared_ptr<Meter> meter)
|
||||
void triggerMeterAdded(Meter *meter)
|
||||
{
|
||||
if (on_meter_added_) on_meter_added_(meter);
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ public:
|
|||
telegram_listeners_.push_back(cb);
|
||||
}
|
||||
|
||||
void whenMeterAdded(std::function<void(shared_ptr<Meter>)> cb)
|
||||
void whenMeterAdded(std::function<void(Meter*)> cb)
|
||||
{
|
||||
on_meter_added_ = cb;
|
||||
}
|
||||
|
|
|
@ -353,7 +353,7 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
|
|||
{
|
||||
addShellMeterUpdated(s);
|
||||
}
|
||||
for (auto s : mi.meter_shells)
|
||||
for (auto s : mi.new_meter_shells)
|
||||
{
|
||||
addShellMeterAdded(s);
|
||||
}
|
||||
|
@ -1401,9 +1401,6 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
|
|||
}
|
||||
|
||||
triggerUpdate(&t);
|
||||
/*string s = debugValues();
|
||||
|
||||
printf("\n\nVALUES------\n%s\n--------------\n", s.c_str());*/
|
||||
|
||||
if (out_analyzed != NULL) *out_analyzed = t;
|
||||
return true;
|
||||
|
@ -1892,6 +1889,7 @@ void MeterCommonImplementation::createMeterEnv(string id,
|
|||
envs->push_back(string("METER_ID="+id));
|
||||
envs->push_back(string("METER_NAME=")+name());
|
||||
envs->push_back(string("METER_TYPE=")+driverName().str());
|
||||
envs->push_back(string("METER_DRIVER=")+driver_info_->getDynamicSource());
|
||||
|
||||
// If the configuration has supplied json_address=Roodroad 123
|
||||
// then the env variable METER_address will available and have the content "Roodroad 123"
|
||||
|
@ -2020,7 +2018,6 @@ void MeterCommonImplementation::printMeter(Telegram *t,
|
|||
createMeterEnv(id, envs, extra_constant_fields);
|
||||
|
||||
envs->push_back(string("METER_JSON=")+*json);
|
||||
envs->push_back(string("METER_DRIVER=")+driver_info_->getDynamicSource());
|
||||
envs->push_back(string("METER_MEDIA=")+media);
|
||||
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());
|
||||
envs->push_back(string("METER_TIMESTAMP_UTC=")+datetimeOfUpdateRobot());
|
||||
|
@ -3237,3 +3234,13 @@ LIST_OF_METER_TYPES
|
|||
available_meter_types_[strlen(available_meter_types_)-1] = 0;
|
||||
return available_meter_types_;
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::setMeterManager(MeterManager *mm)
|
||||
{
|
||||
meter_manager_ = mm;
|
||||
}
|
||||
|
||||
MeterManager *MeterCommonImplementation::meterManager()
|
||||
{
|
||||
return meter_manager_;
|
||||
}
|
||||
|
|
15
src/meters.h
15
src/meters.h
|
@ -96,7 +96,7 @@ struct MeterInfo
|
|||
LinkModeSet link_modes;
|
||||
int bps {}; // For mbus communication you need to know the baud rate.
|
||||
vector<string> shells;
|
||||
vector<string> meter_shells;
|
||||
vector<string> new_meter_shells;
|
||||
vector<string> extra_constant_fields; // Additional static fields that are added to each message.
|
||||
vector<string> extra_calculated_fields; // Additional field calculated using formulas.
|
||||
vector<string> selected_fields; // Usually set to the default fields, but can be override in meter config.
|
||||
|
@ -119,7 +119,7 @@ struct MeterInfo
|
|||
address_expressions = aes;
|
||||
key = k;
|
||||
shells = s;
|
||||
meter_shells = ms;
|
||||
new_meter_shells = ms;
|
||||
extra_constant_fields = j;
|
||||
extra_calculated_fields = calcfs;
|
||||
link_modes = lms;
|
||||
|
@ -133,7 +133,7 @@ struct MeterInfo
|
|||
address_expressions.clear();
|
||||
key = "";
|
||||
shells.clear();
|
||||
meter_shells.clear();
|
||||
new_meter_shells.clear();
|
||||
extra_constant_fields.clear();
|
||||
extra_calculated_fields.clear();
|
||||
link_modes.clear();
|
||||
|
@ -379,6 +379,7 @@ private:
|
|||
};
|
||||
|
||||
struct BusManager;
|
||||
struct MeterManager;
|
||||
|
||||
struct Meter
|
||||
{
|
||||
|
@ -400,6 +401,8 @@ struct Meter
|
|||
virtual string name() = 0;
|
||||
virtual DriverName driverName() = 0;
|
||||
virtual DriverInfo *driverInfo() = 0;
|
||||
virtual bool hasReceivedFirstTelegram() = 0;
|
||||
virtual void markFirstTelegramReceived() = 0;
|
||||
|
||||
virtual string datetimeOfUpdateHumanReadable() = 0;
|
||||
virtual string datetimeOfUpdateRobot() = 0;
|
||||
|
@ -440,6 +443,8 @@ struct Meter
|
|||
bool simulated, std::vector<Address> *addresses,
|
||||
bool *id_match, Telegram *out_t = NULL) = 0;
|
||||
virtual MeterKeys *meterKeys() = 0;
|
||||
virtual void setMeterManager(MeterManager *mm) = 0;
|
||||
virtual MeterManager *meterManager() = 0;
|
||||
|
||||
virtual void addExtraCalculatedField(std::string ecf) = 0;
|
||||
virtual void addShellMeterAdded(std::string cmdline) = 0;
|
||||
|
@ -460,7 +465,7 @@ struct MeterManager
|
|||
{
|
||||
virtual void addMeterTemplate(MeterInfo &mi) = 0;
|
||||
virtual void addMeter(shared_ptr<Meter> meter) = 0;
|
||||
virtual void triggerMeterAdded(shared_ptr<Meter> meter) = 0;
|
||||
virtual void triggerMeterAdded(Meter *meter) = 0;
|
||||
virtual Meter*lastAddedMeter() = 0;
|
||||
virtual void removeAllMeters() = 0;
|
||||
virtual void forEachMeter(std::function<void(Meter*)> cb) = 0;
|
||||
|
@ -468,7 +473,7 @@ struct MeterManager
|
|||
virtual bool hasAllMetersReceivedATelegram() = 0;
|
||||
virtual bool hasMeters() = 0;
|
||||
virtual void onTelegram(function<bool(AboutTelegram&,vector<uchar>)> cb) = 0;
|
||||
virtual void whenMeterAdded(std::function<void(shared_ptr<Meter>)> cb) = 0;
|
||||
virtual void whenMeterAdded(std::function<void(Meter*)> cb) = 0;
|
||||
virtual void whenMeterUpdated(std::function<void(Telegram*t,Meter*)> cb) = 0;
|
||||
virtual void pollMeters(shared_ptr<BusManager> bus) = 0;
|
||||
virtual void analyzeEnabled(bool b, OutputFormat f, string force_driver, string key, bool verbose, int profile) = 0;
|
||||
|
|
|
@ -85,6 +85,8 @@ struct MeterCommonImplementation : public virtual Meter
|
|||
|
||||
static bool isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi);
|
||||
MeterKeys *meterKeys();
|
||||
void setMeterManager(MeterManager *mm);
|
||||
MeterManager *meterManager();
|
||||
|
||||
MeterCommonImplementation(MeterInfo &mi, DriverInfo &di);
|
||||
|
||||
|
@ -212,6 +214,8 @@ protected:
|
|||
void setSelectedFields(vector<string> &f) { selected_fields_ = f; }
|
||||
|
||||
void forceMfctIndex(int i) { force_mfct_index_ = i; }
|
||||
bool hasReceivedFirstTelegram() { return has_received_first_telegram_; }
|
||||
void markFirstTelegramReceived() { has_received_first_telegram_ = true; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -238,6 +242,8 @@ private:
|
|||
Translate::Lookup mfct_tpl_status_bits_ = NoLookup;
|
||||
int force_mfct_index_ = -1;
|
||||
bool has_process_content_ = false;
|
||||
bool has_received_first_telegram_ = false;
|
||||
MeterManager *meter_manager_ {};
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ using namespace std;
|
|||
Printer::Printer(bool json, bool pretty_print_json, bool fields, char separator,
|
||||
bool use_meterfiles, string &meterfiles_dir,
|
||||
bool use_logfile, string &logfile,
|
||||
vector<string> new_meter_shell_cmdlines,
|
||||
vector<string> shell_cmdlines, bool overwrite,
|
||||
MeterFileNaming naming,
|
||||
MeterFileTimestamp timestamp)
|
||||
|
@ -35,6 +36,7 @@ Printer::Printer(bool json, bool pretty_print_json, bool fields, char separator,
|
|||
meterfiles_dir_ = meterfiles_dir;
|
||||
use_logfile_ = use_logfile;
|
||||
logfile_ = logfile;
|
||||
new_meter_shell_cmdlines_ = new_meter_shell_cmdlines;
|
||||
shell_cmdlines_ = shell_cmdlines;
|
||||
overwrite_ = overwrite;
|
||||
naming_ = naming;
|
||||
|
@ -51,6 +53,13 @@ void Printer::print(Telegram *t, Meter *meter,
|
|||
|
||||
meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields, pretty_print_json_);
|
||||
|
||||
if (!meter->hasReceivedFirstTelegram() &&
|
||||
(new_meter_shell_cmdlines_.size() > 0 || meter->shellCmdlinesMeterAdded().size() > 0))
|
||||
{
|
||||
meter->markFirstTelegramReceived();
|
||||
envs.push_back("METER_ADDED=true");
|
||||
printNewMeterShells(meter, envs);
|
||||
}
|
||||
if (shell_cmdlines_.size() > 0 || meter->shellCmdlinesMeterUpdated().size() > 0) {
|
||||
printShells(meter, envs);
|
||||
printed = true;
|
||||
|
@ -66,6 +75,20 @@ void Printer::print(Telegram *t, Meter *meter,
|
|||
}
|
||||
}
|
||||
|
||||
void Printer::printNewMeterShells(Meter *meter, vector<string> &envs)
|
||||
{
|
||||
vector<string> *shells = &new_meter_shell_cmdlines_;
|
||||
if (meter->shellCmdlinesMeterAdded().size() > 0) {
|
||||
shells = &meter->shellCmdlinesMeterAdded();
|
||||
}
|
||||
for (auto &s : *shells) {
|
||||
vector<string> args;
|
||||
args.push_back("-c");
|
||||
args.push_back(s);
|
||||
invokeShell("/bin/sh", args, envs);
|
||||
}
|
||||
}
|
||||
|
||||
void Printer::printShells(Meter *meter, vector<string> &envs)
|
||||
{
|
||||
vector<string> *shells = &shell_cmdlines_;
|
||||
|
|
|
@ -28,6 +28,7 @@ struct Printer {
|
|||
char separator,
|
||||
bool meterfiles, string &meterfiles_dir,
|
||||
bool use_logfile, string &logfile,
|
||||
vector<string> new_meter_shell_cmdlines,
|
||||
vector<string> shell_cmdlines,
|
||||
bool overwrite,
|
||||
MeterFileNaming naming,
|
||||
|
@ -43,11 +44,13 @@ struct Printer {
|
|||
bool use_logfile_;
|
||||
string logfile_;
|
||||
char separator_;
|
||||
vector<string> new_meter_shell_cmdlines_;
|
||||
vector<string> shell_cmdlines_;
|
||||
bool overwrite_;
|
||||
MeterFileNaming naming_;
|
||||
MeterFileTimestamp timestamp_;
|
||||
|
||||
void printNewMeterShells(Meter *meter, vector<string> &envs);
|
||||
void printShells(Meter *meter, vector<string> &envs);
|
||||
void printFiles(Meter *meter, Telegram *t, string &human_readable, string &fields, string &json);
|
||||
|
||||
|
|
|
@ -2,4 +2,4 @@ loglevel=debug
|
|||
device=simulations/simulation_metershell.txt
|
||||
logtelegrams=false
|
||||
format=json
|
||||
metershell=echo "IF THIS IS STOREd THEN THERE IS A BUG" > /tmp/wmbusmeters_metershell1_test
|
||||
metershell=echo "IF THIS IS STORE config14 THEN THERE IS A BUG" > /tmp/wmbusmeters_metershell1_test
|
|
@ -2,4 +2,4 @@ loglevel=debug
|
|||
device=simulations/simulation_shell.txt
|
||||
logtelegrams=false
|
||||
format=json
|
||||
shell=echo "IF THIS IS STOREd THEN THERE IS A BUG" > /tmp/wmbusmeters_meter_shell_test
|
||||
shell=echo "IF THIS IS STORED config5 THEN THERE IS A BUG" > /tmp/wmbusmeters_meter_shell_test
|
Ładowanie…
Reference in New Issue