Документ описывает упрощенный протокол взаимодействия с устройством интернета вещей, предназначенный главным образом для организации взаимодействия с устройством со слабыми ресурсами с использованием любых каналов связи, способных передавать потоки данных (COM, TCP/IP и т. д.). Управляемое устройство может быть хабом, при этом оно объединяет несколько других устройств. В рамках данного документа предполагается, что происходит взаимодействие Устройства с неким Клиентом (в частности, им может быть сервер IoT, к которому подключено устройство).
Каждое Устройство имеет уникальный 128-битный идентификатор (Uuid).
Каждое Устройство может иметь идентификатор типа (Uuid), определяемый производителем.
Взаимодействие происходит путем двухстороннего обмена сообщениями. Каждое сообщение — строка байт, причем в протоколе в качестве разделителей и зарезервированных элементов используются строки ascii-символов. Сообщения разделяются байтом с десятичным кодом 10 (символ перевода строки, "\n" в языке С).
Сообщения состоят из нескольких элементов, первый из которых называется заголовком, остальные аргументами. Элементы сообщения разделяются байтом с десятичным кодом 124 (символ "|").
 Пример сообщения:
 info|Argument 1|Argument 2|Argument 3\n
Для экранирования служебных символов в сообщении используется байт с десятичным кодом 92 (символ обратной косой черты "\"). Экранирование символов производится по следующим правилам:
Символ "\" экранируется им же. В сообщении — "\\".
Символ "|" экранируется как "\|".
Символ перевода строки заменяется экранированной буквой "n" (десятичный код 110). В сообщении — "\n".
Символ с кодом 0 заменяется на экранированный "0" (десятичный код 48). В сообщении — "\0".
Произвольный байт данных может быть записан как \xHH, где HH — шестнадцатеричный код символа в нижнем или верхнем регистре. Пример — "\x2f". Если шестнадцатеричный код не распознан, символ игнорируется.
Символ с кодом 0 служит для сигнализации о том, что Устройство перезагрузилось и его состояние было сброшено.
Информационное сообщение от Устройства. Заголовок — info. Предназначено для передачи информации, не требующей специальной обработки (например, отладочная информация) и предназначенной для передачи ее человеку (разработчику или оператору). Сообщение не требует ответа. Аргументы сообщения — текстовые строки, содержащие информацию, предназначенную для прочтения человеком.
Запрос идентификации Устройства от Клиента. Заголовок — identify. Аргументы отсутствуют. Устройство должно в течении 5 секунд вернуть ответное сообщение с заголовком deviceinfo со следующими аргументами:
 1. Уникальный идентификатор Устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" или "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".
 2. Человеко-читаемое название (не должно быть в формате UUID).
 3. Идентификатор типа Устройства (UUID), может отсутствовать.
Запрос идентификации Устройства-хаба от Клиента. Заголовок — identify. Аргументы отсутствуют. Устройство должно в течении 5 секунд вернуть ответное сообщение с заголовком deviceinfo со следующими аргументами:
 1. Специальный идентификатор "#hub".
 2. Уникальный идентификатор Устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" или "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".
 3. Человеко-читаемое название.
 4. Идентификатор типа Устройства (UUID), может отсутствовать.
Запрос на перечисление подключенных к Устройству-хабу дочерних устройств от Клиента. Заголовок — identify_hub. В ответ Устройство-хаб сразу возвращает ok либо err (если Устройство не является хабом). Позже дочерние устройства, подключенные к хабу, передают сообщения deviceinfo.
Сообщение синхронизации от Клиента. Заголовок — sync. Предназначено для проверки состояния канала связи с Устройством. В ответ на это сообщение Устройство должно в течении 5 секунд вернуть сообщение syncr.
Команда от Клиента. Заголовок — call. Первый аргумент — идентификатор вызова, второй — название команды (любое кроме зарезервированных, описанных в разделе "Зарезервированные названия команд"). Остальные аргументы сообщения — аргументы команды. Если Устройство не может выполнить команду в течение 5 секунд, оно должно регулярно передавать сообщение syncс с аргументом-идентификатором вызова. Устройство по окончании выполнения команды должно вернуть сообщение с заголовком ok в случае успешного завершения или err в случае неудачи, первый аргумент этих сообщений — идентификатор вызова, далее — возвращаемые значения (для сообщения ok) или описание ошибки (для сообщения err).
Сообщение синхронизации команды. Заголовок — syncс. Если управляемое устройство не может выполнить команду быстрее 5 секунд, оно должно регулярно посылать сообщение syncc. Если в течение 5 секунд сообщение не пришло, команда считается невыполненной.
Измерение в текстовом виде от Устройства. Заголовок — meas. Аргументы сообщения: название датчика и значение в текстовом виде, каждое число в отдельном аргументе сообщения. (см. Форматы данных сенсоров)
Измерения в бинарном виде от Устройства. Заголовок — measb. Аргументы сообщения: название датчика, далее значение в бинарном виде, все передаваемые числа (включая временную метку) упакованы в один аргумент сообщения без разделителей. Порядок байт — от младшего к старшему. (см. Форматы данных сенсоров).
Измерения в бинарном виде от Устройства, закодированные в base64. Заголовок — measb64. Аргументы сообщения: название датчика, далее значение в текстовом виде, все передаваемые числа (включая временную метку) упакованы в один аргумент сообщения без разделителей, закодированный в base64. Порядок байт числа — от младшего к старшему. (см. Форматы данных сенсоров).
Сообщение об изменении состояния от Устройства. Сообщение — statechanged. Передается устройством, когда происходит изменение его состояния. Аргументы:
 1. Название команды или "#" (см. раздел "Состояние устройства").
 2. Номер аргумента команды (начиная с 1) или название дополнительного параметра устройства.
 3. Новое значение.
Широковещательный запрос на поиск устройства (для сетей ptp, поддерживающих широковещательные запросы, например, UDP запрос в локальной IP сети). Заголовок — find_device. Аргумент — имя или идентификатор устройства, идентификатор сервера, возможны дополнительные аргументы, если это необходимо для идентификации сервера. Устройство с указанным именем или адресом, принявшее сообщение, может идентифицировать сервер (по аргументам или, например, адресу отправителя в IP сети) и подключиться к нему.
Отправка сообщений устройству, находящемуся за Устройством-хабом, происходит аналогично отправке сообщений самому устройству, но к каждому сообщению добавляется в начало два аргумента: специальный идентификатор "#hub" и идентификатор целевого устройства в виде текстового шестнадцатеричного представления UUID "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx". Аналогичным образом приходят ответные сообщения: заголовок "#hub", идентификатор отправителя, дальше само сообщение. Для отправки сообщения всем устройствам за хабом используется идентификатор "#broadcast".
Уведомления от хаба:
Появление устройства за хабом. Заголовок — device_identified (после заголовка #hub и идентификатора отправителя. Аргумент — название устройства.
 Пример:
 #hub|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|device_identified|test1\n
Отключение устройства от хаба. Заголовок — device_lost.
 Пример:
 #hub|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|device_lost\n
| 
 Название  | 
 Параметры  | 
 Описание и возвращаемые значения  | 
|---|---|---|
| 
 #sensors  | 
 отсутствуют  | 
 Запрос списка датчиков. Возвращаемое значение — список датчиков (формат описан ниже в разделе "Формат описания датчиков")  | 
| 
 #controls  | 
 отсутствуют  | 
 Запрос описания интерфейса управления. Возвращаемое значение — описание интерфейса управления (формат описан ниже в разделе "Формат описания интерфейса")  | 
| 
 #state  | 
 отсутствуют  | 
 Запрос состояния устройства (см. раздел "Состояние устройства")  | 
| 
 #setup  | 
 1 — идентификатор устройства 2 — имя устройства  | 
 Запись идентификатора и имени устройства в энергонезависимую память (команда может игнорироваться, если идентификатор и имя задаются при производстве устройства)  | 
При расширении списка зарезервированных команд в дальнейшем их названию будут начинаться с "#".
Описание датчиков представляет собой xml или json документ, которому соответствует список датчиков с атрибутами. Для каждого датчика указывается имя, отображаемое название, тип, единицы измерения (строка, например "оС", "м/с2" и т.д.) и дополнительные атрибуты. Имя сенсора уникально в пределах устройства. Тип датчика описывает формат передаваемых устройством данных и способ представления в сообщении. Форматы передаваемых значений описаны ниже в разделе Форматы данных датчиков. Описание датчиков передается между устройствами в xml или json формате, соответствующие схемы приложены в отдельных файлах sensors.xsd, sensors_simplified.xsd, sensors.json-schema, sensors_simplified.json-schema.
Примеры:
<sensors>
 <sensor name="temperature" title="Temperature in celsius from 1st and 2nd thermometers" type="s_f32_d2" unit="оС">
 <attributes min="-50" max="50"/>
 </sensor>
 <sensor><!--sensor definition--></sensor>
 </sensors>
{"sensors" : [
 {
 "name" : "temperature",
 "title" : " Temperature in celsius",
 "type" : "s_f32",
 "unit" : "оС",
 "attributes" :
 {
 "min" : "-50",
 "max" : "50"
 }
 },
 {
 //sensor definition
 }
 ]}
В различных форматах могут использоваться метки локального и глобального времени. Локальное время — время, измеряемое на устройстве от какой-то фиксированной точки (но не известной), например — от момента включения устройства. Глобальное время — количество миллисекунд, прошедшее с 01.01.1970г. В бинарном виде временная метка — всегда 64-битное целое число со знаком. Использование глобального времени возможно при наличии на устройстве часов реального времени. Временная метка всегда передается в начале измерения.
Строка формата датчика представляет собой набор ключей, разделенных символом "_". Ключ представляет собой набор символов, которые объединены в группы. Из каждой группы может присутствовать только один ключ.
Ключи, описывающие тип чисел в измерениях
| 
 Ключ  | 
 Описание  | 
|---|---|
| 
 f32  | 
 Вещественное число одинарной точности согласно стандарту IEEE 754. В языке C — тип float.  | 
| 
 f64  | 
 Вещественное число двойной точности согласно стандарту IEEE 754. В языке C — тип double.  | 
| 
 s8  | 
 Целое число со знаком размером 8 бит (1 байт). Значения от -128 до 128  | 
| 
 u8  | 
 Целое число без знака размером 1 байт. Значения от 0 до 255  | 
| 
 s16  | 
 Целое число со знаком размером 2 байта. Значения от -32768 до 32767  | 
| 
 u16  | 
 Целое число без знака размером 2 байта. Значения от 0 до 65535  | 
| 
 s32  | 
 Целое число со знаком размером 4 байта. Значения от -2147483648 до 2147483647  | 
| 
 u32  | 
 Целое число без знака размером 4 байта. Значения от 0 до 4294967295  | 
| 
 s64  | 
 Целое число со знаком размером 8 байт. Значения от -9223372036854775808 до 9223372 036854775807  | 
| 
 u64  | 
 Целое число без знака размером 8 байт. Значения от 0 до 18446744073709551615  | 
| 
 txt  | 
 Вместо чисел передается текст в кодировке UTF-8. Для этого типа не используются сообщения measb и measb64  | 
  
Ключ, описывающий размерность отсчета:
| 
 Ключ  | 
 Описание  | 
|---|---|
| 
 dXX  | 
 XX — размерность отсчета, целое число >=1. Например, d2, d3, d45. Если ключ не указан, размерность по-умолчанию — 1.  | 
  
Ключи, описывающие количество значений в одном измерении:
| 
 Ключ  | 
 Описание  | 
|---|---|
| 
 sv  | 
 Сокращение от "single value". Измерение представляет собой один многомерный отсчет с размерностью, указанной в описании датчика.  | 
| 
 pv  | 
 Сокращение от "packet value". Измерение представляет собой набор многомерных отсчетов с размерностью, указанной в описании датчика. Количество отсчетов в наборе 1 и более, может варьироваться в каждом измерении.  | 
Ключи, описывающие временную метку измерения:
| 
 Ключ  | 
 Описание  | 
|---|---|
| 
 lt  | 
 Временная метка локального времени устройства. Может быть в любых единицах измерения (секунды, милли-, микро- или наносекунды, тики и т. д.).  | 
| 
 gt  | 
 Временная метка глобального времени — количество миллисекунд, прошедшее с 01.01.1970г.  | 
| 
 nt  | 
 Временная метка отсутствует. Вариант по-умолчанию, если ни один из ключей не указан.  | 
Примеры (название датчика — всегда test):
| 
 Формат  | 
 Описание  | 
|---|---|
| 
 sv_f32_d3_gt  | 
 Измерение — единичный трехмерный отсчет, состоящий из трех значений с плавающей точкой одинарной точности и метки глобального времени Пример: meas|test|1532516864977|12.0|16.3|67.9  | 
| 
 sv_u32  | 
 Измерение — единичный одномерный отсчет, содержащий целое 32-битное число без знака Пример: meas|test|100500  | 
| 
 pv_d2_u8_lt  | 
 Измерение — пакет, содержащий метку локального времени и набор двумерных отсчетов из 1-байтовых беззнаковых значений Пример: meas|test|123456|3|27|56|1 meas|test|654321|67|12|252|22|56|12 123456 и 654321 — метки локального времени, в первом примере пакет содержит 2 отсчета по два значения, во втором — 3 отсчета.  | 
Элементы управления устройством объединены в группы, содержащие сами элементы управления и дочерние группы. В группе может быть задано горизонтальное или вертикальное размещение элементов. Если не задано — по умолчанию по вертикали.
Для каждого элемента управления задается команда, пересылаемая устройству, человеко-читаемое название элемента, список параметров и дополнительные атрибуты. Параметры команды добавляются в порядке следования в описании.
Если параметры для элемента управления не заданы, отображается кнопка, при нажатии отправляется команда без параметров. Если задан один параметр, генерируется один элемент UI в зависимости от типа параметра, при взаимодействии с которым отправляется команда, и кнопка только при необходимости, например, для поля ввода. Если параметры заданы, но присутствует атрибут "force_button" со значением "1", генерируется набор элементов UI согласно заданному размещению, соответствующих типам параметров, и кнопка, при нажатии на которую отправляется команда. Если атрибут "force_button" отсутствует, команда генерируется автоматически при изменении состояния элементов UI. Каждый параметр команды имеет набор атрибутов, различающихся в зависимости от типа. Если присутствует атрибут "button_text", он задает текст на кнопке.
Описание элементов управления передается между устройствами в xml или json формате, соответствующие схемы приложены в отдельных файлах controls.xsd, controls_simplified.xsd, controls.json-schema, controls_simplified.json-schema.
Примеры:
<controls>
 <group title="$title" layout="v|h">
 <group title="$title" layout="v|h">
 <control title="$title" command="$cmd" layout="v|h">
 <param title="$title" type="$type">
 <attributes key1="$value1" key2="$value2"/>
 </param>
 <param><!--param definition--></param>
 </control>
 <control title="$title" command="$cmd" layout="v|h" force_button="1" button_text="Some text">
 <!-- control definition-->
 </control>
 </group>
 <control><!--command definition--></control>
 <group><!--group definition--></group>
 </group>
 </controls>
{"controls" : {
 "element_type" : "group",
 "title" : "$title",
 "layout" : "v|h",
 "elements" :
 [
 {
 "element_type" : "group"
 //group definition
 },
 {
 "element_type" : "control",
 "title" : "$title",
 "layout" : "v|h",
 "command" : "$command",
 "button_text": "Some text",
 "params" : [
 {
 "title" : "$title",
 "type" : "$type",
 "constraints" :
 {
 "$key1" : "$value1",
 "$key2" : "$value2"
 }
 }
 ]
 }
]
 }}
| 
 Тип параметра  | 
 Возможные ограничения  | 
 Элемент UI  | 
| 
 checkbox  | 
 onValue — значение, передаваемое, когда чекбокс включен (по умолчанию "1") offValue — значение, передаваемое, когда чекбокс выключен (по умолчанию "0")  | 
 Чекбокс, checkable кпопка 
  | 
| 
 Поле ввода (с кнопкой отправки справа, если параметр у контрола один) 
  | 
||
| 
 select  | 
 values — список значений, разделенных символом "|" (если отсутствует, всегда отправляется "0") titles — список отображаемых названий для значений, разделенных символом "|"  | 
 Выпадающий список 
  | 
| 
 slider  | 
 min — минимальное значение (по умолчанию 0) max — минимальное значение (по умолчанию 1023) step — величина шаг (по умолчанию 1) layout — вид слайдера ("h" — горизонтальный, "v" - вертикальный)  | 
 Слайдер 
  | 
| 
 dial  | 
 min — минимальное значение (по умолчанию 0) max — минимальное значение (по умолчанию 1023) step — величина шаг (по умолчанию 1)  | 
 "Крутилка" 
  | 
| 
 radio  | 
 values - список значений, разделенных символом "|" (если отсутствует или пустой, элемент не отображается, передается значение "0") titles — список отображаемых названий для значений, разделенных символом "|"  | 
 Группа радиокнопок, из которых может быть нажата только одна 
  | 
| 
 hidden  | 
 value — отправляемое значение ("0", если отсутствует)  | 
 Не отображается в интерфейсе  | 
  
Состояние управляющего интерфейса устройства описывает текущие значения параметров команд устройства и значения дополнительных параметров, не связанных с интерфейсом управления. При изменении состояния устройство оповещает об этом подключенного клиента при помощи специального сообщения "statechanged". Аргументы сообщения сгруппированы по 3. Первым аргументом в группе идет команда, параметр которой изменился, или "#", если изменился дополнительный параметр, не связанный ни с какой командой. В первом случае вторым аргументом в группе идет номер аргумента команды (начиная с 1), во втором — название дополнительного параметра. Третий аргумент в группе — значение параметра. При запросе всего состояния устройства при помощи зарезервированной команды "#state" возвращается все состояние устройства в одном сообщении с заголовком "ok" и аргументами, сгруппированными по 3 по аналогии с сообщением "statechanged".