Skip to main content

Статус устройств

Статус устройства — это заряд его батареи и запас по SNR (margin). Сервер запрашивает статус MAC-командой DevStatusReq, устройство отвечает командой DevStatusAns; у обеих команд CID 0x06. ONS спрашивает сам, включать ничего не нужно. Частоту запросов сервер подстраивает под то, как часто устройство выходит на связь и отвечает ли оно. Полученные значения сервер передаёт в каждом сообщении uplink, показывает в веб-интерфейсе и хранит в базе.

Когда сервер запрашивает статус​

Каждый запрос — это кадр downlink: он занимает эфирное время шлюза и окно приёма устройства. Поэтому сервер спрашивает редко, а тех, кто не отвечает, — ещё реже. Срок следующего запроса он считает так:

срок = max(интервал устройства, K × период кадров) × 2^промахов, рост от промахов — не выше потолка
СоставляющаяЧто этоПо умолчанию
Интервал устройстваНастройка dev_status_req_interval, секунды. Нижняя граница: чаще запрос не уходит. 0 или пусто — не спрашивать никогда, см. «Как изменить частоту запросов»86400 (сутки)
KСколько кадров uplink приходится на один запрос20
Период кадровКак часто устройство выходит на связь: сервер сглаживает интервал между кадрами, вес нового интервала — 0,25. Оценка появляется со второго кадра; до этого множитель по кадрам не действует—
ПромахиСколько запросов подряд осталось без ответа. Каждый промах удваивает срок0
ПотолокПредел роста срока от промахов30 суток

Промах засчитывается, когда срок следующего запроса настал, а ответа на прошлый так и не было, — один раз на запрос. Любой DevStatusAns, в том числе пришедший без запроса, обнуляет промахи.

Что получается при K = 20 и интервале в сутки:

УстройствоКак часто сервер спрашивает
Кадр раз в сутки, отвечаетРаз в 20 суток
Кадр раз в 5 минут, отвечаетРаз в сутки
Кадр раз в сутки, не отвечаетЧерез 20 суток, дальше раз в 30 суток
Кадр раз в 5 минут, не отвечаетЧерез сутки, 2, 4, 8, 16 суток, дальше раз в 30 суток
Интервал 0 или пустоНе спрашивает

Запрос по сроку сервер ставит только при приёме uplink — отдельных таймеров нет. На каждом uplink он обновляет оценку периода и, если срок настал, ставит DevStatusReq в очередь MAC-команд устройства. Запрос уходит в кадре downlink в окне приёма после этого uplink, вместе с данными приложения, если они есть в очереди. Ответ устройство присылает в ближайшем плановом uplink. Когда устройство какого класса принимает downlink — на странице «Классы устройств».

Попутная отправка​

Если кадр downlink уже уходит по другой причине — например, данные приложения, другая MAC-команда или подтверждение (ACK) подтверждаемого uplink, — сервер добавляет в него DevStatusReq раньше срока. Условие: с прошлого запроса прошло не меньше половины срока и не меньше интервала устройства. Своего кадра попутная отправка не создаёт.

У часто выходящих на связь устройств, которые отвечают, срок равен интервалу, поэтому раньше срока попутный запрос у них не уходит. У неотвечающего устройства попутный запрос уходит в первом же кадре downlink после того, как засчитан промах. Если кадры вниз у такого устройства уходят часто, интервалы из таблицы выше становятся на шаг короче: при кадре раз в 5 минут — сутки, сутки, 2, 4, 8, 16 суток, дальше раз в 30 суток.

Попутной отправки не бывает:

  • у мультикаст-групп и устройств класса B;
  • если в кадре не осталось места под команду;
  • если на прошлый запрос ещё не пришёл ответ, а срок следующего ещё не настал.

Когда запрос не уходит​

  • Интервал устройства 0 или пустой. Сервер не спрашивает статус никогда; флаги сервера этого не меняют. В прежних версиях ONS устройства, созданные через WebSocket API, получали пустой интервал — им статус не запрашивается.
  • Устройство только появилось в кэше сервера — например, после подключения к сети (join): на каждом join сервер собирает запись устройства заново. С этого uplink начинается отсчёт срока, запрос не уходит.
  • Прошлый DevStatusReq ещё стоит в очереди MAC-команд — не поместился в кадр. Второй сервер не ставит.
  • Мультикаст-группа. Uplink группы не передают, поэтому запросов статуса не получают.
  • Устройство класса B. ONS не передаёт таким устройствам кадры: запрос ставится в очередь, и в журнале появляется строка due, но в эфир он не уходит. Ответа не будет, и срок растёт, как у неотвечающего устройства. См. «Классы устройств».
  • Сбой внутри механизма. В этом случае сервер запрос не шлёт и пишет предупреждение в свой журнал.

