diff --git a/components/truma_inetbox/TrumaiNetBoxApp.cpp b/components/truma_inetbox/TrumaiNetBoxApp.cpp index 264a1f5..832bc2e 100644 --- a/components/truma_inetbox/TrumaiNetBoxApp.cpp +++ b/components/truma_inetbox/TrumaiNetBoxApp.cpp @@ -30,6 +30,14 @@ void TrumaiNetBoxApp::update() { this->heater_.update(); this->timer_.update(); + // Master mode auto-discovery (start device discovery once) + if (this->master_mode_ && !this->master_discovery_started_) { + this->master_discovery_started_ = true; + // Start device discovery for typical Truma heater NAD range + this->master_scan_b2(0x7F, 0x00, 0xFF); // Broadcast scan, full identifier range + ESP_LOGI(TAG, "Master mode: Started automatic device discovery"); + } + // Master TX scheduler (throttle to ~20ms spacing) if (this->master_mode_ && !this->master_tx_queue_.empty()) { uint32_t now = micros(); diff --git a/components/truma_inetbox/TrumaiNetBoxApp.h b/components/truma_inetbox/TrumaiNetBoxApp.h index 46e0f82..3bd0e60 100644 --- a/components/truma_inetbox/TrumaiNetBoxApp.h +++ b/components/truma_inetbox/TrumaiNetBoxApp.h @@ -93,6 +93,7 @@ class TrumaiNetBoxApp : public LinBusProtocol { struct MasterReq { uint8_t pid; uint8_t len; uint8_t data[9]; }; std::queue master_tx_queue_; uint32_t last_master_send_us_ = 0; + bool master_discovery_started_ = false; }; diff --git a/tools/udp_lin_receiver.py b/tools/udp_lin_receiver.py index 53f31b3..7511e65 100644 --- a/tools/udp_lin_receiver.py +++ b/tools/udp_lin_receiver.py @@ -77,6 +77,7 @@ def run(): ap.add_argument("--duration", type=float, default=0.0, help="Stop after N seconds (0 = no limit)") ap.add_argument("--quiet", action="store_true", help="No console output, only CSV") ap.add_argument("--pid-diff", action="store_true", help="Track textual 'PID ..' lines and only print when data changes") + ap.add_argument("--suppress-repeats", action="store_true", help="Suppress repeated identical messages (shows first + count)") ap.add_argument("--buffer", type=int, default=4096, help="Receive buffer size (default: 4096)") args = ap.parse_args() @@ -101,6 +102,9 @@ def run(): start = time.time() last_by_pid: Dict[int, Tuple[int, ...]] = {} + last_message = None + repeat_count = 0 + last_display_time = 0 while True: if args.duration and (time.time() - start) >= args.duration: @@ -129,6 +133,33 @@ def run(): # Console output if not args.quiet: + # Format the display message + if is_text and as_text: + display_msg = f"{ts} {src_ip}:{src_port} ({size}B) TEXT: {as_text}" + else: + display_msg = f"{ts} {src_ip}:{src_port} ({size}B) HEX: {hexstr}" + + # Handle repeat suppression + if args.suppress_repeats: + current_msg_key = as_text if is_text else hexstr + current_time = time.time() + + if current_msg_key == last_message: + repeat_count += 1 + # Show periodic updates for long repeated sequences + if current_time - last_display_time > 5.0: # Every 5 seconds + print(f"... repeated {repeat_count} times (last: {ts})") + last_display_time = current_time + else: + # Message changed + if repeat_count > 0: + print(f"... repeated {repeat_count} times total") + print(display_msg) + last_message = current_msg_key + repeat_count = 0 + last_display_time = current_time + continue + if args.pid_diff and is_text: parsed = maybe_parse_pid_and_data(as_text) if parsed: @@ -140,10 +171,7 @@ def run(): continue # default console print - if is_text and as_text: - print(f"{ts} {src_ip}:{src_port} ({size}B) TEXT: {as_text}") - else: - print(f"{ts} {src_ip}:{src_port} ({size}B) HEX: {hexstr}") + print(display_msg) if __name__ == "__main__":