ソースを参照

ESP32: add reset reason to boot event, CLI, and web panel

Implement getResetReason() and getResetReasonString() for ESP32Board,
covering all esp_reset_reason_t values: power-on, external reset,
software reset, panic/exception, interrupt watchdog, task watchdog,
generic watchdog, deep sleep wake, brownout, and SDIO reset.

Extend the pwrmgt.bootreason CLI command to support ESP32 alongside
NRF52. On ESP32 only the reset reason is reported (no shutdown reason).

Pass the reset reason as the value field when recording the
HISTORY_EVENT_BOOT stats event so the reason is stored in the in-memory
ring buffer and persisted to the archive events log.

Add bootReasonLabel() to the web panel and update renderEventsSection()
to annotate boot events with the human-readable reset reason string,
e.g. "boot (panic/exception)", when a non-null value is present.
Valentin V. Bartenev 2 ヶ月 前
コミット
9c8f884f11

+ 1 - 1
examples/simple_repeater/MyMesh.cpp

@@ -1331,7 +1331,7 @@ void MyMesh::begin(FILESYSTEM *fs, ArchiveStorage* archive) {
     next_archive_neighbours_flush_ms = millis() + kArchiveNeighboursFlushIntervalMs;
   }
   if (web.isWebStatsEnabled()) {
-    recordStatsEvent(HISTORY_EVENT_BOOT);
+    recordStatsEvent(HISTORY_EVENT_BOOT, board.getResetReason());
     if (_archive != nullptr) {
       recordStatsEvent(_archive->isMounted() ? HISTORY_EVENT_ARCHIVE_MOUNTED : HISTORY_EVENT_ARCHIVE_UNAVAILABLE);
     }

+ 4 - 1
src/helpers/CommonCLI.cpp

@@ -898,10 +898,13 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
     strcpy(reply, "ERROR: Power management not supported");
 #endif
   } else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) {
-#ifdef NRF52_POWER_MANAGEMENT
+#if defined(NRF52_POWER_MANAGEMENT)
     sprintf(reply, "> Reset: %s; Shutdown: %s",
       _board->getResetReasonString(_board->getResetReason()),
       _board->getShutdownReasonString(_board->getShutdownReason()));
+#elif defined(ESP_PLATFORM)
+    sprintf(reply, "> Reset: %s",
+      _board->getResetReasonString(_board->getResetReason()));
 #else
     strcpy(reply, "ERROR: Power management not supported");
 #endif

+ 20 - 0
src/helpers/ESP32Board.h

@@ -84,6 +84,26 @@ public:
 
   uint8_t getStartupReason() const override { return startup_reason; }
 
+  uint32_t getResetReason() const override {
+    return (uint32_t)esp_reset_reason();
+  }
+
+  const char* getResetReasonString(uint32_t reason) override {
+    switch ((esp_reset_reason_t)reason) {
+      case ESP_RST_POWERON:   return "Power On";
+      case ESP_RST_EXT:       return "External Reset";
+      case ESP_RST_SW:        return "Software Reset";
+      case ESP_RST_PANIC:     return "Panic/Exception";
+      case ESP_RST_INT_WDT:   return "Interrupt Watchdog";
+      case ESP_RST_TASK_WDT:  return "Task Watchdog";
+      case ESP_RST_WDT:       return "Watchdog";
+      case ESP_RST_DEEPSLEEP: return "Deep Sleep Wake";
+      case ESP_RST_BROWNOUT:  return "Brownout";
+      case ESP_RST_SDIO:      return "SDIO Reset";
+      default:                return "Unknown";
+    }
+  }
+
 #if defined(P_LORA_TX_LED)
   void onBeforeTransmit() override {
     digitalWrite(P_LORA_TX_LED, HIGH);   // turn TX LED on

+ 17 - 4
src/helpers/web/WebPanelServer.cpp

@@ -1627,6 +1627,14 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
         ${renderMetricList(metrics, "metric-grid-4")}
       </section>`;
     }
+    function bootReasonLabel(value) {
+      const ESP_RESET_REASONS = {
+        1: "power on", 2: "external reset", 3: "software reset",
+        4: "panic/exception", 5: "interrupt watchdog", 6: "task watchdog",
+        7: "watchdog", 8: "deep sleep wake", 9: "brownout", 10: "SDIO reset"
+      };
+      return ESP_RESET_REASONS[value] || ("reason " + value);
+    }
     function renderEventsSection(events) {
       if (!Array.isArray(events) || !events.length) {
         return `<section class="hud-card">
@@ -1634,10 +1642,15 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
           <div class="events-empty">No recent events</div>
         </section>`;
       }
-      const rows = events.map((event) => `<tr>
-        <td>${escapeHtml(event.type || "event")}</td>
-        <td>${escapeHtml(formatDuration(event.t || 0))}</td>
-      </tr>`).join("");
+      const rows = events.map((event) => {
+        const label = event.type === "boot" && event.value != null
+          ? `boot (${bootReasonLabel(event.value)})`
+          : (event.type || "event");
+        return `<tr>
+          <td>${escapeHtml(label)}</td>
+          <td>${escapeHtml(formatDuration(event.t || 0))}</td>
+        </tr>`;
+      }).join("");
       return `<section class="hud-card">
         <h3>Events</h3>
         <div class="events-table-wrap">