The model is what the firmware, the lean page and any other reader share, so each reads a device the same way. It is data, not code: the firmware is built from it, and a reader decodes with it. How it travels over the air is Sensor Data Format; where its names and units come from is Health and Sensor Data Standards.

flowchart LR
	T[Device type] --> S[Sensors]
	D[Device] --> T
	S --> C[Channels]
	C --> L[Log]
	C --> A[BTHome advert]
	L --> R[Readings]
	A --> R

The parts

  • Device type: a kind of hardware, such as a Puck.js v2.1, with its maker, its model and the sensors it has (Puck.js).
  • Device: one piece of hardware. It names itself: it reports its own id (its Bluetooth address, read by the device itself), type and firmware, because a reader cannot rely on what its platform says about it. Chrome gives a Puck an opaque id of its own making, a native app gives its Bluetooth address, and iOS gives neither (Reaching a Puck).
  • Sensor: a part of a device type that measures something: an accelerometer, a thermometer, the button.
  • Channel: one stream of values the firmware records from a sensor. It has a kind, a unit, how it is summed up over time, and the standard it maps to:
    • an interval: a count over a span, such as steps per minute;
    • an instant: a value at a time, such as a temperature;
    • an event: something that happened, such as a double press.
  • Log: what the device keeps. Each record is numbered in order, so a reader keeps a bookmark (the last number it read) and asks for what came after it, and two readers each keep their own. When the log is full the oldest records go first. A record whose time was taken before the device’s clock was set is kept and marked as having no known time. Times are UTC, but an interval follows the device’s local hours, and the log records the device’s zone whenever it changes, so a reader knows exactly what each interval covered and a local day’s total is exact in any zone.
  • Reading: what a reader makes of a record or an advert: the device, the channel, the time or span, the value in the channel’s unit, the channel’s standard name, and an id of its own made from the device and the record’s number, so reading one record twice makes one reading.

The Puck’s channels

The channels a Puck.js v2.1 is planned to have, and the standard each takes. A cell left empty has no standard that fits, so the channel keeps a name of this project’s own there. Each channel’s number, value encoding and how often it is written are in Sensor Data Format.

ChannelSensorKindUnitBody standardHome standardBTHome object
Stepsaccelerometer’s step detector, during an activityinterval, summed per minutestepsHealth Connect’s steps record; HealthKit’s stepCountnone for steps: a count (0x3E, uint32)
TemperaturePCT2075TPinterval, averaged per hour°CHome Assistant’s temperature0x02, 0.01 °C
Batterythe cellinstant, daily%Home Assistant’s battery0x01
Buttonthe buttonevent: press, double press, long pressHome Assistant’s button events0x3A
Movingaccelerometer’s movement detectionevent: moving, stillHome Assistant’s moving0x22
Openingmagnetometer used as a reed switchevent: open, closedHome Assistant’s opening0x11
Light levelthe red LED read as a sensorinterval, averaged per hournone, 0 to 1
Magnetic fieldMMC5603NJinstant, three axes, experimental
Activitya gesture set to start one (Gestures), or a readerevent: the kind that starts, 0 when it stopsHealth Connect’s exercise session; HealthKit’s workout

Light is uncalibrated, so it is a level from 0 to 1 and never lux: BTHome’s illuminance object (0x05, lux) would claim a unit it does not have. Temperature, battery and light are home readings, since Health Connect’s temperature records are of a body, not a room.

Open

  • Giving each device its advert key, and trying an encrypted advert on a Puck. How it encrypts is designed and tested on the host (Sensor Data Format, Adverts); until a device holds a key, its adverts carry only battery and temperature.
  • Who may connect to a device, since its console runs any code it is sent.