kopia lustrzana https://github.com/weetmuts/wmbusmeters
New field printing works for partially converted sharky driver.
rodzic
3e56671bfc
commit
ebae419f82
|
@ -261,6 +261,7 @@ As {options} you can use:
|
||||||
--nodeviceexit if no wmbus devices are found, then exit immediately
|
--nodeviceexit if no wmbus devices are found, then exit immediately
|
||||||
--normal for normal logging
|
--normal for normal logging
|
||||||
--oneshot wait for an update from each meter, then quit
|
--oneshot wait for an update from each meter, then quit
|
||||||
|
--ppjson pretty print the json
|
||||||
--resetafter=<time> reset the wmbus dongle regularly, default is 23h
|
--resetafter=<time> reset the wmbus dongle regularly, default is 23h
|
||||||
--selectfields=id,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields)
|
--selectfields=id,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields)
|
||||||
--separator=<c> change field separator to c
|
--separator=<c> change field separator to c
|
||||||
|
|
|
@ -242,6 +242,12 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(argv[i], "--ppjson"))
|
||||||
|
{
|
||||||
|
c->pretty_print_json = true;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strncmp(argv[i], "--format=", 9))
|
if (!strncmp(argv[i], "--format=", 9))
|
||||||
{
|
{
|
||||||
if (!strcmp(argv[i]+9, "json"))
|
if (!strcmp(argv[i]+9, "json"))
|
||||||
|
|
|
@ -95,6 +95,7 @@ struct Configuration
|
||||||
bool ignore_duplicate_telegrams = true; // Default is to ignore duplicates.
|
bool ignore_duplicate_telegrams = true; // Default is to ignore duplicates.
|
||||||
std::string logfile;
|
std::string logfile;
|
||||||
bool json {};
|
bool json {};
|
||||||
|
bool pretty_print_json {};
|
||||||
bool fields {};
|
bool fields {};
|
||||||
char separator { ';' };
|
char separator { ';' };
|
||||||
std::vector<std::string> telegram_shells;
|
std::vector<std::string> telegram_shells;
|
||||||
|
|
|
@ -23,7 +23,6 @@ struct MeterSharky : public virtual MeterCommonImplementation
|
||||||
MeterSharky(MeterInfo &mi, DriverInfo &di);
|
MeterSharky(MeterInfo &mi, DriverInfo &di);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double total_energy_kwh_ {};
|
|
||||||
double total_energy_tariff1_kwh_ {};
|
double total_energy_tariff1_kwh_ {};
|
||||||
double total_volume_m3_ {};
|
double total_volume_m3_ {};
|
||||||
double total_volume_tariff2_m3_ {};
|
double total_volume_tariff2_m3_ {};
|
||||||
|
@ -58,8 +57,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT,
|
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT,
|
||||||
"The total heat energy consumption recorded by this meter.",
|
"The total heat energy consumption recorded by this meter.",
|
||||||
SET_FUNC(total_energy_kwh_, Unit::KWH),
|
NULL,
|
||||||
GET_FUNC(total_energy_kwh_, Unit::KWH));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"total_energy_consumption_tariff1",
|
"total_energy_consumption_tariff1",
|
||||||
|
@ -73,21 +72,19 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The total heat energy consumption recorded by this meter on tariff 1.",
|
"The total heat energy consumption recorded by this meter on tariff 1.",
|
||||||
SET_FUNC(total_energy_tariff1_kwh_, Unit::KWH),
|
NULL,
|
||||||
GET_FUNC(total_energy_tariff1_kwh_, Unit::KWH));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"total_volume",
|
"total_volume",
|
||||||
|
"The total heating media volume recorded by this meter.",
|
||||||
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
Quantity::Volume,
|
Quantity::Volume,
|
||||||
VifScaling::Auto,
|
VifScaling::Auto,
|
||||||
FieldMatcher::build()
|
FieldMatcher::build()
|
||||||
.set(MeasurementType::Instantaneous)
|
.set(MeasurementType::Instantaneous)
|
||||||
.set(VIFRange::Volume)
|
.set(VIFRange::Volume)
|
||||||
,
|
);
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
|
||||||
"The total heating media volume recorded by this meter.",
|
|
||||||
SET_FUNC(total_volume_m3_, Unit::M3),
|
|
||||||
GET_FUNC(total_volume_m3_, Unit::M3));
|
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"total_volume_tariff2",
|
"total_volume_tariff2",
|
||||||
|
@ -101,8 +98,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The total heating media volume recorded by this meter on tariff 2.",
|
"The total heating media volume recorded by this meter on tariff 2.",
|
||||||
SET_FUNC(total_volume_tariff2_m3_, Unit::M3),
|
NULL,
|
||||||
GET_FUNC(total_volume_tariff2_m3_, Unit::M3));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"volume_flow",
|
"volume_flow",
|
||||||
|
@ -116,8 +113,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The current heat media volume flow.",
|
"The current heat media volume flow.",
|
||||||
SET_FUNC(volume_flow_m3h_, Unit::M3H),
|
NULL,
|
||||||
GET_FUNC(volume_flow_m3h_, Unit::M3H));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"power",
|
"power",
|
||||||
|
@ -131,8 +128,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The current power consumption.",
|
"The current power consumption.",
|
||||||
SET_FUNC(power_kw_, Unit::KW),
|
NULL,
|
||||||
GET_FUNC(power_kw_, Unit::KW));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"flow_temperature",
|
"flow_temperature",
|
||||||
|
@ -146,8 +143,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The current forward heat media temperature.",
|
"The current forward heat media temperature.",
|
||||||
SET_FUNC(flow_temperature_c_, Unit::C),
|
NULL,
|
||||||
GET_FUNC(flow_temperature_c_, Unit::C));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"return_temperature",
|
"return_temperature",
|
||||||
|
@ -161,8 +158,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The current return heat media temperature.",
|
"The current return heat media temperature.",
|
||||||
SET_FUNC(return_temperature_c_, Unit::C),
|
NULL,
|
||||||
GET_FUNC(return_temperature_c_, Unit::C));
|
NULL);
|
||||||
|
|
||||||
addNumericFieldWithExtractor(
|
addNumericFieldWithExtractor(
|
||||||
"temperature_difference",
|
"temperature_difference",
|
||||||
|
@ -176,8 +173,8 @@ MeterSharky::MeterSharky(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementat
|
||||||
IndexNr(1),
|
IndexNr(1),
|
||||||
PrintProperty::JSON | PrintProperty::FIELD,
|
PrintProperty::JSON | PrintProperty::FIELD,
|
||||||
"The current return heat media temperature.",
|
"The current return heat media temperature.",
|
||||||
SET_FUNC(temperature_difference_c_, Unit::C),
|
NULL,
|
||||||
GET_FUNC(temperature_difference_c_, Unit::C));
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test: Heat sharky ANYID NOKEY
|
// Test: Heat sharky ANYID NOKEY
|
||||||
|
|
|
@ -108,7 +108,6 @@ bool parseDV(Telegram *t,
|
||||||
vector<uchar>::iterator data,
|
vector<uchar>::iterator data,
|
||||||
size_t data_len,
|
size_t data_len,
|
||||||
map<string,pair<int,DVEntry>> *dv_entries,
|
map<string,pair<int,DVEntry>> *dv_entries,
|
||||||
vector<DVEntry*> *dv_entries_ordered,
|
|
||||||
vector<uchar>::iterator *format,
|
vector<uchar>::iterator *format,
|
||||||
size_t format_len,
|
size_t format_len,
|
||||||
uint16_t *format_hash)
|
uint16_t *format_hash)
|
||||||
|
@ -142,7 +141,6 @@ bool parseDV(Telegram *t,
|
||||||
}
|
}
|
||||||
|
|
||||||
dv_entries->clear();
|
dv_entries->clear();
|
||||||
dv_entries_ordered->clear();
|
|
||||||
|
|
||||||
// Data format is:
|
// Data format is:
|
||||||
|
|
||||||
|
@ -345,12 +343,9 @@ bool parseDV(Telegram *t,
|
||||||
SubUnitNr(subunit),
|
SubUnitNr(subunit),
|
||||||
value) };
|
value) };
|
||||||
|
|
||||||
(*dv_entries_ordered).push_back( &(*dv_entries)[key].second );
|
DVEntry *dve = &(*dv_entries)[key].second;
|
||||||
|
|
||||||
DVEntry *dve = (*dv_entries_ordered).back();
|
assert(key == dve->dif_vif_key.str());
|
||||||
DVEntry *dvee = &(*dv_entries)[key].second;
|
|
||||||
|
|
||||||
assert(key == dve->dif_vif_key.str() && key == dvee->dif_vif_key.str());
|
|
||||||
|
|
||||||
if (value.length() > 0) {
|
if (value.length() > 0) {
|
||||||
// This call increments data with datalen.
|
// This call increments data with datalen.
|
||||||
|
|
|
@ -174,7 +174,6 @@ struct DVEntry
|
||||||
TariffNr tariff_nr;
|
TariffNr tariff_nr;
|
||||||
SubUnitNr subunit_nr;
|
SubUnitNr subunit_nr;
|
||||||
std::string value;
|
std::string value;
|
||||||
FieldInfo *field_info {}; // The field info selected to decode this entry.
|
|
||||||
|
|
||||||
DVEntry(int off, DifVifKey dvk, MeasurementType mt, Vif vi, StorageNr st, TariffNr ta, SubUnitNr su, std::string &val) :
|
DVEntry(int off, DifVifKey dvk, MeasurementType mt, Vif vi, StorageNr st, TariffNr ta, SubUnitNr su, std::string &val) :
|
||||||
offset(off), dif_vif_key(dvk), measurement_type(mt), vif(vi), storage_nr(st), tariff_nr(ta), subunit_nr(su), value(val) {}
|
offset(off), dif_vif_key(dvk), measurement_type(mt), vif(vi), storage_nr(st), tariff_nr(ta), subunit_nr(su), value(val) {}
|
||||||
|
@ -186,6 +185,11 @@ struct DVEntry
|
||||||
bool extractDate(struct tm *out);
|
bool extractDate(struct tm *out);
|
||||||
bool extractReadableString(std::string *out);
|
bool extractReadableString(std::string *out);
|
||||||
bool hasVifes();
|
bool hasVifes();
|
||||||
|
void setFieldInfo(FieldInfo *fi) { field_info_ = fi; }
|
||||||
|
FieldInfo *getFieldInfo() { return field_info_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
FieldInfo *field_info_ {}; // The field info selected to decode this entry.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldMatcher
|
struct FieldMatcher
|
||||||
|
@ -279,7 +283,6 @@ bool parseDV(Telegram *t,
|
||||||
std::vector<uchar>::iterator data,
|
std::vector<uchar>::iterator data,
|
||||||
size_t data_len,
|
size_t data_len,
|
||||||
std::map<std::string,std::pair<int,DVEntry>> *dv_entries,
|
std::map<std::string,std::pair<int,DVEntry>> *dv_entries,
|
||||||
std::vector<DVEntry*> *dv_entries_ordered,
|
|
||||||
std::vector<uchar>::iterator *format = NULL,
|
std::vector<uchar>::iterator *format = NULL,
|
||||||
size_t format_len = 0,
|
size_t format_len = 0,
|
||||||
uint16_t *format_hash = NULL);
|
uint16_t *format_hash = NULL);
|
||||||
|
|
|
@ -50,11 +50,10 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<DVEntry> dv_entries_ordered;
|
map<string,pair<int,DVEntry>> dv_entries;
|
||||||
map<string,pair<int,DVEntry*>> dv_entries;
|
|
||||||
|
|
||||||
Telegram t;
|
Telegram t;
|
||||||
vector<uchar>::iterator i = databytes.begin();
|
vector<uchar>::iterator i = databytes.begin();
|
||||||
|
|
||||||
parseDV(&t, databytes, i, databytes.size(), &dv_entries, &dv_entries_ordered);
|
parseDV(&t, databytes, i, databytes.size(), &dv_entries);
|
||||||
}
|
}
|
||||||
|
|
20
src/main.cc
20
src/main.cc
|
@ -174,7 +174,9 @@ provided you with this binary. Read the full license for all details.
|
||||||
|
|
||||||
shared_ptr<Printer> create_printer(Configuration *config)
|
shared_ptr<Printer> create_printer(Configuration *config)
|
||||||
{
|
{
|
||||||
return shared_ptr<Printer>(new Printer(config->json, config->fields,
|
return shared_ptr<Printer>(new Printer(config->json,
|
||||||
|
config->pretty_print_json,
|
||||||
|
config->fields,
|
||||||
config->separator, config->meterfiles, config->meterfiles_dir,
|
config->separator, config->meterfiles, config->meterfiles_dir,
|
||||||
config->use_logfile, config->logfile,
|
config->use_logfile, config->logfile,
|
||||||
config->telegram_shells,
|
config->telegram_shells,
|
||||||
|
@ -249,7 +251,13 @@ void list_fields(Configuration *config, string meter_driver)
|
||||||
int width = 13; // Width of timestamp_utc
|
int width = 13; // Width of timestamp_utc
|
||||||
for (FieldInfo &fi : meter->fieldInfos())
|
for (FieldInfo &fi : meter->fieldInfos())
|
||||||
{
|
{
|
||||||
if ((int)fi.vname().size() > width) width = fi.vname().size();
|
string name = fi.vname();
|
||||||
|
if (fi.xuantity() != Quantity::Text)
|
||||||
|
{
|
||||||
|
name += "_"+unitToStringLowerCase(defaultUnitForQuantity(fi.xuantity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)name.size() > width) width = name.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
string id = padLeft("id", width);
|
string id = padLeft("id", width);
|
||||||
|
@ -275,7 +283,13 @@ void list_fields(Configuration *config, string meter_driver)
|
||||||
for (auto &fi : meter->fieldInfos())
|
for (auto &fi : meter->fieldInfos())
|
||||||
{
|
{
|
||||||
if (fi.vname() == "") continue;
|
if (fi.vname() == "") continue;
|
||||||
string fn = padLeft(fi.vname(), width);
|
string name = fi.vname();
|
||||||
|
if (fi.xuantity() != Quantity::Text)
|
||||||
|
{
|
||||||
|
name += "_"+unitToStringLowerCase(defaultUnitForQuantity(fi.xuantity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
string fn = padLeft(name, width);
|
||||||
printf("%s %s\n", fn.c_str(), fi.help().c_str());
|
printf("%s %s\n", fn.c_str(), fi.help().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -773,7 +773,8 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity,
|
||||||
function<double(Unit)> getValueFunc, string help, PrintProperties pprops)
|
function<double(Unit)> getValueFunc, string help, PrintProperties pprops)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
VifScaling::Auto,
|
VifScaling::Auto,
|
||||||
|
@ -792,7 +793,8 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity, Unit
|
||||||
function<double(Unit)> getValueFunc, string help, PrintProperties pprops)
|
function<double(Unit)> getValueFunc, string help, PrintProperties pprops)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
unit,
|
unit,
|
||||||
VifScaling::Auto,
|
VifScaling::Auto,
|
||||||
|
@ -812,7 +814,8 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity,
|
||||||
string help, PrintProperties pprops)
|
string help, PrintProperties pprops)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
VifScaling::Auto,
|
VifScaling::Auto,
|
||||||
|
@ -843,7 +846,8 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(
|
||||||
function<double(Unit)> getValueFunc)
|
function<double(Unit)> getValueFunc)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
vif_scaling,
|
vif_scaling,
|
||||||
|
@ -858,27 +862,25 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeterCommonImplementation::addNumericFieldWithExtractor(
|
void MeterCommonImplementation::addNumericFieldWithExtractor(string vname,
|
||||||
string vname,
|
string help,
|
||||||
Quantity vquantity,
|
PrintProperties print_properties,
|
||||||
VifScaling vif_scaling,
|
Quantity vquantity,
|
||||||
FieldMatcher matcher,
|
VifScaling vif_scaling,
|
||||||
PrintProperties print_properties,
|
FieldMatcher matcher)
|
||||||
string help,
|
|
||||||
function<void(Unit,double)> setValueFunc,
|
|
||||||
function<double(Unit)> getValueFunc)
|
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
vif_scaling,
|
vif_scaling,
|
||||||
matcher,
|
matcher,
|
||||||
help,
|
help,
|
||||||
print_properties,
|
print_properties,
|
||||||
getValueFunc,
|
|
||||||
NULL,
|
NULL,
|
||||||
setValueFunc,
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NoLookup
|
NoLookup
|
||||||
));
|
));
|
||||||
|
@ -893,7 +895,8 @@ void MeterCommonImplementation::addNumericField(
|
||||||
function<double(Unit)> getValueFunc)
|
function<double(Unit)> getValueFunc)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
VifScaling::None,
|
VifScaling::None,
|
||||||
|
@ -923,7 +926,8 @@ void MeterCommonImplementation::addStringFieldWithExtractor(
|
||||||
function<string()> getValueFunc)
|
function<string()> getValueFunc)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
VifScaling::None,
|
VifScaling::None,
|
||||||
|
@ -954,7 +958,8 @@ void MeterCommonImplementation::addStringFieldWithExtractorAndLookup(
|
||||||
Translate::Lookup lookup)
|
Translate::Lookup lookup)
|
||||||
{
|
{
|
||||||
field_infos_.push_back(
|
field_infos_.push_back(
|
||||||
FieldInfo(vname,
|
FieldInfo(field_infos_.size(),
|
||||||
|
vname,
|
||||||
vquantity,
|
vquantity,
|
||||||
defaultUnitForQuantity(vquantity),
|
defaultUnitForQuantity(vquantity),
|
||||||
VifScaling::None,
|
VifScaling::None,
|
||||||
|
@ -1462,15 +1467,15 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
|
||||||
void MeterCommonImplementation::processFieldExtractors(Telegram *t)
|
void MeterCommonImplementation::processFieldExtractors(Telegram *t)
|
||||||
{
|
{
|
||||||
// Iterate through the dv_entries in the telegram.
|
// Iterate through the dv_entries in the telegram.
|
||||||
|
for (auto &p : t->dv_entries)
|
||||||
for (auto i = t->dv_entries_ordered.begin(); i != t->dv_entries_ordered.end(); ++i)
|
|
||||||
{
|
{
|
||||||
DVEntry *dve = *i;
|
DVEntry *dve = &p.second.second;
|
||||||
for (FieldInfo &fi : field_infos_)
|
for (FieldInfo &fi : field_infos_)
|
||||||
{
|
{
|
||||||
if (fi.hasMatcher() && fi.matches(dve))
|
if (fi.hasMatcher() && fi.matches(dve))
|
||||||
{
|
{
|
||||||
debug("Using field info %s to extract %d\n", fi.vname().c_str(), dve->dif_vif_key.str().c_str());
|
debug("Using field info %s to extract %d\n", fi.vname().c_str(), dve->dif_vif_key.str().c_str());
|
||||||
|
dve->setFieldInfo(&fi);
|
||||||
fi.performExtraction(this, t, dve);
|
fi.performExtraction(this, t, dve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1511,7 +1516,7 @@ double MeterCommonImplementation::getNumericValue(FieldInfo *fi, Unit to)
|
||||||
}
|
}
|
||||||
|
|
||||||
string field_name_no_unit = fi->vname();
|
string field_name_no_unit = fi->vname();
|
||||||
if (numeric_values_.count(field_name_no_unit) == 0) return -471147114711;
|
assert(numeric_values_.count(field_name_no_unit) != 0);
|
||||||
NumericField &nf = numeric_values_[field_name_no_unit];
|
NumericField &nf = numeric_values_[field_name_no_unit];
|
||||||
return convert(nf.value, nf.unit, to);
|
return convert(nf.value, nf.unit, to);
|
||||||
}
|
}
|
||||||
|
@ -1525,7 +1530,6 @@ void MeterCommonImplementation::setStringValue(FieldInfo *fi, string v)
|
||||||
}
|
}
|
||||||
|
|
||||||
string field_name_no_unit = fi->vname();
|
string field_name_no_unit = fi->vname();
|
||||||
//printf("Setting string %s = %s\n", field_name_no_unit.c_str(), v.c_str());
|
|
||||||
string_values_[field_name_no_unit] = StringField(v, fi);
|
string_values_[field_name_no_unit] = StringField(v, fi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1537,7 +1541,7 @@ string MeterCommonImplementation::getStringValue(FieldInfo *fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
string field_name_no_unit = fi->vname();
|
string field_name_no_unit = fi->vname();
|
||||||
if (string_values_.count(field_name_no_unit) == 0) return "???";
|
assert (string_values_.count(field_name_no_unit) != 0);
|
||||||
StringField &sf = string_values_[field_name_no_unit];
|
StringField &sf = string_values_[field_name_no_unit];
|
||||||
return sf.value;
|
return sf.value;
|
||||||
}
|
}
|
||||||
|
@ -1664,13 +1668,35 @@ void MeterCommonImplementation::printMeter(Telegram *t,
|
||||||
{
|
{
|
||||||
s += indent+"\"id\":\"\","+newline;
|
s += indent+"\"id\":\"\","+newline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate over the meter field infos...
|
||||||
for (FieldInfo& fi : field_infos_)
|
for (FieldInfo& fi : field_infos_)
|
||||||
{
|
{
|
||||||
if (fi.printProperties().hasJSON())
|
if (fi.printProperties().hasJSON())
|
||||||
{
|
{
|
||||||
s += indent+fi.renderJson(this, &conversions())+","+newline;
|
// The field should be printed in the json. (Most usually should.)
|
||||||
|
bool found = false;
|
||||||
|
for (auto& i : t->dv_entries)
|
||||||
|
{
|
||||||
|
// Check each telegram dv entry.
|
||||||
|
DVEntry *dve = &i.second.second;
|
||||||
|
// Has the entry been matches to this field, then print it as json.
|
||||||
|
if (dve->getFieldInfo() == &fi)
|
||||||
|
{
|
||||||
|
s += indent+fi.renderJson(this, &conversions())+","+newline;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found && !fi.printProperties().hasOPTIONAL())
|
||||||
|
{
|
||||||
|
// No telegram entries found, but this field should be printed anyway.
|
||||||
|
// It will be printed with any value received from a previous telegram.
|
||||||
|
// Or if no value has been received, a default bad value, like -12345678
|
||||||
|
s += indent+fi.renderJson(this, &conversions())+","+newline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s += indent+"\"timestamp\":\""+datetimeOfUpdateRobot()+"\"";
|
s += indent+"\"timestamp\":\""+datetimeOfUpdateRobot()+"\"";
|
||||||
|
|
||||||
if (t->about.device != "")
|
if (t->about.device != "")
|
||||||
|
|
|
@ -287,7 +287,7 @@ enum PrintProperty
|
||||||
JSON = 1, // This field should be printed when using --format=json
|
JSON = 1, // This field should be printed when using --format=json
|
||||||
FIELD = 2, // This field should be printed when using --format=field
|
FIELD = 2, // This field should be printed when using --format=field
|
||||||
IMPORTANT = 4, // The most important field.
|
IMPORTANT = 4, // The most important field.
|
||||||
OPTIONAL = 8, // If no data has arrived, do include this field in the json output.
|
OPTIONAL = 8, // If no data has arrived, then do not include this field in the json output.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PrintProperties
|
struct PrintProperties
|
||||||
|
@ -309,7 +309,8 @@ struct PrintProperties
|
||||||
|
|
||||||
struct FieldInfo
|
struct FieldInfo
|
||||||
{
|
{
|
||||||
FieldInfo(string vname,
|
FieldInfo(int index,
|
||||||
|
string vname,
|
||||||
Quantity xuantity,
|
Quantity xuantity,
|
||||||
Unit default_unit,
|
Unit default_unit,
|
||||||
VifScaling vif_scaling,
|
VifScaling vif_scaling,
|
||||||
|
@ -322,6 +323,7 @@ struct FieldInfo
|
||||||
function<void(string)> set_string_value_override,
|
function<void(string)> set_string_value_override,
|
||||||
Translate::Lookup lookup
|
Translate::Lookup lookup
|
||||||
) :
|
) :
|
||||||
|
index_(index),
|
||||||
vname_(vname),
|
vname_(vname),
|
||||||
xuantity_(xuantity),
|
xuantity_(xuantity),
|
||||||
default_unit_(default_unit),
|
default_unit_(default_unit),
|
||||||
|
@ -336,6 +338,7 @@ struct FieldInfo
|
||||||
lookup_(lookup)
|
lookup_(lookup)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
int index() { return index_; }
|
||||||
string vname() { return vname_; }
|
string vname() { return vname_; }
|
||||||
Quantity xuantity() { return xuantity_; }
|
Quantity xuantity() { return xuantity_; }
|
||||||
Unit defaultUnit() { return default_unit_; }
|
Unit defaultUnit() { return default_unit_; }
|
||||||
|
@ -374,6 +377,7 @@ struct FieldInfo
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
int index_; // The field infos for a meter are ordered.
|
||||||
string vname_; // Value name, like: total current previous target, ie no unit suffix.
|
string vname_; // Value name, like: total current previous target, ie no unit suffix.
|
||||||
Quantity xuantity_; // Quantity: Energy, Volume
|
Quantity xuantity_; // Quantity: Energy, Volume
|
||||||
Unit default_unit_; // Default unit for above quantity: KWH, M3
|
Unit default_unit_; // Default unit for above quantity: KWH, M3
|
||||||
|
|
|
@ -128,14 +128,12 @@ protected:
|
||||||
function<double(Unit)> getValueFunc); // Use the GET macro above.
|
function<double(Unit)> getValueFunc); // Use the GET macro above.
|
||||||
|
|
||||||
void addNumericFieldWithExtractor(
|
void addNumericFieldWithExtractor(
|
||||||
string vname, // Name of value without unit, eg total
|
string vname, // Name of value without unit, eg "total" "total_month{storagenr}"
|
||||||
Quantity vquantity, // Value belongs to this quantity.
|
string help, // Information about this field.
|
||||||
VifScaling vif_scaling,
|
|
||||||
FieldMatcher matcher,
|
|
||||||
PrintProperties print_properties, // Should this be printed by default in fields,json and hr.
|
PrintProperties print_properties, // Should this be printed by default in fields,json and hr.
|
||||||
string help,
|
Quantity vquantity, // Value belongs to this quantity, this quantity determines the default unit.
|
||||||
function<void(Unit,double)> setValueFunc, // Use the SET macro above.
|
VifScaling vif_scaling, // How should any Vif value be scaled.
|
||||||
function<double(Unit)> getValueFunc); // Use the GET macro above.
|
FieldMatcher matcher);
|
||||||
|
|
||||||
void addNumericField(
|
void addNumericField(
|
||||||
string vname, // Name of value without unit, eg total
|
string vname, // Name of value without unit, eg total
|
||||||
|
@ -162,6 +160,12 @@ protected:
|
||||||
function<void(string)> setValueFunc, // Use the SET_STRING macro above.
|
function<void(string)> setValueFunc, // Use the SET_STRING macro above.
|
||||||
function<string()> getValueFunc); // Use the GET_STRING macro above.
|
function<string()> getValueFunc); // Use the GET_STRING macro above.
|
||||||
|
|
||||||
|
void addStringFieldWithExtractor(
|
||||||
|
string vname,
|
||||||
|
string help,
|
||||||
|
PrintProperties print_properties,
|
||||||
|
FieldMatcher matcher);
|
||||||
|
|
||||||
void addStringFieldWithExtractorAndLookup(
|
void addStringFieldWithExtractorAndLookup(
|
||||||
string vname, // Name of value without unit, eg total
|
string vname, // Name of value without unit, eg total
|
||||||
Quantity vquantity, // Value belongs to this quantity.
|
Quantity vquantity, // Value belongs to this quantity.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Printer::Printer(bool json, bool fields, char separator,
|
Printer::Printer(bool json, bool pretty_print_json, bool fields, char separator,
|
||||||
bool use_meterfiles, string &meterfiles_dir,
|
bool use_meterfiles, string &meterfiles_dir,
|
||||||
bool use_logfile, string &logfile,
|
bool use_logfile, string &logfile,
|
||||||
vector<string> shell_cmdlines, bool overwrite,
|
vector<string> shell_cmdlines, bool overwrite,
|
||||||
|
@ -28,6 +28,7 @@ Printer::Printer(bool json, bool fields, char separator,
|
||||||
MeterFileTimestamp timestamp)
|
MeterFileTimestamp timestamp)
|
||||||
{
|
{
|
||||||
json_ = json;
|
json_ = json;
|
||||||
|
pretty_print_json_ = pretty_print_json;
|
||||||
fields_ = fields;
|
fields_ = fields;
|
||||||
separator_ = separator;
|
separator_ = separator;
|
||||||
use_meterfiles_ = use_meterfiles;
|
use_meterfiles_ = use_meterfiles;
|
||||||
|
@ -48,7 +49,7 @@ void Printer::print(Telegram *t, Meter *meter,
|
||||||
vector<string> envs;
|
vector<string> envs;
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
|
|
||||||
meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields, false);
|
meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields, pretty_print_json_);
|
||||||
|
|
||||||
if (shell_cmdlines_.size() > 0 || meter->shellCmdlines().size() > 0) {
|
if (shell_cmdlines_.size() > 0 || meter->shellCmdlines().size() > 0) {
|
||||||
printShells(meter, envs);
|
printShells(meter, envs);
|
||||||
|
|
|
@ -23,6 +23,7 @@ using namespace std;
|
||||||
|
|
||||||
struct Printer {
|
struct Printer {
|
||||||
Printer(bool json,
|
Printer(bool json,
|
||||||
|
bool pretty_print_json,
|
||||||
bool fields,
|
bool fields,
|
||||||
char separator,
|
char separator,
|
||||||
bool meterfiles, string &meterfiles_dir,
|
bool meterfiles, string &meterfiles_dir,
|
||||||
|
@ -36,7 +37,7 @@ struct Printer {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool json_, fields_;
|
bool json_, pretty_print_json_, fields_;
|
||||||
bool use_meterfiles_;
|
bool use_meterfiles_;
|
||||||
string meterfiles_dir_;
|
string meterfiles_dir_;
|
||||||
bool use_logfile_;
|
bool use_logfile_;
|
||||||
|
|
|
@ -145,8 +145,7 @@ int test_crc()
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_parse(const char *data, std::map<std::string,std::pair<int,DVEntry>> *dv_entries,
|
int test_parse(const char *data, std::map<std::string,std::pair<int,DVEntry>> *dv_entries, int testnr)
|
||||||
std::vector<DVEntry*> *dv_entries_ordered, int testnr)
|
|
||||||
{
|
{
|
||||||
debug("\n\nTest nr %d......\n\n", testnr);
|
debug("\n\nTest nr %d......\n\n", testnr);
|
||||||
bool b;
|
bool b;
|
||||||
|
@ -155,7 +154,7 @@ int test_parse(const char *data, std::map<std::string,std::pair<int,DVEntry>> *d
|
||||||
hex2bin(data, &databytes);
|
hex2bin(data, &databytes);
|
||||||
vector<uchar>::iterator i = databytes.begin();
|
vector<uchar>::iterator i = databytes.begin();
|
||||||
|
|
||||||
b = parseDV(&t, databytes, i, databytes.size(), dv_entries, dv_entries_ordered);
|
b = parseDV(&t, databytes, i, databytes.size(), dv_entries);
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -207,29 +206,28 @@ void test_date(map<string,pair<int,DVEntry>> &values, const char *key, string da
|
||||||
int test_dvparser()
|
int test_dvparser()
|
||||||
{
|
{
|
||||||
map<string,pair<int,DVEntry>> dv_entries;
|
map<string,pair<int,DVEntry>> dv_entries;
|
||||||
vector<DVEntry*> dv_entries_ordered;
|
|
||||||
|
|
||||||
int testnr = 1;
|
int testnr = 1;
|
||||||
test_parse("2F 2F 0B 13 56 34 12 8B 82 00 93 3E 67 45 23 0D FD 10 0A 30 31 32 33 34 35 36 37 38 39 0F 88 2F", &dv_entries, &dv_entries_ordered, testnr);
|
test_parse("2F 2F 0B 13 56 34 12 8B 82 00 93 3E 67 45 23 0D FD 10 0A 30 31 32 33 34 35 36 37 38 39 0F 88 2F", &dv_entries, testnr);
|
||||||
test_double(dv_entries, "0B13", 123.456, testnr);
|
test_double(dv_entries, "0B13", 123.456, testnr);
|
||||||
test_double(dv_entries, "8B8200933E", 234.567, testnr);
|
test_double(dv_entries, "8B8200933E", 234.567, testnr);
|
||||||
test_string(dv_entries, "0DFD10", "30313233343536373839", testnr);
|
test_string(dv_entries, "0DFD10", "30313233343536373839", testnr);
|
||||||
|
|
||||||
testnr++;
|
testnr++;
|
||||||
dv_entries.clear();
|
dv_entries.clear();
|
||||||
test_parse("82046C 5f1C", &dv_entries, &dv_entries_ordered, testnr);
|
test_parse("82046C 5f1C", &dv_entries, testnr);
|
||||||
test_date(dv_entries, "82046C", "2010-12-31 00:00:00", testnr); // 2010-dec-31
|
test_date(dv_entries, "82046C", "2010-12-31 00:00:00", testnr); // 2010-dec-31
|
||||||
|
|
||||||
testnr++;
|
testnr++;
|
||||||
dv_entries.clear();
|
dv_entries.clear();
|
||||||
test_parse("0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000", &dv_entries, &dv_entries_ordered, testnr);
|
test_parse("0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000", &dv_entries, testnr);
|
||||||
test_double(dv_entries, "0C13", 5.548, testnr);
|
test_double(dv_entries, "0C13", 5.548, testnr);
|
||||||
test_date(dv_entries, "426C", "2127-01-01 00:00:00", testnr); // 2127-jan-1
|
test_date(dv_entries, "426C", "2127-01-01 00:00:00", testnr); // 2127-jan-1
|
||||||
test_date(dv_entries, "82106C", "2000-01-01 00:00:00", testnr); // 2000-jan-1
|
test_date(dv_entries, "82106C", "2000-01-01 00:00:00", testnr); // 2000-jan-1
|
||||||
|
|
||||||
testnr++;
|
testnr++;
|
||||||
dv_entries.clear();
|
dv_entries.clear();
|
||||||
test_parse("426C FE04", &dv_entries, &dv_entries_ordered, testnr);
|
test_parse("426C FE04", &dv_entries, testnr);
|
||||||
test_date(dv_entries, "426C", "2007-04-30 00:00:00", testnr); // 2010-dec-31
|
test_date(dv_entries, "426C", "2007-04-30 00:00:00", testnr); // 2010-dec-31
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1720,7 +1720,7 @@ bool Telegram::parse_TPL_72(vector<uchar>::iterator &pos)
|
||||||
|
|
||||||
if (decrypt_ok)
|
if (decrypt_ok)
|
||||||
{
|
{
|
||||||
parseDV(this, frame, pos, remaining, &dv_entries, &dv_entries_ordered);
|
parseDV(this, frame, pos, remaining, &dv_entries);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1735,7 +1735,7 @@ bool Telegram::parse_TPL_78(vector<uchar>::iterator &pos)
|
||||||
header_size = distance(frame.begin(), pos);
|
header_size = distance(frame.begin(), pos);
|
||||||
int remaining = distance(pos, frame.end());
|
int remaining = distance(pos, frame.end());
|
||||||
suffix_size = 0;
|
suffix_size = 0;
|
||||||
parseDV(this, frame, pos, remaining, &dv_entries, &dv_entries_ordered);
|
parseDV(this, frame, pos, remaining, &dv_entries);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1786,7 +1786,7 @@ bool Telegram::parse_TPL_79(vector<uchar>::iterator &pos)
|
||||||
int remaining = distance(pos, frame.end());
|
int remaining = distance(pos, frame.end());
|
||||||
suffix_size = 0;
|
suffix_size = 0;
|
||||||
|
|
||||||
parseDV(this, frame, pos, remaining, &dv_entries, &dv_entries_ordered, &format, format_bytes.size());
|
parseDV(this, frame, pos, remaining, &dv_entries, &format, format_bytes.size());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1804,7 +1804,7 @@ bool Telegram::parse_TPL_7A(vector<uchar>::iterator &pos)
|
||||||
|
|
||||||
if (decrypt_ok)
|
if (decrypt_ok)
|
||||||
{
|
{
|
||||||
parseDV(this, frame, pos, remaining, &dv_entries, &dv_entries_ordered);
|
parseDV(this, frame, pos, remaining, &dv_entries);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -363,6 +363,12 @@ struct Explanation
|
||||||
|
|
||||||
struct Telegram
|
struct Telegram
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
Telegram(Telegram&t) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Telegram() = default;
|
||||||
|
|
||||||
AboutTelegram about;
|
AboutTelegram about;
|
||||||
|
|
||||||
// If a warning is printed mark this.
|
// If a warning is printed mark this.
|
||||||
|
@ -510,8 +516,6 @@ struct Telegram
|
||||||
// The actual content of the (w)mbus telegram. The DifVif entries.
|
// The actual content of the (w)mbus telegram. The DifVif entries.
|
||||||
// Mapped from their key for quick access to their offset and content.
|
// Mapped from their key for quick access to their offset and content.
|
||||||
std::map<std::string,std::pair<int,DVEntry>> dv_entries;
|
std::map<std::string,std::pair<int,DVEntry>> dv_entries;
|
||||||
// And sorted in increasing offset order.
|
|
||||||
std::vector<DVEntry*> dv_entries_ordered;
|
|
||||||
|
|
||||||
string autoDetectPossibleDrivers();
|
string autoDetectPossibleDrivers();
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ cat <<EOF > $TEST/test_expected.txt
|
||||||
voltage_at_phase_1_v Voltage at phase L1.
|
voltage_at_phase_1_v Voltage at phase L1.
|
||||||
voltage_at_phase_2_v Voltage at phase L2.
|
voltage_at_phase_2_v Voltage at phase L2.
|
||||||
voltage_at_phase_3_v Voltage at phase L3.
|
voltage_at_phase_3_v Voltage at phase L3.
|
||||||
device_date_time_txt Device date time.
|
device_date_time Device date time.
|
||||||
total_energy_consumption_tariff_1_kwh The total energy consumption recorded by this meter on tariff 1.
|
total_energy_consumption_tariff_1_kwh The total energy consumption recorded by this meter on tariff 1.
|
||||||
total_energy_consumption_tariff_2_kwh The total energy consumption recorded by this meter on tariff 2.
|
total_energy_consumption_tariff_2_kwh The total energy consumption recorded by this meter on tariff 2.
|
||||||
total_energy_consumption_tariff_3_kwh The total energy consumption recorded by this meter on tariff 3.
|
total_energy_consumption_tariff_3_kwh The total energy consumption recorded by this meter on tariff 3.
|
||||||
|
|
|
@ -93,6 +93,8 @@ Add :verbose to any analyze to get more verbose analyze output.
|
||||||
|
|
||||||
\fB\--oneshot\fR wait for an update from each meter, then quit
|
\fB\--oneshot\fR wait for an update from each meter, then quit
|
||||||
|
|
||||||
|
\fB\--ppjson\fR pretty print the json output
|
||||||
|
|
||||||
\fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 23h
|
\fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 23h
|
||||||
|
|
||||||
\fB\--selectfields=\fRid,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields)
|
\fB\--selectfields=\fRid,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields)
|
||||||
|
|
Ładowanie…
Reference in New Issue