Step 4a of docs/SECURITY_PLAN.md. Port 80 keeps the eleven HTTP routes of
ADR 0006 and the socket at /ws; everything else moved to protocol 2.
- Port 8081 (ApiRoutes) and the socket on 8080 (SocketEmitter) are gone.
Protocol 2 owns its frame buffer and loop-task check.
- Port 80 drops every route the old web UI called: reads, edits,
settings, scans, reboot, /shades.cfg, /discovery. HttpRoutes.cpp holds
what stays.
- ModelSnapshot, SnapshotSlots and the read documents are gone. The item
snapshot types stay, as ItemSnapshot, for events, MQTT and the command
replies.
- Model edits reply only to their protocol 2 op: requestResult goes.
- The settings' toJSON writers, used only by the settings routes, go.
- The _espsomfy_rts._tcp mDNS record moves to port 80, with path=/ws.
- The memory event reports the loop-rate window it closes.
- A deleted room no longer re-publishes its retained MQTT topics.
- e2e: the heap check reads the sync's status; the sync is checked on
its own instead of against /controller.
- README gets an API and ports section.
BREAKING CHANGE: ports 8081 and 8080 and the old HTTP routes are gone.
Home Assistant needs integration 3.0.0 or newer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every append found the end of the buffer with strlen(), up to four
times per append and four appends per field, so building a response
cost the square of its size. /discovery fills a 4 KB buffer and spent
about 195 ms of its ~210 ms there (shades 126 ms, groups 69 ms), all on
the async_tcp task that serves every socket and web request.
Keep the length in the formatter and write every append at the end
through one helper. The web response and socket event subclasses and
ControllerChunker use the tracked length too. Output is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add Timing.h and use it to log what holds up the main loop, how long a
new socket client's setup takes, slow socket sends, and how long each
web request took and from which client. Socket connects and disconnects
are logged with how long the client stayed, and late pings as warnings.
Routine sends and pings are not logged, as each line costs several ms
on a 115200 baud console.
Report a stored crash once with the crashed and running build IDs, then
erase it, since it was reported on every boot and its backtrace only
decodes against the build that crashed. Mount the file system once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When something didn't fit, the formatters skipped it silently, closing
brackets included, and clients got malformed JSON. Two writes could
also go past the buffer:
- AsyncJsonResp flushed when full and then wrote the value without
checking again, so a value bigger than the whole buffer overflowed.
It is now streamed straight out instead.
- JsonSockEvent::closeEvent added the closing ] when only one byte was
left, putting the terminator one byte past the buffer.
The formatters now set an overflowed() flag and log an error, and a
socket event that overflowed is logged and not sent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JsonFormatter and BufferedJsonFormatter move verbatim out of
WResp.cpp/WResp.h, which now include JsonFormatter.h. They don't need
the web server, so on their own they can be unit tested on the PC; the
native env builds the new file. AsyncJsonResp and JsonSockEvent stay
in WResp. No behaviour change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>