SmartestHome/pebble-presence/WIREFORMAT.md

68 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# The wire format
One byte-array tuple over AppMessage, defined here and implemented twice — in
`src/pkjs/index.js` (writer) and `src/c/main.c` (reader). **If you change one, change
the other and the version byte.** A silent mismatch between them decodes into garbage
rooms rather than failing, which is why the version byte exists at all.
## Why a byte array and not a dictionary
Pebble's guaranteed AppMessage buffers are small (124 in / 636 out documented minimum,
~2 KB in practice for a JS-backed app), and a dictionary costs ~7 bytes of overhead per
tuple. A ten-room plan as one tuple per room would spend more on keys than on rooms. As
one packed array it is a few hundred bytes with room to spare.
## Coordinates are quantised to a byte
Room polygons are already stored normalised 0.01.0 by `identity`. Multiply by 255 and
round: a vertex costs 2 bytes and the error is under half a percent of the plan's
width, which on a 170 px inscribed box is sub-pixel. The phone does the projection into
the watch's inscribed box; the watch does no floating point at all.
## Layout
```
header
u8 version 1
u8 room_count
u8 unplaced_count
u8 flags bit0: positions are available on this level
per room (room_count times)
u8 name_len
u8[] name UTF-8, truncated to 24 bytes by the writer
u8 state 0 = empty, 1 = occupied, 2 = unknown (drawn, never reported)
u8 vertex_count
u16[] vertices x,y each u8, so 2 bytes per vertex
u8 target_count anonymous radar targets — somebody is there, nobody knows who
u16[] targets x,y each u8
u8 occupant_count
per occupant
u8 colour_index 0..7 into identity's PERSON_COLORS, 255 = unknown
u8 initial ASCII
u8 occ_flags bit0: has a fused position
u16 position x,y each u8 — PRESENT ONLY when bit0 is set
u8 name_len
u8[] name UTF-8, truncated to 16 bytes
per unplaced person (unplaced_count times)
u8 colour_index
u8 initial
u8 name_len
u8[] name
```
## Truncation, and why the writer does it
The writer builds the payload and, if it exceeds the inbox size, sheds in this order:
1. **Occupant names** — the detail screen loses full names and falls back to initials.
Worst outcome of the three and still legible.
2. **Rooms with no occupants** — an empty room is the least informative thing on the
plan.
3. **Whole levels** — refuse, and say so on the watch.
It never silently sends a partial structure. A payload that decodes half-way is worse
than one that does not arrive, because the watch cannot tell the difference between
"three rooms" and "three rooms and then the buffer ran out".