Device Management - Kush-Kelaiya22/imPress GitHub Wiki
Device Management
How to watch and look after classroom devices: presence, health states, diagnostics, device keys, the student module inventory, and enabling or disabling a device. The page is Modules in the admin menu. Reference: docs/api/device-api.md.
Contents
- The Modules page
- Presence
- Health states
- Diagnostics
- Device keys
- Disabling a device
- Student module inventory
- Linking a gateway to a class
- Reading the signs: worked examples
The Modules page
The top of the page has four counters:
| Counter | Counts |
|---|---|
| Total devices | every registered gateway and hub |
| Connected | devices currently online |
| OTA pending | devices with an update pending |
| Need attention | devices in the ERROR or DEGRADED health state |
Below it, the All devices table:
| Column | Shows |
|---|---|
| Device | name and MAC address |
| Type | c6 (gateway), s3 (hub) |
| Health | the health state badge, with its reasons underneath; disabled if switched off |
| Firmware | the running version; ✓ verified if an admin stamped it |
| OTA | the pending version and its state, or up to date |
| Assigned class | the class this gateway serves |
| Students (C6) | students currently online on this gateway's mesh |
| RAM free / Flash total | the gateway's latest report |
| Actions | Diagnostics, Push OTA, Verify |
Then the Student modules seen by gateways card: the inventory.
Presence
| Device | Online when | Offline / "seen" after |
|---|---|---|
| Gateway, hub | any contact: registration, heartbeat (every 15 s), status ping (every 2 min), WebSocket message | 30 s of silence |
| Student module | a join, a heartbeat (every 30 s), or a relayed message | 90 s of silence (three missed heartbeats), or an explicit leave |
The presence sweep runs every 15 s and makes these changes. Each change to online or offline is written to the activity log once (esp_device.online, esp_device.offline), not on every heartbeat. Teachers' class pages get a fresh snapshot on every change, and poll every 5 s as a fallback.
Health states
A gateway's health is computed from its latest values every time it is shown. The first rule that matches wins:
| State | When | Badge |
|---|---|---|
UNKNOWN |
never seen | outline |
OFFLINE |
silent for more than 30 s | grey |
UPDATING |
an OTA update is in progress for it | blue |
ERROR |
the last OTA update failed (failed, rolled_back, timed_out, unreachable), or it reset because of a panic, int_wdt, task_wdt, wdt or brownout in the last 10 minutes |
red |
DEGRADED |
its hub link is down, or Wi-Fi signal is below −80 dBm, or its lowest free memory since boot is below 20 KB | amber |
ONLINE |
none of the above | green |
The reasons are listed under the badge in plain words, for example reset by task_wdt 2 min ago, S3 link down, weak Wi-Fi (-83 dBm) or last OTA update rolled back.
Order matters: an offline device shows OFFLINE even if its last report was a crash, because you can't know more until it comes back. A device that is updating shows UPDATING, not DEGRADED.
When an ERROR clears:
- Caused by a crash: after 10 minutes of uptime.
- Caused by a failed update: only after a later update succeeds.
Rules source: backend/app/services/health.py, tested rule by rule in backend/tests/test_health.py.
Diagnostics
Diagnostics on a device opens a read-only panel, with Refresh and Reset key:
| Row | Meaning |
|---|---|
| Health | the state and reasons |
| Last seen | when it last contacted the backend |
| Firmware | the running version |
| Uptime | time since its last boot |
| Last reset | why it last restarted (table below) |
| Boots | boots since its first flash. A rising count with short uptimes means a reset loop |
| Wi-Fi signal | RSSI in dBm (−50 excellent, −70 fine, below −80 weak) |
| Free heap (now / lowest) | current free memory, and the lowest since boot |
| S3 link | up (with the hub's uptime) or down. Up means the hub's own heartbeat arrived over SPI in the last 15 s |
| Reported | when these values arrived |
| Device key | own key (active, since when) · issued (not used yet) · shared key |
Reset reasons:
| Value | Meaning | Usual cause |
|---|---|---|
poweron |
power applied | normal start, or power cut |
external |
reset pin | someone pressed reset |
software |
the firmware restarted itself | after an OTA update; a configuration change |
panic |
a crash | a firmware bug: capture the serial log |
int_wdt, task_wdt, wdt |
a watchdog fired | a task stuck or starving the CPU |
brownout |
the supply voltage dipped | a weak power supply or cable |
deepsleep |
woke from deep sleep | not used by imPress |
other |
anything else |
Firmware older than v2.1 doesn't send diagnostics; its fields show not reported, and the rules that need them don't apply. The panel only reads: diagnostics add no remote control over devices.
The hub doesn't send its own reset reason or memory yet. Only the gateway does, along with the hub link state and the hub's uptime.
Device keys
Every device starts with the site's shared key. When it registers, the backend issues it its own key, and from then on the device uses that key. The Diagnostics panel shows the state:
stateDiagram-v2
[*] --> shared: no key of its own
shared --> issued: registers with the shared key → the response carries its key
issued --> issued: registers again before using it (a lost response) → a new key replaces it
issued --> active: first request made with its own key
active --> shared: an admin clicks Reset key
| State | What it means for security |
|---|---|
| shared key | the device still uses the shared key; anyone with that key can act for it |
| issued | a key was issued but never used; the shared key still works for this device |
| active | only this device's key can act for it, and that key works for no other device |
Reset key (after a confirmation):
- The device's current key stops working at once.
- On its next request the device gets
401, drops its key, registers again with the shared key, and is issued a new one.
Use it when a device was reflashed (its flash, and so its key, was erased) or when a key may have leaked.
When every device shows own key, set IMPRESS_DEVICE_KEYS_REQUIRED=true. The shared key then only works for registration (Security).
Disabling a device
Switching a device's access off (admin) refuses every request for that device, whichever key it presents, and excludes it from deployments. Other devices are unaffected. Switching it back on restores it; its key is kept.
Student module inventory
The Student modules seen by gateways card lists every student module any gateway has heard:
| Column | Meaning |
|---|---|
| Device ID | the module's 32-bit ID in hex (from its MAC). Older firmware that sends no ID shows — and is keyed by enrollment number |
| Enrollment | the student identity the module last announced |
| State | connected, or seen N ago (after a leave or 90 s of silence) |
| Class | the class of the gateway that heard it, and its section |
| Gateway | which gateway relayed it |
| Last seen | how long ago |
| Battery | as reported (currently always 100 % on student modules) |
You can filter by state and class, and search by device ID or enrollment number (partial matches, any case).
Properties:
- One row per module. A module that reconnects, or moves to another room, keeps its row; its gateway and class update.
- No history: the inventory records presence, not location over time, by design.
- Deletes: erasing a student keeps the module's row but removes the enrollment number. Deleting a class keeps the rows but unlinks them.
- Teachers see their own class's modules in the Live Devices panel; the full inventory is admin-only.
Linking a gateway to a class
| Method | How |
|---|---|
| Room code (recommended) | set the class's Room Label (classroom_code, e.g. RM-201) and have the gateway register with it. The smoke test does exactly this |
| Automatic | a gateway that registers without a code links itself to the first active class without a gateway (lowest id). Good for a single room; unpredictable with many |
| By an admin | the link and unlink actions in the API (/api/admin/modules/{id}/link-device, /unlink) |
A hub is linked to its gateway (gateway_id) so that OTA prompts for the hub can be delivered through that gateway.
Reading the signs: worked examples
| What you see | Likely cause | Action |
|---|---|---|
ERROR · reset by brownout 3 min ago; Boots rising |
the power supply sags under Wi-Fi bursts | a better 5 V supply and a shorter, thicker cable |
DEGRADED · S3 link down; students not reaching the backend |
the hub is off, unplugged or crashed, or the SPI wiring is loose | check the hub's power and the 6 signal wires plus ground |
DEGRADED · weak Wi-Fi (-84 dBm) |
the gateway is far from the access point | move the gateway, or add an access point |
DEGRADED · low memory |
a memory leak or overload | capture the serial log; note the firmware version; report it |
ERROR · last OTA update rolled back |
the new image couldn't reach the backend within 120 s and the old one booted | see Recovery Procedures |
OFFLINE, last seen hours ago |
power off, or the Wi-Fi credentials changed | check power; check the NVS Wi-Fi settings |
| Gateway online, inventory empty during class | modules unprovisioned (NO ID), wrong mesh channel, or hub down | check a module's screen; the hub link state |
shared key on a device running v2.1 firmware |
it hasn't registered since the backend upgrade | it will at its next boot or reconnect; or restart it |