diff --git a/CHANGES b/CHANGES index 1477e98..14871ea 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,9 @@ To list the fields avilable for a meter do --listfields=multical21 To list all meters do --listmeters To search for a meter do --listmeters=water or --listmeters=multi +The wmbus device used to received the telegram and the rssi level +is part of the json, eg: "device":"rtlwmbus[1234]","rssi_dbm":-47 + Version 0.9.36: 2020-09-08 Added support for detection of the proper driver diff --git a/simulations/simulation_aes.msg b/simulations/simulation_aes.msg index f0a56db..fcc0b9c 100644 --- a/simulations/simulation_aes.msg +++ b/simulations/simulation_aes.msg @@ -1,6 +1,6 @@ T1;1;1;2019-04-03 19:00:42.000;97;148;88888888;0x6e4401068888888805077a85006085bc2630713819512eb4cd87fba554fb43f67cf9654a68ee8e194088160df752e716238292e8af1ac20986202ee561d743602466915e42f1105d9c6782a54504e4f099e65a7656b930c73a30775122d2fdf074b5035cfaa7e0050bf32faae03a77 -{"media":"water","meter":"apator162","name":"ApWater","id":"88888888","total_m3":4.848,"timestamp":"1111-11-11T11:11:11Z"} +{"media":"water","meter":"apator162","name":"ApWater","id":"88888888","total_m3":4.848,"timestamp":"1111-11-11T11:11:11Z","device":"rtlwmbus[]","rssi_dbm":97} C1;1;1;2020-01-23 10:25:13.000;97;148;76348799;0x2A442D2C998734761B168D2091D37CAC21E1D68CDAFFCD3DC452BD802913FF7B1706CA9E355D6C2701CC24 -{"media":"cold water","meter":"multical21","name":"Vatten","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"} +{"media":"cold water","meter":"multical21","name":"Vatten","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z","device":"rtlwmbus[]","rssi_dbm":97} T1;1;1;2019-04-03 19:00:42.000;97;148;77777777;0xAE44EE4D777777773C077A4400A025E78F4A01F9DCA029EDA03BA452686E8FA917507B29E5358B52D77C111EA4C41140290523F3F6B9F9261705E041C0CA41305004605F42D6C9464E5A04EEE227510BD0DC0983C665C3A5E4739C2082975476AC637BCDD39766AEF030502B6A7697BE9E1C49AF535C15470FCF8ADA36CAB9D0B2A1A8690F8DDCF70859F18B3414D8315B311A0AFA57325531587CB7E9CC110E807F24C190D7E635BEDAF4CAE8A161 -{"media":"water","meter":"supercom587","name":"Wasser","id":"77777777","total_m3":0,"timestamp":"1111-11-11T11:11:11Z"} \ No newline at end of file +{"media":"water","meter":"supercom587","name":"Wasser","id":"77777777","total_m3":0,"timestamp":"1111-11-11T11:11:11Z","device":"rtlwmbus[]","rssi_dbm":97} \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index 6187a3b..5384aac 100644 --- a/src/main.cc +++ b/src/main.cc @@ -834,7 +834,7 @@ void open_wmbus_device_and_set_linkmodes(Configuration *config, string how, Dete debug("(main) added %s to files\n", detected->found_file.c_str()); simulation_files_.insert(detected->specified_device.file); } - wmbus->onTelegram([&, simulated](vector data){return meter_manager_->handleTelegram(data, simulated);}); + wmbus->onTelegram([&, simulated](AboutTelegram &about,vector data){return meter_manager_->handleTelegram(about, data, simulated);}); wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity); } @@ -1122,8 +1122,9 @@ bool start(Configuration *config) { notice("No meters configured. Printing id:s of all telegrams heard!\n"); - meter_manager_->onTelegram([](vector frame) { + meter_manager_->onTelegram([](AboutTelegram &about, vector frame) { Telegram t; + t.about = about; MeterKeys mk; t.parserNoWarnings(); // Try a best effort parse, do not print any warnings. t.parse(frame, &mk); diff --git a/src/meters.cc b/src/meters.cc index 3813b9d..a4d3d21 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -66,13 +66,13 @@ struct MeterManagerImplementation : public virtual MeterManager return meters_.size() != 0; } - bool handleTelegram(vector data, bool simulated) + bool handleTelegram(AboutTelegram &about, vector data, bool simulated) { if (!hasMeters()) { if (on_telegram_) { - on_telegram_(data); + on_telegram_(about, data); } return true; } @@ -82,7 +82,7 @@ struct MeterManagerImplementation : public virtual MeterManager string id; for (auto &m : meters_) { - bool h = m->handleTelegram(data, simulated, &id); + bool h = m->handleTelegram(about, data, simulated, &id); if (h) handled = true; } if (isVerboseEnabled() && !handled) @@ -92,7 +92,7 @@ struct MeterManagerImplementation : public virtual MeterManager return handled; } - void onTelegram(function)> cb) + void onTelegram(function)> cb) { on_telegram_ = cb; } @@ -101,7 +101,7 @@ struct MeterManagerImplementation : public virtual MeterManager private: vector> meters_; - function)> on_telegram_; + function)> on_telegram_; }; shared_ptr createMeterManager() @@ -428,9 +428,10 @@ string concatFields(Meter *m, Telegram *t, char c, vector &prints, vector return s; } -bool MeterCommonImplementation::handleTelegram(vector input_frame, bool simulated, string *id) +bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector input_frame, bool simulated, string *id) { Telegram t; + t.about = about; bool ok = t.parseHeader(input_frame); if (simulated) t.markAsSimulated(); @@ -515,6 +516,12 @@ void MeterCommonImplementation::printMeter(Telegram *t, } } s += "\"timestamp\":\""+datetimeOfUpdateRobot()+"\""; + if (t->about.device != "") + { + s += ","; + s += "\"device\":\""+t->about.device+"\","; + s += "\"rssi_dbm\":"+to_string(t->about.rssi_dbm); + } for (string add_json : additionalJsons()) { s += ","; diff --git a/src/meters.h b/src/meters.h index 0674e62..eef1fed 100644 --- a/src/meters.h +++ b/src/meters.h @@ -225,7 +225,7 @@ struct Meter // The handleTelegram expects an input_frame where the DLL crcs have been removed. // Returns true of this meter handled this telegram! - virtual bool handleTelegram(vector input_frame, bool simulated, string *id) = 0; + virtual bool handleTelegram(AboutTelegram &about, vector input_frame, bool simulated, string *id) = 0; virtual bool isTelegramForMe(Telegram *t) = 0; virtual MeterKeys *meterKeys() = 0; @@ -247,10 +247,10 @@ struct MeterManager virtual Meter*lastAddedMeter() = 0; virtual void removeAllMeters() = 0; virtual void forEachMeter(std::function cb) = 0; - virtual bool handleTelegram(vector data, bool simulated) = 0; + virtual bool handleTelegram(AboutTelegram &about, vector data, bool simulated) = 0; virtual bool hasAllMetersReceivedATelegram() = 0; virtual bool hasMeters() = 0; - virtual void onTelegram(function)> cb) = 0; + virtual void onTelegram(function)> cb) = 0; virtual ~MeterManager() = default; }; diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index f6d9488..a4f2155 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -74,7 +74,7 @@ protected: // Print the dimensionless Text quantity, no unit is needed. void addPrint(string vname, Quantity vquantity, function getValueFunc, string help, bool field, bool json); - bool handleTelegram(vector frame, bool simulated, string *id); + bool handleTelegram(AboutTelegram &about, vector frame, bool simulated, string *id); void printMeter(Telegram *t, string *human_readable, string *fields, char separator, diff --git a/src/wmbus.cc b/src/wmbus.cc index d5f2589..d3245ec 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -232,6 +232,11 @@ void Telegram::print() notice(" ver: 0x%02x\n", dll_version); + if (about.device != "") + { + notice(" device: %s\n", about.device.c_str()); + notice(" rssi: %d dBm\n", about.rssi_dbm); + } string possible_drivers = autoDetectPossibleDrivers(); notice(" driver: %s\n", possible_drivers.c_str()); } @@ -241,7 +246,7 @@ void Telegram::printDLL() string possible_drivers = autoDetectPossibleDrivers(); string man = manufacturerFlag(dll_mfct); - verbose("(telegram) DLL L=%02x C=%02x (%s) M=%04x (%s) A=%02x%02x%02x%02x VER=%02x TYPE=%02x (%s) (driver %s)\n", + verbose("(telegram) DLL L=%02x C=%02x (%s) M=%04x (%s) A=%02x%02x%02x%02x VER=%02x TYPE=%02x (%s) (driver %s) DEV=%s RSSI=%d\n", dll_len, dll_c, cType(dll_c).c_str(), dll_mfct, @@ -250,7 +255,9 @@ void Telegram::printDLL() dll_version, dll_type, mediaType(dll_type).c_str(), - possible_drivers.c_str()); + possible_drivers.c_str(), + about.device.c_str(), + about.rssi_dbm); } void Telegram::printELL() @@ -3177,12 +3184,12 @@ WMBusDeviceType WMBusCommonImplementation::type() return type_; } -void WMBusCommonImplementation::onTelegram(function)> cb) +void WMBusCommonImplementation::onTelegram(function)> cb) { telegram_listeners_.push_back(cb); } -bool WMBusCommonImplementation::handleTelegram(vector frame) +bool WMBusCommonImplementation::handleTelegram(AboutTelegram &about, vector frame) { bool handled = false; last_received_ = time(NULL); @@ -3191,7 +3198,7 @@ bool WMBusCommonImplementation::handleTelegram(vector frame) { if (f) { - bool h = f(frame); + bool h = f(about, frame); if (h) handled = true; } } diff --git a/src/wmbus.h b/src/wmbus.h index a004b21..98848d4 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -320,8 +320,23 @@ struct MeterKeys bool hasAuthenticationKey() { return authentication_key.size() > 0; } }; +struct AboutTelegram +{ + // wmbus device used to receive this telegram. + string device; + // The device's opinion of the rssi, best effort conversion into the dbm scale. + // -100 dbm = 0.1 pico Watt to -20 dbm = 10 micro W + // Measurements smaller than -100 and larger than -10 are unlikely. + int rssi_dbm {}; + + AboutTelegram(string dv, int rs) : device(dv), rssi_dbm(rs) {} + AboutTelegram() {} +}; + struct Telegram { + AboutTelegram about; + // The meter address as a string usually printed on the meter. string id; // If decryption failed, set this to true, to prevent further processing. @@ -491,7 +506,7 @@ struct WMBus virtual int numConcurrentLinkModes() = 0; virtual bool canSetLinkModes(LinkModeSet lms) = 0; virtual void setLinkModes(LinkModeSet lms) = 0; - virtual void onTelegram(function)> cb) = 0; + virtual void onTelegram(function)> cb) = 0; virtual SerialDevice *serial() = 0; // Return true of the serial has been overridden, usually with stdin or a file. virtual bool serialOverride() = 0; diff --git a/src/wmbus_amb8465.cc b/src/wmbus_amb8465.cc index 50deb8b..9780eb4 100644 --- a/src/wmbus_amb8465.cc +++ b/src/wmbus_amb8465.cc @@ -86,8 +86,8 @@ private: int *msgid_out, int *payload_len_out, int *payload_offset, - uchar *rssi); - void handleMessage(int msgid, vector &frame); + int *rssi_dbm); + void handleMessage(int msgid, vector &frame, int rssi_dbm); }; shared_ptr openAMB8465(string device, shared_ptr manager, shared_ptr serial_override) @@ -279,7 +279,7 @@ FrameStatus WMBusAmber::checkAMB8465Frame(vector &data, int *msgid_out, int *payload_len_out, int *payload_offset, - uchar *rssi) + int *rssi_dbm) { if (data.size() < 2) return PartialFrame; debugPayload("(amb8465) checkAMB8465Frame", data); @@ -317,9 +317,9 @@ FrameStatus WMBusAmber::checkAMB8465Frame(vector &data, if (rssi_len) { - *rssi = data[*frame_length-2]; - signed int dbm = (*rssi >= 128) ? (*rssi - 256) / 2 - 74 : *rssi / 2 - 74; - verbose("(amb8465) rssi %d (%d dBm)\n", *rssi, dbm); + int rssi = (int)data[*frame_length-2]; + *rssi_dbm = (rssi >= 128) ? (rssi - 256) / 2 - 74 : rssi / 2 - 74; + verbose("(amb8465) rssi %d (%d dBm)\n", rssi, *rssi_dbm); } return FullFrame; @@ -362,9 +362,9 @@ FrameStatus WMBusAmber::checkAMB8465Frame(vector &data, if (rssi_expected_) { - *rssi = data[*frame_length-1]; - signed int dbm = (*rssi >= 128) ? (*rssi - 256) / 2 - 74 : *rssi / 2 - 74; - verbose("(amb8465) rssi %d (%d dBm)\n", *rssi, dbm); + int rssi = data[*frame_length-1]; + *rssi_dbm = (rssi >= 128) ? (rssi - 256) / 2 - 74 : rssi / 2 - 74; + verbose("(amb8465) rssi %d (%d dBm)\n", rssi, *rssi_dbm); } return FullFrame; @@ -403,11 +403,11 @@ void WMBusAmber::processSerialData() size_t frame_length; int msgid; int payload_len, payload_offset; - uchar rssi; + int rssi_dbm; for (;;) { - FrameStatus status = checkAMB8465Frame(read_buffer_, &frame_length, &msgid, &payload_len, &payload_offset, &rssi); + FrameStatus status = checkAMB8465Frame(read_buffer_, &frame_length, &msgid, &payload_len, &payload_offset, &rssi_dbm); if (status == PartialFrame) { @@ -443,17 +443,18 @@ void WMBusAmber::processSerialData() read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleMessage(msgid, payload); + handleMessage(msgid, payload, rssi_dbm); } } } -void WMBusAmber::handleMessage(int msgid, vector &frame) +void WMBusAmber::handleMessage(int msgid, vector &frame, int rssi_dbm) { switch (msgid) { case (0): { - handleTelegram(frame); + AboutTelegram about("amb8465["+cached_device_id_+"]", rssi_dbm); + handleTelegram(about, frame); break; } case (0x80|CMD_SET_MODE_REQ): diff --git a/src/wmbus_cul.cc b/src/wmbus_cul.cc index e4d5287..1894d99 100644 --- a/src/wmbus_cul.cc +++ b/src/wmbus_cul.cc @@ -241,7 +241,8 @@ void WMBusCUL::processSerialData() { read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/src/wmbus_d1tc.cc b/src/wmbus_d1tc.cc index 7b277a3..05f7d91 100644 --- a/src/wmbus_d1tc.cc +++ b/src/wmbus_d1tc.cc @@ -204,7 +204,8 @@ void WMBusD1TC::processSerialData() payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len); } read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/src/wmbus_im871a.cc b/src/wmbus_im871a.cc index b549650..edb28ff 100644 --- a/src/wmbus_im871a.cc +++ b/src/wmbus_im871a.cc @@ -107,7 +107,7 @@ struct Config s += "link_mode="+toString(LinkModeIM871A(link_mode)); string ids; - strprintf(ids, " id=%08x media=%02x version=%02x c_field=%02x", id, media, version, c_field); + strprintf(ids, " id=%08x media=%02x version=%02x c_field=%02x auto_rssi=%02x", id, media, version, c_field, auto_rssi); return s+ids; } @@ -189,7 +189,8 @@ struct WMBusIM871A : public virtual WMBusCommonImplementation static FrameStatus checkIM871AFrame(vector &data, size_t *frame_length, int *endpoint_out, int *msgid_out, - int *payload_len_out, int *payload_offset); + int *payload_len_out, int *payload_offset, + int *rssi_dbm); private: @@ -205,11 +206,26 @@ private: friend AccessCheck detectIM871A(Detected *detected, shared_ptr manager); void handleDevMgmt(int msgid, vector &payload); - void handleRadioLink(int msgid, vector &payload); + void handleRadioLink(int msgid, vector &payload, int rssi_dbm); void handleRadioLinkTest(int msgid, vector &payload); void handleHWTest(int msgid, vector &payload); }; + +int toDBM(int rssi) +{ + // Very course approximation of this graph: + // Figure 7-3: RSSI vs. Input Power (Silicon Labs Si1002 datasheet [3]) + // Stronger rssi:s than 0 dbm will be reported as 0 dbm. + // rssi = >230 -> 0 dbm + // rssi = 205 -> -20 dbm + // rssi = 45 -> -100 dbm +#define SLOPE (80.0/(205.0-45.0)) + if (rssi >= 230) return 0; + int dbm = -100+SLOPE*(rssi-45); + return dbm; +} + shared_ptr openIM871A(string device, shared_ptr manager, shared_ptr serial_override) { assert(device != ""); @@ -493,9 +509,9 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms) request_[6] = (int)LinkModeIM871A::C1a; // Defaults to C1a } - request_[7] = 16+32; // iff2 bits: Set rssi+timestamp + request_[7] = 0x10 | 0x20; // iff2 bits: Set rssi 0x10, timestamp 0x20 request_[8] = 1; // Enable rssi - request_[9] = 1; // Enable timestamp + request_[9] = 0; // Disable timestamp verbose("(im871a) set config to set link mode %02x\n", request_[6]); bool sent = serial()->send(request_); @@ -512,7 +528,8 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms) FrameStatus WMBusIM871A::checkIM871AFrame(vector &data, size_t *frame_length, int *endpoint_out, int *msgid_out, - int *payload_len_out, int *payload_offset) + int *payload_len_out, int *payload_offset, + int *rssi_dbm) { if (data.size() == 0) return PartialFrame; @@ -613,8 +630,9 @@ FrameStatus WMBusIM871A::checkIM871AFrame(vector &data, i += 4; } if (has_rssi) { - uint32_t rssi = data[i]; - verbose("(im871a) rssi %02x\n", rssi); + int rssi = data[i]; + *rssi_dbm = toDBM(rssi); + debug("(im871a) rssi %d (%d dBm)\n", rssi, *rssi_dbm); i++; } if (has_crc16) { @@ -647,10 +665,11 @@ void WMBusIM871A::processSerialData() int endpoint; int msgid; int payload_len, payload_offset; + int rssi_dbm = 0; for (;;) { - FrameStatus status = checkIM871AFrame(read_buffer_, &frame_length, &endpoint, &msgid, &payload_len, &payload_offset); + FrameStatus status = checkIM871AFrame(read_buffer_, &frame_length, &endpoint, &msgid, &payload_len, &payload_offset, &rssi_dbm); if (status == PartialFrame) { @@ -688,7 +707,7 @@ void WMBusIM871A::processSerialData() // It can be wmbus receiver-dongle messages or wmbus remote meter messages received over the radio. switch (endpoint) { case DEVMGMT_ID: handleDevMgmt(msgid, payload); break; - case RADIOLINK_ID: handleRadioLink(msgid, payload); break; + case RADIOLINK_ID: handleRadioLink(msgid, payload, rssi_dbm); break; case RADIOLINKTEST_ID: handleRadioLinkTest(msgid, payload); break; case HWTEST_ID: handleHWTest(msgid, payload); break; } @@ -726,13 +745,16 @@ void WMBusIM871A::handleDevMgmt(int msgid, vector &payload) } } -void WMBusIM871A::handleRadioLink(int msgid, vector &frame) +void WMBusIM871A::handleRadioLink(int msgid, vector &frame, int rssi_dbm) { switch (msgid) { case RADIOLINK_MSG_WMBUSMSG_IND: // 0x03 + { // Invoke common telegram reception code in WMBusCommonImplementation. - handleTelegram(frame); - break; + AboutTelegram about("im871a["+cached_device_id_+"]", rssi_dbm); + handleTelegram(about, frame); + } + break; default: verbose("(im871a) Unhandled radio link message %d\n", msgid); } @@ -757,10 +779,10 @@ void WMBusIM871A::handleHWTest(int msgid, vector &payload) bool extract_response(vector &data, vector &response, int expected_endpoint, int expected_msgid) { size_t frame_length; - int endpoint, msgid, payload_len, payload_offset; + int endpoint, msgid, payload_len, payload_offset, rssi_dbm; FrameStatus status = WMBusIM871A::checkIM871AFrame(data, &frame_length, &endpoint, &msgid, - &payload_len, &payload_offset); + &payload_len, &payload_offset, &rssi_dbm); if (status != FullFrame || endpoint != expected_endpoint || msgid != expected_msgid) @@ -845,10 +867,10 @@ AccessCheck detectIM871A(Detected *detected, shared_ptrreceive(&response); size_t frame_length; - int endpoint, msgid, payload_len, payload_offset; + int endpoint, msgid, payload_len, payload_offset, rssi_dbm; FrameStatus status = WMBusIM871A::checkIM871AFrame(response, &frame_length, &endpoint, &msgid, - &payload_len, &payload_offset); + &payload_len, &payload_offset, &rssi_dbm); if (status != FullFrame || endpoint != 1 || msgid != DEVMGMT_MSG_GET_CONFIG_RSP) diff --git a/src/wmbus_rawtty.cc b/src/wmbus_rawtty.cc index 8d611ef..5e70e9c 100644 --- a/src/wmbus_rawtty.cc +++ b/src/wmbus_rawtty.cc @@ -132,7 +132,8 @@ void WMBusRawTTY::processSerialData() payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len); } read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/src/wmbus_rc1180.cc b/src/wmbus_rc1180.cc index 05e2956..c91e8dd 100644 --- a/src/wmbus_rc1180.cc +++ b/src/wmbus_rc1180.cc @@ -230,7 +230,8 @@ void WMBusRC1180::processSerialData() payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len); } read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/src/wmbus_rtl433.cc b/src/wmbus_rtl433.cc index 637a5d0..ff6b109 100644 --- a/src/wmbus_rtl433.cc +++ b/src/wmbus_rtl433.cc @@ -208,7 +208,8 @@ void WMBusRTL433::processSerialData() payload[0] = payload.size()-1; } } - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/src/wmbus_rtlwmbus.cc b/src/wmbus_rtlwmbus.cc index 373e748..2a773a5 100644 --- a/src/wmbus_rtlwmbus.cc +++ b/src/wmbus_rtlwmbus.cc @@ -55,11 +55,12 @@ struct WMBusRTLWMBUS : public virtual WMBusCommonImplementation void processSerialData(); void simulate(); - WMBusRTLWMBUS(shared_ptr serial, shared_ptr manager); + WMBusRTLWMBUS(string serialnr, shared_ptr serial, shared_ptr manager); ~WMBusRTLWMBUS() { } private: + string serialnr_; vector read_buffer_; vector received_payload_; bool warning_dll_len_printed_ {}; @@ -67,33 +68,35 @@ private: FrameStatus checkRTLWMBUSFrame(vector &data, size_t *hex_frame_length, int *hex_payload_len_out, - int *hex_payload_offset); + int *hex_payload_offset, + double *rssi); void handleMessage(vector &frame); string setup_; }; -shared_ptr openRTLWMBUS(string identifier, string command, shared_ptr manager, +shared_ptr openRTLWMBUS(string serialnr, string command, shared_ptr manager, function on_exit, shared_ptr serial_override) { - debug("(rtlwmbus) opening %s\n", identifier.c_str()); + debug("(rtlwmbus) opening %s\n", serialnr.c_str()); + vector args; vector envs; args.push_back("-c"); args.push_back(command); if (serial_override) { - WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial_override, manager); + WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serialnr, serial_override, manager); imp->markSerialAsOverriden(); return shared_ptr(imp); } - auto serial = manager->createSerialDeviceCommand(identifier, "/bin/sh", args, envs, on_exit, "rtlwmbus"); - WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial, manager); + auto serial = manager->createSerialDeviceCommand(serialnr, "/bin/sh", args, envs, on_exit, "rtlwmbus"); + WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serialnr, serial, manager); return shared_ptr(imp); } -WMBusRTLWMBUS::WMBusRTLWMBUS(shared_ptr serial, shared_ptr manager) : - WMBusCommonImplementation(DEVICE_RTLWMBUS, manager, serial) +WMBusRTLWMBUS::WMBusRTLWMBUS(string serialnr, shared_ptr serial, shared_ptr manager) : + WMBusCommonImplementation(DEVICE_RTLWMBUS, manager, serial), serialnr_(serialnr) { reset(); } @@ -105,7 +108,7 @@ bool WMBusRTLWMBUS::ping() string WMBusRTLWMBUS::getDeviceId() { - return ""; + return serialnr_; } LinkModeSet WMBusRTLWMBUS::getLinkModes() @@ -139,7 +142,8 @@ void WMBusRTLWMBUS::processSerialData() for (;;) { - FrameStatus status = checkRTLWMBUSFrame(read_buffer_, &frame_length, &hex_payload_len, &hex_payload_offset); + double rssi = 0; + FrameStatus status = checkRTLWMBUSFrame(read_buffer_, &frame_length, &hex_payload_len, &hex_payload_offset, &rssi); if (status == PartialFrame) { @@ -194,7 +198,10 @@ void WMBusRTLWMBUS::processSerialData() payload[0] = payload.size()-1; } } - handleTelegram(payload); + + string id = string("rtlwmbus[")+getDeviceId()+"]"; + AboutTelegram about(id, rssi); + handleTelegram(about, payload); } } } @@ -202,7 +209,8 @@ void WMBusRTLWMBUS::processSerialData() FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector &data, size_t *hex_frame_length, int *hex_payload_len_out, - int *hex_payload_offset) + int *hex_payload_offset, + double *rssi) { // C1;1;1;2019-02-09 07:14:18.000;117;102;94740459;0x49449344590474943508780dff5f3500827f0000f10007b06effff530100005f2c620100007f2118010000008000800080008000000000000000000e003f005500d4ff2f046d10086922 // There might be a second telegram on the same line ;0x4944....... @@ -259,8 +267,27 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector &data, return ErrorInFrame; } } - // Look for start of telegram 0x size_t i = 0; + int count = 0; + // Look for packet rssi + for (; i+1 < data.size(); ++i) { + if (data[i] == ';') count++; + if (count == 4) break; + } + if (count == 4) + { + size_t from = i+1; + for (i++; istop(); } diff --git a/src/wmbus_utils.h b/src/wmbus_utils.h index 491fb6c..58a86e5 100644 --- a/src/wmbus_utils.h +++ b/src/wmbus_utils.h @@ -33,8 +33,8 @@ struct WMBusCommonImplementation : public virtual WMBus ~WMBusCommonImplementation(); WMBusDeviceType type(); - void onTelegram(function)> cb); - bool handleTelegram(vector frame); + void onTelegram(function)> cb); + bool handleTelegram(AboutTelegram &about, vector frame); void checkStatus(); bool isWorking(); string dongleId(); @@ -73,7 +73,7 @@ struct WMBusCommonImplementation : public virtual WMBus private: bool is_working_ {}; - vector)>> telegram_listeners_; + vector)>> telegram_listeners_; WMBusDeviceType type_ {}; int protocol_error_count_ {}; time_t timeout_ {}; // If longer silence than timeout, then reset dongle! It might have hanged! diff --git a/src/wmbus_wmb13u.cc b/src/wmbus_wmb13u.cc index d2ec946..6d56fdb 100644 --- a/src/wmbus_wmb13u.cc +++ b/src/wmbus_wmb13u.cc @@ -239,7 +239,8 @@ void WMBusWMB13U::processSerialData() payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len-3); } read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); - handleTelegram(payload); + AboutTelegram about("", 0); + handleTelegram(about, payload); } } } diff --git a/tests/rtlwmbus_water.sh b/tests/rtlwmbus_water.sh index aee68c2..2dc2cf4 100755 --- a/tests/rtlwmbus_water.sh +++ b/tests/rtlwmbus_water.sh @@ -1,3 +1,3 @@ #!/bin/sh echo "T1;1;1;2019-04-03 19:00:42.000;97;148;88888888;0x6e4401068888888805077a85006085bc2630713819512eb4cd87fba554fb43f67cf9654a68ee8e194088160df752e716238292e8af1ac20986202ee561d743602466915e42f1105d9c6782a54504e4f099e65a7656b930c73a30775122d2fdf074b5035cfaa7e0050bf32faae03a77" -#{"media":"water","meter":"apator162","name":"ApWater","id":"88888888","total_m3":4.848,"timestamp":"1111-11-11T11:11:11Z"} +#{"media":"water","meter":"apator162","name":"ApWater","id":"88888888","total_m3":4.848,"timestamp":"1111-11-11T11:11:11Z","device":"rtlwmbus[cmd_0]","rssi_dbm":97} diff --git a/tests/test_stdin_and_file.sh b/tests/test_stdin_and_file.sh index bc4fd30..4fde5f3 100755 --- a/tests/test_stdin_and_file.sh +++ b/tests/test_stdin_and_file.sh @@ -69,8 +69,8 @@ TESTNAME="Reading rtlwmbus formatted telegrams from stdin" TESTRESULT="ERROR" cat > $TEST/test_expected.txt < $TEST/test_expected.txt <