SenML
Каждый проект изобретает свой JSON вида {"temp": 23.1}, и серверу приходится знать все эти схемы. SenML задаёт одну: массив записей с именем, единицей, значением и временем, которые одинаково читаются в JSON и в CBOR.
Обновлено Редакция GAW
Содержание
SenML (Sensor Measurement Lists) — формат представления показаний датчиков и простых параметров, определённый в RFC 8428. Данные — один массив записей (pack), каждая запись — набор полей: имя источника, единица измерения, значение, время. Формат рассчитан так, чтобы устройство с минимальными ресурсами могло закодировать одно измерение, а сервер — эффективно собирать тысячи (разд. 1). Сериализаций четыре: JSON, CBOR, XML и EXI; передаётся обычно по HTTP или CoAP, для которого зарегистрированы Content-Format 110 (senml+json) и 112 (senml+cbor) (разд. 12.5).
Поля записи
| Поле | Метка JSON | Метка CBOR | Смысл |
|---|---|---|---|
| Base Name | bn | −2 | префикс, приписываемый к именам следующих записей |
| Base Time | bt | −3 | время, прибавляемое к t |
| Base Unit | bu | −4 | единица по умолчанию |
| Base Value / Base Sum | bv / bs | −5 / −6 | слагаемое для v и s |
| Base Version | bver | −1 | версия формата, по умолчанию 10 |
| Name | n | 0 | имя датчика или параметра |
| Unit | u | 1 | единица измерения |
| Value | v, vs, vb, vd | 2, 3, 4, 8 | число, строка, булево, двоичные данные |
| Sum | s | 5 | интеграл значения по времени |
| Time | t | 6 | время измерения |
| Update Time | ut | 7 | максимальный интервал до следующего показания |
Таблица 1 RFC 8428 (разд. 4.3). Базовые поля действуют на свою запись и на все последующие, пока не встретится запись с тем же базовым полем; обычные — только на свою (разд. 4). В записи должно быть ровно одно поле значения, если нет Sum (разд. 4.2). Поле ut позволяет серверу заметить, что датчик замолчал.
Пример из разд. 5.1.2 — напряжение и ток одного устройства «сейчас»:
[
{"bn":"urn:dev:ow:10e2073a01080063:","n":"voltage","u":"V","v":120.1},
{"n":"current","u":"A","v":1.2}
]
Имя после склейки с bn должно состоять только из символов A–Z, a–z, 0–9, -, :, ., /, _ и начинаться с буквы или цифры; стандарт рекомендует URI или URN — например, адрес 1-Wire или UUID (разд. 4.5.1). Единицы берутся из реестра IANA «SenML Units»: Cel, V, A, W, Hz, lx, Ohm и другие символы СИ; g (грамм) помечен как нерекомендуемый — положено kg (разд. 12.1). Масштабированных единиц в u нет вовсе: SenML требует немасштабированных единиц СИ, и единственное исключение — Cel вместо K (RFC 8798, разд. 2.1). Милливольты и миллисекунды датчик переводит в V и s сам; для таких единиц RFC 8798 завёл отдельный реестр вторичных единиц с масштабом и смещением (ms — s × 1/1000, mV — V × 1/1000, dBm — dBW со смещением −30), но в SenML версии 10 поле u принимает только основные единицы (разд. 3). Двоичное значение vd в JSON — Base64 с URL-безопасным алфавитом без дополнения, в CBOR — байтовая строка.
Время без часов
Время измерения — сумма bt и t (разд. 4.5.3). Значения меньше 2^28 (268 435 456) относительны «сейчас»: 0 — только что, −5 — пять секунд назад, положительные — в будущем, что удобно для команд исполнительным механизмам. Значения от 2^28 — абсолютные секунды Unix с 1970-01-01T00:00Z, так что самая ранняя абсолютная дата — 1978-07-04 21:24:16 UTC. Датчик без синхронизации времени шлёт относительные метки, а шлюз переводит их в абсолютные при приёме. В разд. 5.1.2 ряд токов за последние пять секунд записан как "t":-5 … "t":-1 плюс последняя запись без t, то есть «сейчас», при одном bt на весь пакет.
CBOR и потоки
В CBOR метки заменяются целыми: базовые — отрицательными, остальные — от 0 (разд. 6), так что {"n":"current","t":-4,"v":1.3} превращается в карту {0: "current", 6: -4, 2: 1.3}. Дамп примера из разд. 6 с семью записями заканчивается смещением 0xc3 — 195 байт. Для непрерывной записи есть потоковый вариант SenSML (разд. 4.8): в CBOR массив открывают с неопределённой длиной и читают запись за записью, не дожидаясь конца. Тот же формат годится для настройки: пакет SenML в POST или PUT трактуется как команда установить значения названных ресурсов в заданное время (разд. 4.9). SenML используют с CoAP, HTTP и MQTT; как собрать и разобрать такую запись в прошивке без динамической памяти — в статье о реализации протоколов.
Частые вопросы
Как выглядит минимальная запись SenML?
Массив с одной записью: [{"n":"urn:dev:ow:10e2073a01080063","u":"Cel","v":23.1}] — пример из разд. 1 RFC 8428. Поле n — имя датчика (здесь URN с адресом 1-Wire), u — единица из реестра SenML, v — числовое значение. Времени нет, значит измерение сделано «сейчас». Для булевых, строковых и двоичных значений есть поля vb, vs и vd.
Зачем нужны базовые поля bn, bt, bu?
Чтобы не повторять общее в каждой записи. Базовое поле действует на свою запись и на все следующие, пока не встретится запись с таким же базовым полем. Base Name приписывается спереди к n, Base Time складывается с t, Base Unit подставляется, если u не задано. В примере разд. 5.1.2 bn задаёт устройство один раз, а записи несут только короткие имена voltage и current.
Как SenML кодирует время, если у датчика нет часов?
Относительно момента отправки. Значения Time меньше 2^28 считаются секундами от «сейчас»: 0 — измерение только что, −5 — пять секунд назад, положительные — в будущем, для команд исполнительным механизмам. Значения от 2^28 и выше — абсолютные секунды Unix с 1970 года; поэтому самое раннее абсолютное время в SenML — 4 июля 1978 года. Получатель с точными часами переводит относительные метки в абсолютные при приёме.
Источники
- C. Jennings, Z. Shelby, J. Arkko, A. Keranen, C. Bormann. Sensor Measurement Lists (SenML). RFC 8428, August 2018 — разд. 1: формат и медиатипы для простых показаний датчиков в HTTP и CoAP, единственный массив записей, сериализации JSON, CBOR, XML и EXI, пример [{"n":"urn:dev:ow:10e2073a01080063","u":"Cel","v":23.1}]; разд. 4: базовые поля действуют на свою запись и все последующие до записи с тем же базовым полем, обычные — только на свою; разд. 4.1: Base Name, Base Time, Base Unit, Base Value, Base Sum, Base Version (по умолчанию 10); разд. 4.2: Name, Unit, Value — v число, vb булево, vs строка, vd двоичные данные, ровно одно поле значения, если нет Sum; Sum — интеграл в единицах, умноженных на секунды; Time; Update Time — максимальный период до следующего показания; разд. 4.3, табл. 1: метки bn −2, bt −3, bu −4, bv −5, bs −6, bver −1, n 0, u 1, v 2, vs 3, vb 4, vd 8, s 5, t 6, ut 7; vd — Base64 с URL-безопасным алфавитом без дополнения, в CBOR — байтовая строка; разд. 4.5.1: имя из символов A–Z, a–z, 0–9, «-», «:», «.», «/», «_», начинается с буквы или цифры, рекомендованы URI и URN, в том числе адрес 1-Wire и UUID; разд. 4.5.3: время = Base Time + Time, значения меньше 2^28 (268 435 456) — относительно «сейчас» (0 — сейчас, отрицательные — в прошлом), от 2^28 — секунды Unix с 1970-01-01T00:00Z, наименьшее абсолютное время — 1978-07-04 21:24:16 UTC; разд. 4.8: потоковый вариант SenSML; разд. 4.9: конфигурирование и управление через POST или PUT; разд. 5.1.2: пример с bn, voltage 120.1 V и current 1.2 A, затем ряд значений тока с t от −5 до −1 и последняя запись без t при bt 1.276020076001e+09; разд. 6: в CBOR метки — целые, базовые отрицательные, потоковый массив — неопределённой длины, дамп примера заканчивается смещением 0xc3; разд. 12.1: реестр единиц — символы СИ m, kg, s, A, K, Hz, V, Ohm, W, Cel, lx и другие, g помечена как нерекомендуемая; разд. 12.5, табл. 8: CoAP Content-Format 110 senml+json, 111 sensml+json, 112 senml+cbor, 113 sensml+cbor, 114 и 115 exi, 310 и 311 xml
- C. Bormann. Additional Units for Sensor Measurement Lists (SenML). RFC 8798, June 2020 — разд. 2, табл. 1: новые основные единицы B, VA, VAs, var, vars, J/m, kg/m3 и deg (помечена как нерекомендуемая); разд. 2.1: SenML требует немасштабированных единиц СИ, единственное исключение — Cel вместо K; разд. 3, табл. 2: реестр вторичных единиц с масштабом и смещением — ms (s, 1/1000), min (s, 60), h (s, 3600), kW (W, 1000), mV (V, 1/1000), mA (A, 1/1000), mm, cm, km (m), KiB (B, 1024), dBm (dBW, масштаб 1, смещение −30); пример: 100 ms → 0,1 s, 10 dBm → −20 dBW; в SenML версии 10 поле u допускает только основные единицы, вторичные — через новую версию или поле с «_» на конце; разд. 4: реестр не скачивать с IANA каждым устройством, а раздавать вместе с обновлением ПО
Нашли ошибку? ·
Смотрите также
- CBORДвоичный формат сериализации с моделью данных JSON плюс байтовые строки и теги; штатная полезная нагрузка CoAP
- CoAPПротокол запрос-ответ поверх UDP для ограниченных устройств: типы сообщений, методы, таймауты, порт 5683
- MQTTПротокол издатель — подписчик через брокер: топики, QoS, retain, Last Will
- SNTPПодмножество NTPv4 для клиентов с одним сервером: пакет 48 байт, порт 123, 64-битная метка времени с 1900 года
- Base64Запись двоичных данных 64 печатными символами: алфавит, группы по 3 байта, дополнение «=», base64url
- UUIDУниверсальный уникальный идентификатор: формат, variant и version, случайный v4, упорядоченный v7, UUID в BLE
- Реализация протокола обменаКадры по паузе, длине и разделителю, COBS, CRC-16, таймауты, разбор потока