Make sure metershell is invoked together with the first telegram content.

pull/1427/head
Fredrik Öhrström 2024-11-24 01:09:59 +01:00
rodzic 01c13ccfa5
commit 638894ac37
14 zmienionych plików z 109 dodań i 31 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -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.

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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_;
}

Wyświetl plik

@ -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;

Wyświetl plik

@ -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:

Wyświetl plik

@ -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_;

Wyświetl plik

@ -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);

Wyświetl plik

@ -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

Wyświetl plik

@ -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