Что приходит в ответе​

DevStatusAns несёт два байта: заряд батареи и margin.

Байт зарядаЧто значитbattery_level
0Устройство на внешнем питании0
1–254Уровень зарядаПроценты: байт / 254 × 100, дробное число. 1 → 0,39 %, 254 → 100 %
255Устройство не может измерить заряд255

Margin — запас по SNR, с которым устройство приняло запрос, в дБ, от −32 до 31. Сервер читает второй байт целиком: значения больше 31 переводит в отрицательные, вычитая 64. Два старших бита (RFU) он не отбрасывает: если устройство их выставит, margin получится неверным.

Последний ответ сервер держит в кэше устройства, а каждый ответ записывает в базу вместе со временем записи (UTC). После повторного подключения к сети (join) значения в кэше пустые, пока не придёт новый ответ.

Где видны значения​

WebSocket API​

В каждом сообщении realtime_data есть поля battery_level и margin — последние известные серверу значения. Они повторяются в каждом uplink, пока не придёт новый ответ. До первого ответа и после повторного подключения к сети (join) в них null. Время измерения в сообщении не передаётся.

Ответ попадает в realtime_data с задержкой на один uplink. Значения для сообщения сервер берёт, когда передаёт uplink дальше, а MAC-команды этого же uplink, включая DevStatusAns, разбирает примерно через 0,6 секунды. Поэтому ответ из uplink N появится в realtime_data только в uplink N+1. В базу — на график и в MCP — ответ попадает сразу при разборе.

Если у приложения есть JS-кодек, поля статуса не теряются: сервер дополняет сообщение результатом кодека и передаёт его дальше.

MQTT, HTTP и ThingsBoard​

Интеграции MQTT и HTTP публикуют тело того же вида, что realtime_data, с полями battery_level и margin. Интеграция ThingsBoard передаёт battery_level, margin и join_request_time как телеметрию.

Веб-интерфейс​

Блок «Состояние узла» — в карточке устройства в разделе «Узлы», на вкладке «Мониторинг»:

  • в заголовке — последний margin («N dB», подсказка «Запас помехоустойчивости») и заряд («N%»);
  • графики «Запас помехоустойчивости» (ось «Margin (dB)») и «Аккумулятор» (ось «Процент заряда»);
  • период — поле у кнопки «Количество месяцев»: от 1 до 12 месяцев, по умолчанию 1. Графики перестраиваются по нажатию кнопки.
Что показано вместо процентаКогда
«На внешнем питании», значок вилки; графика «Аккумулятор» нетУ самой старой записи за период заряд 0
«Нет актуальных данных»; графика «Аккумулятор» нетУ последней записи заряд 255
«Нет актуальных данных»Последнее значение на графике заряда вне диапазона 1–100, например 0

Записи с зарядом 255 в график «Аккумулятор» не попадают. Margin больше 31 график показывает как 31.

Журнал MAC-команд​

Каждый запрос по сроку и попутный, а также каждый ответ сервер записывает в журнал MAC-команд устройства. В веб-интерфейсе это блок «Журнал MAC-команд» на вкладке «Мониторинг», см. «Радиопараметры и журнал MAC-команд». Команда с CID 6 называется в нём DevStatus; по ней журнал можно отфильтровать.

НаправлениеСтатусСодержимоеЧто значит
ReqdueПустоЗапрос по сроку. Строка пишется при постановке запроса в очередь MAC-команд
Reqfree-rideПустоПопутный запрос в кадре, который уходил по другой причине
Ansanswered2 байта ответа в hexУстройство ответило

Это не те статусы sent, acked, rejected и unsolicited, что описаны на странице «Узлы»; интерфейс показывает их серой меткой. Источник (source) у таких строк — dev_status.

REST API​

