Commit graph

3 commits

Author SHA1 Message Date
cjkas
89d3713d86 test: prove no read item can outgrow the snapshot unit
The read routes leave out a room, shade, group or linked shade that
doesn't fit the 3 KB unit, without telling the client (KNOWN_ISSUES.md).
test_snapshot_limits fills a snapshot with the largest possible items and
checks every read document written with the real unit is identical to
the same document written with an unlimited one. The largest item, a
shade, is 1,097 bytes. The unit is now SNAPSHOT_UNIT_SIZE in
ModelSnapshot.h, used by Web.cpp and the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 23:29:04 +02:00
cjkas
72b37e5f8d refactor: apply shade model edits on loop() through ModelEditor
The 19 routes that changed rooms, shades, groups and repeaters on the web
server task (add, save, delete, link and unlink, setPaired, the sort
orders) now copy their request into a model_edit_t, queue it on the
LoopQueue and reply {status:accepted,requestId:N}. loop() applies it
(SomfyJson.cpp, next to fromJSON) and broadcasts requestResult {requestId,
ok, id, code, desc}. One edit at a time; a second gets 503, a body over
4 KB gets 413.

ModelEditor.h/.cpp holds the rules, tested natively: the lowest free id,
the next sort order, a free remote address, adding to and removing from
the group-member and repeater lists, and the GPIO pin-conflict check. They
replace the getNext*Id/getMax*Order copies, the remote-address search,
the list code and the inline pin checks. The pin check now uses the
protocol being saved and checks every pin against Ethernet, not only up.

/getNextRoom, /getNextShade, /getNextGroup, /groupOptions and a new
/repeaters (the UI already called it) are ModelSnapshot reads.

The web UI's editJSON() sends an edit, waits for its requestResult, then
reads the item back from /shade, /group, /room or /repeaters, so the
callbacks that used the old reply bodies are unchanged. No result within
5 s offers a reload; reads and edits told Busy are retried. It now also
refreshes its lists on shadeAdded/shadeRemoved/groupAdded/groupRemoved
from other clients, and procRoomRemoved keeps the right rooms.

Also fixed: a shade that fails validation is no longer added; linked
repeaters and sort orders are saved; linking reports a full list.

27 new native tests, 319 in all. Flash: esp32devdbg -11,484 bytes,
esp32dev -7,180 bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:34:39 +02:00
cjkas
c4d20908a5 refactor: serve the read routes from a ModelSnapshot that loop() fills
/controller, /discovery, /rooms, /shades, /groups, /room, /shade and /group
now take a SnapshotSlots slot, queue a fill on the LoopQueue and send a
chunked response whose body waits (RESPONSE_TRY_AGAIN) until loop() has
copied the shade model into the slot. SnapshotWriter then streams the
document from that copy a unit at a time, so each document describes one
moment. At most two reads run at once; a third gets 503. A slot's 5.6 KB
snapshot is allocated only while a read holds it, and its atomic state
decides whether loop() or the read frees it when the read goes away first.

The JSON of each item is unchanged and now lives in ModelSnapshot.cpp,
where the native tests check it. Replies still written on the web server
task copy their one item with SomfySnapshot.cpp, so serializing a group
no longer calls updateFlags(), which emitted groupState and published MQTT
from async_tcp.

Also: every read route is chunked and leaves out an item too big for its
3 KB unit, like /controller did; /discovery drops its timing log; the
SOMFY_MAX_* limits move to ShadeTypes.h.

21 new native tests, 292 in all. Flash: esp32devdbg +440 bytes, esp32dev
+2,064 bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:04:29 +02:00