diff options
| author | Luke Hoersten <[email protected]> | 2026-06-13 22:52:41 -0500 |
|---|---|---|
| committer | Luke Hoersten <[email protected]> | 2026-06-13 22:52:41 -0500 |
| commit | 57c93fd2978ed5b5e64f4620803b7a2cd7767ed2 (patch) | |
| tree | 545d3a4ed3ee42cc87d4bb78ba9321eeadec19b2 /TESTING.md | |
| parent | 6cbdd4ed7466da28e524c9e0804722428a4b9698 (diff) | |
M6: state machine — POST /state, idle timer, /frame 409 guard
state_machine.{h,c} — central wake/sleep transitions:
- state_machine_init() creates the esp_timer one-shot for the idle timer.
- state_machine_set(target) is idempotent and atomic. On AWAKE: backlight
on, idle timer (re)armed. On ASLEEP: idle timer cancelled, backlight off.
Rejects with INVALID_STATE when the device is unconfigured.
- state_machine_frame_painted() restarts the idle timer if awake; called
by /frame after each successful paint.
- Idle-timer callback transitions to ASLEEP. TODO M7 hook: outbound POST
{viewport, state:sleep} to <scrypted>/state.
http_api.c:
- POST /state: parse {state}, accept "wake"/"sleep", reject others 400.
Unconfigured device → 409 "device unconfigured". Already-in-state → 204
(idempotent no-op). Successful transition → 204.
- POST /frame: 409 Conflict when state != AWAKE. After successful paint,
call state_machine_frame_painted() so the idle clock keeps resetting
while frames stream.
app_main:
- Initialize state_machine before http_api so the route handler can drive
it from request 0.
- After display_init(), reconcile the panel with the boot state:
UNCONFIGURED → test pattern (placeholder until M8 IP screen)
ASLEEP → display_sleep() so a configured device boots dark
AWAKE → leave on (not reached on fresh boot)
Disable path: idle_timeout_ms=0 in /config means the timer is never armed
and a wake state persists until /state {sleep} or a power cycle.
Build clean against ESP-IDF 5.4 (binary ~645 KB).
TESTING.md M6 expands with idempotency checks, 409-when-asleep, 409-when-
unconfigured, idle-timer firing within idle_timeout_ms+slack, /frame
restarting the idle timer, idle-timer disable via idle_timeout_ms=0, and
the M7 dependency note about the missing outbound sleep POST.
Diffstat (limited to 'TESTING.md')
| -rw-r--r-- | TESTING.md | 105 |
1 files changed, 96 insertions, 9 deletions
@@ -274,25 +274,112 @@ After every error: `decode_errors` in `GET /state` should increment. **How to verify** +First make sure the device is configured (M4 must be done): + +```bash +curl -X POST -H "Content-Type: application/json" \ + -d '{"viewport":"mudroom","scrypted":"http://host/cb","idle_timeout_ms":10000}' \ + http://<device-ip>/config +``` + +Wake / sleep: + ```bash -curl -X POST -d '{"state":"sleep"}' http://<device-ip>/state # backlight off -curl -X POST -d '{"state":"wake"}' http://<device-ip>/state # backlight on, loading +# Backlight off: +curl -i -X POST -H "Content-Type: application/json" \ + -d '{"state":"sleep"}' http://<device-ip>/state +# expect: 204 + +# Backlight on (loading-screen placeholder until M8): +curl -i -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +# expect: 204 + +# Idempotency: repeating either is also 204 with no side effects: +curl -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +curl -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +# Both: 204 +``` + +`/frame` while asleep returns 409: -# /frame while asleep: -curl -X POST -d '{"state":"sleep"}' http://<device-ip>/state +```bash +curl -X POST -H "Content-Type: application/json" \ + -d '{"state":"sleep"}' http://<device-ip>/state curl -i -X POST -H "Content-Type: image/jpeg" \ --data-binary @test-480x800.jpg \ http://<device-ip>/frame -# expect: HTTP/1.1 409 Conflict +# expect: HTTP/1.1 409 Conflict, body "device asleep — POST /state ..." +``` -# Idle timer (assuming default 60000ms): -curl -X POST -d '{"state":"wake"}' http://<device-ip>/state -# wait 65s without sending /frame +Idle timer: + +```bash +curl -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +sleep 12 # idle_timeout_ms was set to 10000 above curl http://<device-ip>/state | jq .state # expect: "asleep" ``` -**Status**: ⬜ pending. +When the timer fires, the serial log should print: + +``` +I (xxx) state: idle timer expired — sleeping +I (xxx) state: ASLEEP +``` + +Disabling the idle timer: + +```bash +curl -X POST -H "Content-Type: application/json" \ + -d '{"idle_timeout_ms":0}' http://<device-ip>/config +curl -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +sleep 70 +curl http://<device-ip>/state | jq .state +# expect: still "awake" +``` + +Resetting on `/frame`: every successful paint restarts the idle timer. + +```bash +# Set short idle, then keep painting to keep awake: +curl -X POST -d '{"idle_timeout_ms":10000}' \ + -H "Content-Type: application/json" http://<device-ip>/config +curl -X POST -d '{"state":"wake"}' \ + -H "Content-Type: application/json" http://<device-ip>/state +for i in 1 2 3 4 5; do + sleep 8 + curl -X POST -H "Content-Type: image/jpeg" \ + --data-binary @test-480x800.jpg http://<device-ip>/frame +done +curl http://<device-ip>/state | jq .state # expect "awake" +``` + +Unconfigured device rejects `POST /state` with 409: + +```bash +# (After factory reset / fresh boot, no /config yet) +curl -i -X POST -H "Content-Type: application/json" \ + -d '{"state":"wake"}' http://<device-ip>/state +# expect: 409 Conflict "device unconfigured" +``` + +Bad input: + +```bash +curl -i -X POST -d '{"state":"middle"}' \ + -H "Content-Type: application/json" http://<device-ip>/state # 400 +curl -i -X POST -d 'not json' \ + -H "Content-Type: application/json" http://<device-ip>/state # 400 +``` + +**Known gap (M7 closes this)**: when the idle timer fires the device transitions to ASLEEP locally but does NOT yet POST `{viewport,state:sleep}` to `<scrypted>/state`. That outbound POST lands with `state_client` in M7. + +**Status**: 🟡 builds clean against ESP-IDF 5.4. Awaiting hardware. --- |