Те же данные отдаёт REST API сервера, которым пользуется веб-интерфейс. Нужны вход в систему и право просмотра устройства.

  • POST /api/v1/chart/node_status/?dev_eui=<DevEUI>&period=<месяцев> — данные графика «Состояние узла» за последние period месяцев (по умолчанию 1), по возрастанию времени. В поле data ответа — массив с одним объектом {"name": "NODE_STATUS", "series": [...]}. Элемент series: name — время записи, value — margin (больше 31 урезается до 31), battery — battery_level, external — true, если заряд 0. Для неактивного устройства сервер ответит 404.
  • GET /api/v1/node/<DevEUI>/mac_log/?cid=6 — журнал MAC-команд, новые записи сверху, постранично. Фильтры: cid и status. Поля строки: time, cid, direction, payload, status, ack_bits, fcnt, source.

MCP​

  • get_device_status — блок dev_status: battery_level, margin и time — время последней записи в базе.
  • get_mac_log — журнал MAC-команд с полем source; limit — до 500, по умолчанию 50.
  • send_mac_command — запросить статус вне расписания: data = 06 (DevStatusReq), команда уходит на FPort 0. Нужны скоуп mcp:write, право change_node и флаг --allow_mac_write у MCP-сервера. Ответ ищите в get_mac_log. Строки Req для такого запроса в журнале не будет, появится только строка Ans answered.

Как проверить, отвечает ли устройство​

  1. Откройте карточку устройства в разделе «Узлы», вкладку «Мониторинг».
  2. В блоке «Журнал MAC-команд» выберите команду DevStatus.
  3. Сравните строки: после каждой строки Req (due или free-ride) по времени должна появиться строка Ans со статусом answered. Новые строки в журнале сверху, поэтому Ans окажется выше своей Req.

Если строк Ans нет, устройство не отвечает: интервал между запросами растёт вдвое, до 30 суток. Строка Ans без строки Req бывает, когда запрос отправили вручную, например через send_mac_command. Если строк нет вовсе, сервер статус не запрашивает — проверьте интервал устройства — или срок первого запроса ещё не настал. Тот же журнал отдаёт MCP-инструмент get_mac_log.

Как изменить частоту запросов​

Нижнюю границу задаёт настройка устройства dev_status_req_interval, в секундах:

ЗначениеЧто делает сервер
Больше 0Спрашивает не чаще, чем раз в столько секунд
0 или пустоНе спрашивает никогда

По умолчанию — 86400 (сутки). Это значение получают устройства, созданные в веб-интерфейсе, через WebSocket API и MCP; команда create_device_req этого поля не принимает.

Из API настройку меняет только MCP-инструмент update_device: поле dev_status_req_interval, целое от 0 до 2147483647 или null. Нужны скоуп mcp:write, право change_node и флаг --allow_node_write у MCP-сервера. После правки сервер сразу обновляет настройку в кэше устройства. В веб-интерфейсе, REST API и WebSocket API этого поля нет. Кроме того, её может изменить администратор сервера в панели администрирования сервера, и после сохранения сервер тоже сразу обновит кэш.

Остальные параметры общие для всего сервера. Их задаёт администратор инсталляции флагами запуска LWServer:

ФлагЧто задаётПо умолчанию
--dsr_framesK — кадров на один запрос. 0 снимает только множитель по кадрам20
--dsr_backoff_maxПотолок роста срока от промахов, секунды2592000 (30 суток)
--dsr_free_rideДоля срока для попутной отправки. 0 выключает попутную отправку0,5

Прежнее правило — запрос каждые dev_status_req_interval секунд без учёта ответов — возвращает набор --dsr_frames 0 --dsr_backoff_max 0 --dsr_free_ride 0. Он действует только для устройств с заданным интервалом: 0 и пусто всё равно значат «не спрашивать».

Что важно знать​

  • У редких устройств статус обновляется примерно раз в 20 кадров: у устройства с кадром раз в сутки — раз в 20 суток. Значение в realtime_data может быть давним, а время измерения в нём не передаётся; время есть в get_device_status и на графике.
  • После повторного подключения к сети (join) battery_level и margin в realtime_data — null, пока устройство не ответит. Первый запрос после join уйдёт не раньше, чем через интервал устройства.
  • Признак «На внешнем питании» график берёт из самой старой записи за период, а не из последней.
  • В базе заряд хранится в целочисленной колонке, поэтому на графике и в MCP он может отличаться от дробного значения в realtime_data.
  • Состояние механизма — оценка периода, время прошлого запроса, промахи — хранится в кэше сервера и в Redis (ключ живёт 30 суток с последней записи), в базе его нет. Если копии нет ни в памяти сервера, ни в Redis, отсчёт начинается заново, как у нового устройства: первый запрос уйдёт не раньше, чем через интервал устройства, промахи считаются с нуля.

См. также​