feat: report main-loop health in memStatus

memStatus now carries loopRate (loop() passes per second) and loopMaxUs
(the longest pass, in microseconds) over the window since the last
broadcast. Only a broadcast closes the window, so a client connecting
does not wipe a slow pass before Home Assistant has seen it.

/discovery is formatted on the web server's task, so its memory block
reports the last closed window through atomics instead of reading the
counters the loop task is still filling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-18 13:53:30 +02:00
parent 96b00b70f4
commit ce505e93f6
6 changed files with 122 additions and 1 deletions

View file

@ -28,6 +28,7 @@ extern MqttConnection mqtt;
extern rebootDelay_t rebootDelay;
extern ESPNetwork net;
extern SomfyShadeController somfy;
extern LoopStats loopStats;
static unsigned long _lastHeapEmit = 0;
@ -680,8 +681,15 @@ void ESPNetwork::emitHeap(uint8_t num) {
json->addElem("min", minHeap);
json->addElem("total", ESP.getHeapSize());
json->addElem("uptime", (uint64_t)millis());
// The window in progress. Only a broadcast closes it, so a client
// connecting doesn't wipe a slow pass before Home Assistant has seen it.
json->addElem("loopRate", loopStats.rate(millis()));
json->addElem("loopMaxUs", loopStats.maxUs());
json->endObject();
if(target == heap_emit_t::room) sockEmit.endEmitRoom(0);
else sockEmit.endEmit(num);
if(target == heap_emit_t::broadcast) _lastHeapEmit = millis();
if(target == heap_emit_t::broadcast) {
_lastHeapEmit = millis();
loopStats.publish(_lastHeapEmit);
}
}