feat(firmware): include diagnostics in heartbeat payload
Heartbeat v1.1.0 now carries heap stats (free + min_free since boot), esp_reset_reason(), last WiFi disconnect code, and the last 8 persisted event-log entries. Makes field failures diagnosable server-side without retrieving the device: the post-reboot heartbeat will include EVT_BOOT with reset reason and whatever EVT_WIFI_DOWN or EVT_HTTP_FAIL entries preceded it.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include "reporter.h"
|
#include "reporter.h"
|
||||||
#include "hmac.h"
|
#include "hmac.h"
|
||||||
#include "event_log.h"
|
#include "event_log.h"
|
||||||
|
#include "net_guard.h"
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
@@ -9,6 +10,8 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
#include <esp_task_wdt.h>
|
#include <esp_task_wdt.h>
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include <esp_heap_caps.h>
|
||||||
|
|
||||||
static std::vector<CameraHourlyRecord> s_cam_buf;
|
static std::vector<CameraHourlyRecord> s_cam_buf;
|
||||||
static std::vector<BLEHourlyRecord> s_ble_buf;
|
static std::vector<BLEHourlyRecord> s_ble_buf;
|
||||||
@@ -175,11 +178,31 @@ void reporter_submit_ble(const DeviceConfig& cfg, const BLEHourlyRecord& rec) {
|
|||||||
bool reporter_heartbeat(const DeviceConfig& cfg, uint32_t uptime_s, int wifi_rssi) {
|
bool reporter_heartbeat(const DeviceConfig& cfg, uint32_t uptime_s, int wifi_rssi) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc["device_id"] = cfg.device_id;
|
doc["device_id"] = cfg.device_id;
|
||||||
doc["firmware_version"] = "1.0.0";
|
doc["firmware_version"] = "1.1.0";
|
||||||
doc["free_storage_pct"] = 100;
|
doc["free_storage_pct"] = 100;
|
||||||
doc["wifi_rssi"] = wifi_rssi;
|
doc["wifi_rssi"] = wifi_rssi;
|
||||||
doc["pending_records"] = (int)(s_cam_buf.size() + s_ble_buf.size());
|
doc["pending_records"] = (int)(s_cam_buf.size() + s_ble_buf.size());
|
||||||
doc["uptime_seconds"] = uptime_s;
|
doc["uptime_seconds"] = uptime_s;
|
||||||
|
|
||||||
|
// Diagnostics (new in 1.1.0)
|
||||||
|
doc["reset_reason"] = (int)esp_reset_reason();
|
||||||
|
doc["heap_free"] = (int)esp_get_free_heap_size();
|
||||||
|
doc["heap_min_free"] = (int)esp_get_minimum_free_heap_size();
|
||||||
|
doc["last_disconnect_code"] = (int)net_guard_last_disconnect_reason();
|
||||||
|
|
||||||
|
// Last 8 event-log entries, newest first
|
||||||
|
EventLogEntry recent[8];
|
||||||
|
size_t n = event_log_read_recent(recent, 8);
|
||||||
|
JsonArray evs = doc["recent_events"].to<JsonArray>();
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
JsonObject e = evs.add<JsonObject>();
|
||||||
|
e["t"] = recent[i].tag;
|
||||||
|
e["d0"] = recent[i].data0;
|
||||||
|
e["d1"] = recent[i].data1;
|
||||||
|
e["ts"] = recent[i].ts_unix;
|
||||||
|
e["up"] = recent[i].uptime_s;
|
||||||
|
}
|
||||||
|
|
||||||
String body; serializeJson(doc, body);
|
String body; serializeJson(doc, body);
|
||||||
return post_json(cfg, "/api/v1/heartbeat", body);
|
return post_json(cfg, "/api/v1/heartbeat", body);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user