Skip to content

Serial console commands log, stats-radio, stats-packets return "Unknown command" on ESP32-based devices #2644

@gagorski

Description

@gagorski

markdown

Summary

On all ESP32-based devices (XIAO S3, Heltec, LilyGo, etc.), the following serial console
commands always return Unknown command, despite being present in the firmware source:

  • log (read packet log)
  • stats-radio
  • stats-packets
  • stats-core

The same commands work correctly on nRF52840-based devices (e.g. Wio Tracker 1L).

Root Cause

In src/helpers/CommonCLI.cpp, these commands are guarded by a sender_timestamp == 0 check:

} else if (sender_timestamp == 0 && memcmp(command, "log", 3) == 0) {
    _callbacks->dumpLogFile();

The intent is clear: allow these commands only from the local serial console (not from remote
mesh nodes, which carry a non-zero sender timestamp).

However, in examples/simple_repeater/main.cpp (and equivalents in other examples), the
serial console handler passes the current RTC time as sender_timestamp:

uint32_t now = 0;
if (the_mesh.getRTCClock()) {
    now = the_mesh.getRTCClock()->getCurrentTime();
}
the_mesh.handleCommand(now, command, reply);

On ESP32-based boards, ESP32RTCClock::begin() initializes the system time to a hardcoded
value on power-on reset:

void begin() {
    esp_reset_reason_t reason = esp_reset_reason();
    if (reason == ESP_RST_POWERON) {
        struct timeval tv;
        tv.tv_sec = 1715770351;  // 15 May 2024, 8:50pm
        // ...
        settimeofday(&tv, NULL);
    }
}

This means getCurrentTime() never returns 0 — it always returns at least 1715770351.
As a result, sender_timestamp == 0 is never true for local serial commands on these devices,
and the commands fall through to "Unknown command".

On nRF52840 devices, the RTC is not initialized and returns 0, so the guard passes correctly.

Reproduction

  1. Flash any ESP32-based repeater firmware (e.g. Xiao_S3_WIO_repeater)
  2. Connect via serial console (USB or UART)
  3. Run log start → returns logging on ✓ (no sender_timestamp guard)
  4. Run log → returns Unknown command ✗ (has sender_timestamp == 0 guard)
  5. Run stats-radio → returns Unknown command

Not reproduced on: Wio Tracker 1L (nRF52840) — all commands work correctly.

Proposed Fix

In the serial console handler of each main.cpp, pass 0 as sender_timestamp for local
commands, regardless of the current RTC time:

// Before:
the_mesh.handleCommand(now, command, reply);

// After:
the_mesh.handleCommand(0, command, reply);

The variable now is still needed for other purposes (advert timing, etc.) — only the
handleCommand call for serial input should use 0.

This fix correctly reflects the intent of the sender_timestamp == 0 guard: commands typed
on the physical serial console are always local admin commands, not remote mesh commands.

Affected Boards

All variants using ESP32RTCClock as fallback, including:

  • xiao_s3_wio / xiao_c3 / xiao_c6
  • heltec_v2, heltec_v3, heltec_v4
  • lilygo_tbeam_*, lilygo_t3s3, lilygo_tdeck
  • ebyte_eora_s3
  • Any custom ESP32 build

Environment

  • Firmware version: v1.15.0
  • Tested on: XIAO ESP32S3 (Xiao_S3_WIO_repeater)
  • Reference nRF52840 device: Wio Tracker 1L

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions