На прошлой неделе мы рассмотрели аппаратную часть набора GL.iNet GL-S200 Thread Border Router с тремя платами разработки nRF52840 Thread Dev Boards , и теперь, после работы с комплектом, во второй части обзора представлен опыт начала использования.
Начальная настройка GL-S200
Порт WAN подключен к коммутатору Ethernet, соединённому с модемом-роутером, а порт LAN — к ноутбуку для доступа к веб-интерфейсу через стандартный IP-адрес (192.168.8.1). GL-S200 использует ту же панель администрирования, что и другие роутеры GL.iNet, например роутер Beryl AX , рассмотренный ранее в этом году.
После запуска появится мастер выбора языка и установки нового пароля для панели администрирования. По завершению открывается доступ к знакомой панели администрирования GL.iNet 4.x.x.
После завершения мастера система автоматически подключается к Интернету, а средний RGB-светодиод на устройстве загорается зелёным.
Сеть Thread
Первый шаг — переход в раздел THREAD MESH в левой панели для включения сети Thread.
После нажатия кнопки Enable отобразятся три IPv6-адреса:
- Link-Local Address – все интерфейсы, доступные в пределах одной радиопередачи
- Local Address –
все интерфейсы, доступные извне сети Thread (похоже, в документации OpenThread он называется Global Address)Уточнение от GL-iNet: доступ к глобальному IPv6-интернету пока не поддерживается в OT/OTBR.Официальный ответ OpenThread доступен по ссылке: https://github.com/openthread/openthread/discussions/8794Локальный адрес является OMR-адресом (off-mesh-routable), через который можно обращаться к устройствам Thread со стороны Wi-Fi/Ethernet. - Mesh-Local EID – все интерфейсы, доступные в пределах одной сети Thread
При наличии собственных устройств Thread можно перейти в меню Thread Commissioning и ввести EUI64 устройств с предустановленным ключом, но GL.iNet упростили процесс для своих плат разработки Thread Dev Boards (сокращённо TBD), добавив отдельный раздел в веб-интерфейсе.
В разделе GL DEV BOARD->Устройства доступна кнопка Добавить устройства , после чего следует Применить. Нажатие кнопки SW2 на плате автоматически добавляет её в GL-S200 Thread Border Router.
Следует выбрать тип A0+A1 и задать имя платы. Процедура повторяется для двух других плат, после чего в панели администрирования отобразятся значения температуры, давления, влажности и освещённости для всех трёх плат.
Обновление прошивки GL-S200
В процессе работы вспомнилось, что GL.iNet предоставили новую прошивку для GL-S200, требующую ручной установки. Для этого переходим в «SYSTEM->Upgrade».
В панели администрирования отображается актуальность прошивки 4.1.3 release 5, так как новая версия ещё не загружена на OTA-сервер. Однако была предоставлена ссылка для загрузки с более новой прошивкой, собранной 6 марта 2023 года.
Файл загружен, затем в разделе локального обновления он отправлен на GL-S200 Thread Border Router.
После успешной проверки нажимается Установить, и в итоге на устройство установлена прошивка 4.1.3 Release7.
Обновление прошивки плат разработки Thread
В ходе обновления также обнаружено, что платы разработки Thread поддерживают обновление прошивки с версии 1.1.5 до 1.1.9, которое прошло без сбоев.
Топология сети Thread
Thread использует mesh-сеть: узлы подключаются напрямую к роутеру при близком расположении, а при выходе из зоны действия или слабом сигнале сами выступают роутерами. При размещении всех устройств на столе…
…сеть имела ожидаемую звездообразную топологию.
Платы были разнесены и расположены по прямой линии, одна размещена на улице.
Уличная плата легко идентифицируется по повышенным значениям температуры и освещённости.
Нажатие на «Self» в схеме топологии отображает уровень сигнала узла, подключённого к Thread Border Router. Однако не удалось задействовать плату разработки Thread в качестве роутера. Попытки выйти из зоны действия или ослабить сигнал (включая выход на улицу) не дали ожидаемой работы mesh-сети. Инженеры GL.iNet пояснили, что для этого требуется прошивка thread router:
В текущей версии прошивки TBD по умолчанию используется режим оконечного устройства (Thread End Device), который не поддерживает прямое соединение между устройствами. Сегодня мы предоставим вам прошивку для роутера Thread и соответствующее руководство по обновлению TBD.
Мне уже прислали прошивку для роутера, а также утилиту mcumgr для Linux и Windows.
$ bt -l
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
* 0 | 1137 | ttyUSB0 | ch341-uart | USB Serial
Последовательный порт обнаружен, поэтому можно выполнить команду для проверки текущего состояния прошивки:
$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image list
Error: NMP timeout
jaufranc@cnx-laptop-4:~/edev/GL-S200/TBD upgrade$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image list
Images:
image=0 slot=0
version: 1.1.9
bootable: true
flags: active confirmed
hash: 88b4725af7975e0b60915c320a82082bb2dda923b736f0e31d2c7d4d67cac3d3
image=0 slot=1
version: 1.1.5
bootable: true
flags:
hash: 4d8548e6910e7214d8325a7d1a49a8390fb25cce983bdb0b15bfecc657f7860b
Split status: N/A (0)
При первой попытке возникла ошибка «NMP timeout», но со второго раза всё заработало. Мы видим, что прошивка 1.1.9, которую я обновил через админ-панель, находится в слоте 0, а предыдущая версия 1.1.5 — в слоте 1. Теперь можно попробовать прошить роутерную прошивку:
$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image upload GL-Thread-Dev-Board-FTD-OTA-v1.1.9.bin
426.58 KiB / 426.58 KiB [========================] 100.00% 8.93 KiB/s 47s
Done
Давайте проверим ещё раз:
$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image list
Images:
image=0 slot=0
version: 1.1.9
bootable: true
flags: active confirmed
hash: 88b4725af7975e0b60915c320a82082bb2dda923b736f0e31d2c7d4d67cac3d3
image=0 slot=1
version: 1.1.9
bootable: true
flags:
hash: 7dbb8a9867a000bb968099593bc1f6c2c7bb28ab458719f499364c4a77feca9f
Split status: N/A (0)
Прошивка в слоте 0 — это текущая рабочая версия, а в слоте 1 находится только что установленная роутерная прошивка. Переключиться на новую версию можно следующим образом:
sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image test 7dbb8a9867a000bb968099593bc1f6c2c7bb28ab458719f499364c4a77feca9f
Затем мы можем перезагрузить плату и убедиться, что новая прошивка с хэшем 7dbb теперь находится в слоте 0:
$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB0,baud=460800 image list
Images:
image=0 slot=0
version: 1.1.9
bootable: true
flags: active confirmed
hash: 7dbb8a9867a000bb968099593bc1f6c2c7bb28ab458719f499364c4a77feca9f
image=0 slot=1
version: 1.1.9
bootable: true
flags:
hash: 88b4725af7975e0b60915c320a82082bb2dda923b736f0e31d2c7d4d67cac3d3
Split status: N/A (0)
После повторного добавления платы в админ-панель мы видим Thread Leader (GL-S200), два оконечных устройства (End Devices) и роутер (это наша плата с только что установленной роутерной прошивкой)
Конечные устройства не подключены к роутеру Board 1, так как все соединены с GL-S200. После перемещения Board 1 с одним конечным устройством в другую комнату (12 метров от GL-S200 Thread Border Router) топология не изменилась. Видимо, соединение «устойчиво», и узел Thread переподключится к другому роутеру только при выходе из зоны действия, а не просто при слабом сигнале.
После отключения и перезапуска GL-S200 два конечных устройства переподключились к роутеру Board 1, который стал «Thread Leader» в сети.
Таким образом, система работает. Неожиданным оказалось, что Board 2 (в 10 см от GL-S200 Thread Border Router) не переподключилась к GL-S200, несмотря на удалённость Board 1 (12 метров). То есть пока соединение активно, узел Thread не переключится на другой роутер, даже при более близком расположении и сильном сигнале, что логично для энергосбережения.
Далее Board 2 (конечное устройство) и Board 1 (роутер) вынесены за пределы действия GL-S200. После включения Board 1, затем Board 2 для их сопряжения, устройства возвращены обратно. В результате Board 2 подключилась к «Thread Leader» GL-200 через Board 1, действующую как роутер, как показано на схеме выше.
Информация о плате разработки GL Thread
При нажатии на три точки в столбце «Действие» для конкретного устройства открываются дополнительные опции: Device Detail, View Records, Edit Device, Get Code и Reset Device.
Сведения об устройстве
Отображаются EUI-64, имя, IPv6-адрес, расширенный MAC-адрес (64-битный вместо стандартного 48-битного), версия прошивки и данные сенсоров.
Просмотр записей
После непрерывной работы плат более 24 часов я проверил меню «Просмотр записей» для анализа графиков показаний сенсоров конкретной платы.
В целом отображение корректно, но в левом нижнем углу видны значения с 21:00, тогда как график начинается только с 23:00. Аналогичная ситуация наблюдается на всех платах.
На почасовом графике проблема выражена сильнее. Скорее всего, это ошибка визуализации, а не отсутствие данных, поскольку левосторонние точки всегда присутствуют.
Примеры кода
Раздел «Получение кода» наиболее важен для мониторинга и управления собственными Thread-устройствами, предлагая пять примеров реализации.
Для запуска примеров потребуется подключение к Thread Border Router GL-S200 через SSH. Начнём с кода для чтения данных с сенсоров.
root@GL-S200:~# /usr/bin/demo_get_sensor_data
1 dev_id=9483c44004df0679 connected=1 temperature=31.300811 humidity=43.409729 brightness=0 pressure=97.817392
2 dev_id=9483c47d79c19475 connected=1 temperature=32.742767 humidity=53.620910 brightness=0 pressure=97.814472
3 dev_id=9483c4ec736c4f68 connected=1 temperature=31.292800 humidity=42.652893 brightness=0 pressure=97.822056
Можно выбрать конкретное устройство по его EUI-64:
root@GL-S200:~# /usr/bin/demo_get_sensor_data 9483c44004df0679
dev_id=9483c44004df0679 connected=1 temperature=31.300811 humidity=43.409729 brightness=0 pressure=97.817392
Исходный код для справки:
#!/bin/sh
# Note, this file is stored in /usr/bin/demo_get_sensor_data
# Usage: demo_get_sensor_data <dev_id>
# It will print all sensor data if <dev_id> is null, and the <dev_id> is the EUI64 of the device, which saved in /etc/config/thread_devices
. /usr/share/libubox/jshn.sh
dev_id=$1
if [ -z "$dev_id" ]; then
res=$(curl -s localhost/rpc -d '{"jsonrpc":"2.0","id":"0","method":"call","params":["","gw","get_device_list",{}]}')
json_init
json_load "$res"
json_select result
json_select device_list
idx=1
while json_is_a ${idx} object; do
json_select ${idx}
json_get_var dev_id dev_id
json_get_var connected connected
json_select dev_data
json_get_var val_temp temperature
json_get_var val_humi humidity
json_get_var val_brightness brightness
json_get_var val_pressure pressure
echo "$idx dev_id=$dev_id connected=$connected temperature=$val_temp humidity=$val_humi brightness=$val_brightness pressure=$val_pressure"
json_select ..
json_select ..
idx=$((idx + 1))
done
else
res=$(curl -s localhost/rpc -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"call\",\"params\":[\"\",\"gw\",\"get_device_status\",{\"dev_id\":\"$dev_id\"}]}")
json_init
json_load "$res"
json_select result
json_get_var dev_id dev_id
json_get_var connected connected
json_select dev_data
json_get_var val_temp temperature
json_get_var val_humi humidity
json_get_var val_brightness brightness
json_get_var val_pressure pressure
echo "dev_id=$dev_id connected=$connected temperature=$val_temp humidity=$val_humi brightness=$val_brightness pressure=$val_pressure"
fi
Протестируем другие примеры.
ls /usr/bin/demo*
/usr/bin/demo_control_gpio /usr/bin/demo_sensor_trigger
/usr/bin/demo_control_led /usr/bin/demo_user_action_trigger
/usr/bin/demo_get_sensor_data
Второй пример управляет двумя RGB-светодиодами на плате, выбранной по идентификатору устройства EUI-64:
root@GL-S200:~# /usr/bin/demo_control_led 9483c44004df0679
LED OFF
LED ON
LED OFF
LED TOGGLE
Changle LED Color to Red light
Changle LED Color to Orange light
Changle LED Color to Yellow light
Changle LED Color to Green light
Changle LED Color to Blue light
Changle LED Color to Indigo light
Changle LED Color to Purple light
Changle LED Color to White light
Краткая демонстрация работы:
Пример управления GPIO настраивает выводы в режим OUTPUT с последовательным переключением уровней LOW/HIGH для указанной платы:
root@GL-S200:~# /usr/bin/demo_control_gpio 9483c44004df0679
Get GPIO Status
GPIO 0.15: 0
GPIO 0.16: 0
GPIO 0.17: 0
GPIO 0.20: 0
Set GPIO 0.15/0.16/0.17/0.20 to output low level
Get GPIO Status
GPIO 0.15: 0
GPIO 0.16: 0
GPIO 0.17: 0
GPIO 0.20: 0
Set GPIO 0.15/0.16/0.17/0.20 to output high level
Get GPIO Status
GPIO 0.15: 1
GPIO 0.16: 1
GPIO 0.17: 1
GPIO 0.20: 1
Последние два примера (управление светодиодами и GPIO) используют команду coap_cli — компактную реализацию CoAP. Например, для выключения светодиодов:
coap_cli -B 2 -N -e "$ctl_cmd_led_off" -m put coap://[$addr]/cmd 1>/dev/null 2>/
Синтаксис coap_cli:
root@GL-S200:~# coap_cli
coap_cli v4.2.1 -- a small CoAP implementation
Copyright (C) 2010-2019 Olaf Bergmann <bergmann@tzi.org> and others
TLS Library: None
Usage: coap_cli [-a addr] [-b [num,]size] [-e text] [-f file] [-l loss]
[-m method] [-o file] [-p port] [-r] [-s duration] [-t type]
[-v num] [-A type] [-B seconds] [-K interval] [-N] [-O num,text]
[-P addr[:port]] [-T token] [-U]
[[-k key] [-u user]]
[[-c certfile] [-C cafile] [-R root_cafile]] URI
URI can be an absolute URI or a URI prefixed with scheme and host
General Options
-a addr The local interface address to use
-b [num,]size Block size to be used in GET/PUT/POST requests
(value must be a multiple of 16 not larger than 1024)
If num is present, the request chain will start at
block num
-e text Include text as payload (use percent-encoding for
non-ASCII characters)
-f file File to send with PUT/POST (use '-' for STDIN)
-l list Fail to send some datagrams specified by a comma
separated list of numbers or number ranges
(for debugging only)
-l loss% Randomly fail to send datagrams with the specified
probability - 100% all datagrams, 0% no datagrams
-m method Request method (get|put|post|delete|fetch|patch|ipatch),
default is 'get'
-o file Output received data to this file (use '-' for STDOUT)
-p port Listen on specified port
-r Use reliable protocol (TCP or TLS)
-s duration Subscribe to / Observe resource for given duration
in seconds
-t type Content format for given resource for PUT/POST
-v num Verbosity level (default 3, maximum is 9). Above 7,
there is increased verbosity in GnuTLS logging
-A type Accepted media type
-B seconds Break operation after waiting given seconds
(default is 90)
-K interval send a ping after interval seconds of inactivity
-N Send NON-confirmable message
-O num,text Add option num with contents text to request. If the
text begins with 0x, then the hex text is converted to
binary data
-P addr[:port] Use proxy (automatically adds Proxy-Uri option to
request)
-T token Include specified token
-U Never include Uri-Host or Uri-Port options
PSK Options (if supported by underlying (D)TLS library)
-k key Pre-shared key for the specified user
-u user User identity for pre-shared key mode
PKI Options (if supported by underlying (D)TLS library)
-c certfile PEM file containing both CERTIFICATE and PRIVATE KEY
This argument requires (D)TLS with PKI to be available
-C cafile PEM file containing the CA Certificate that was used to
sign the certfile. This will trigger the validation of
the server certificate. If certfile is self-signed (as
defined by '-c certfile'), then you need to have on the
command line the same filename for both the certfile and
cafile (as in '-c certfile -C certfile') to trigger
validation
-R root_cafile PEM file containing the set of trusted root CAs that
are to be used to validate the server certificate.
The '-C cafile' does not have to be in this list and is
'trusted' for the verification.
Alternatively, this can point to a directory containing
a set of CA PEM files
Examples:
coap-client -m get coap://[::1]/
coap-client -m get coap://[::1]/.well-known/core
coap-client -m get coap+tcp://[::1]/.well-known/core
coap-client -m get coaps://[::1]/.well-known/core
coap-client -m get coaps+tcp://[::1]/.well-known/core
coap-client -m get -T cafe coap://[::1]/time
echo -n 1000 | coap-client -m put -T cafe coap://[::1]/time -f -
Демо триггера действий отслеживает состояние энкодера:
root@GL-S200:~# /usr/bin/demo_user_action_trigger 9483c44004df0679
2023/03/19 17:38:14 info (/usr/bin/demo_user_action_trigger:34) 9483c44004df0679: Press the knob.
2023/03/19 17:38:16 info (/usr/bin/demo_user_action_trigger:34) 9483c44004df0679: Press the knob.
2023/03/19 17:38:18 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob forward
2023/03/19 17:38:19 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob forward
2023/03/19 17:38:20 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob forward
2023/03/19 17:38:20 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob reverse
2023/03/19 17:38:21 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob reverse
2023/03/19 17:38:21 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob reverse
2023/03/19 17:38:23 info (/usr/bin/demo_user_action_trigger:34) 9483c44004df0679: Press the knob.
2023/03/19 17:38:25 info (/usr/bin/demo_user_action_trigger:32) 9483c44004df0679: Turn the knob reverse
Код использует бинарник /usr/bin/eco [Обновление: вероятно, это интерпретатор eco-lua для Lua , см. раздел комментариев]:
#!/usr/bin/env eco
-- Note, this file is stored in /usr/bin/demo_user_action_trigger, It listens for events reported when the user operates the knob.
-- Usage: demo_sensor_trigger
local ubus = require 'eco.ubus'
local sys = require 'eco.sys'
local cjson = require 'cjson'
local log = require "glog"
local OPT_TURNING_THE_KNOB = 1
local OPT_PRESS_THE_KNOB = 2
log.level(log.LOG_INFO)
sys.signal(sys.SIGINT, function()
print('
Got SIGINT, now quit')
eco.unloop()
end)
local con, err = ubus.connect()
if not con then
error(err)
end
con:listen('user_active_trigger', function(ev, msg)
local event_data = cjson.encode(msg)
log.debug('Recievd user active trigger ' .. ev .. ' ' .. event_data)
local trigger, operation, direction = msg.trigger, msg.operation, msg.direction
if operation == OPT_TURNING_THE_KNOB then
log.info(trigger .. ': Turn the knob ' .. direction)
elseif operation == OPT_PRESS_THE_KNOB then
log.info(trigger .. ': Press the knob.')
else
log.err('Unknown operation!')
end
end)
Аналогично реализован триггер сенсора, отслеживающий сигналы PIR-сенсора на всех Thread Dev Boards, подключённых к GL-S200:
root@GL-S200:~# /usr/bin/demo_sensor_trigger
2023/03/19 17:47:46 info (/usr/bin/demo_sensor_trigger:31) 9483c44004df0679: Human body detected.
2023/03/19 17:47:46 info (/usr/bin/demo_sensor_trigger:31) 9483c4ec736c4f68: Human body detected.
2023/03/19 17:47:49 info (/usr/bin/demo_sensor_trigger:31) 9483c4ec736c4f68: Human body detected.
2023/03/19 17:47:52 info (/usr/bin/demo_sensor_trigger:31) 9483c44004df0679: Human body detected.
2023/03/19 17:48:15 info (/usr/bin/demo_sensor_trigger:31) 9483c47d79c19475: Human body detected.
Эти примеры помогут начать разработку собственных скриптов.
Раздел «Автоматизация» в GL-S200
В разделе GL DEV BOARDS также предусмотрена секция «Автоматизация».
Попробуем управлять RGB-светодиодами на двух Thread Dev Boards с помощью энкодера на третьей плате.
После присвоения имени автоматизации выбираем действие пользователя и плату с энкодером: «Board 2».
Выбрано действие «Поворот ручки», затем «Действие(я) устройства».
Для управления оставшимися платами выбраны «Board 1» и «Board 2».
Единственная доступная опция — «Сменить цвет». Применяем настройки.
Однако RGB-светодиоды не реагировали на вращение энкодера. Оказалось, требуется предварительно включить подсветку отдельной автоматизацией, активируемой нажатием на энкодер.
Теперь функционал работает корректно.
Раздел автоматизации поддерживает вебхуки. Создадим оповещение в Discord при обнаружении движения: настроен сервер Discord, получен Webhook URL (https://discord.com/api/webhooks/xxxx) по инструкциям Discord .
Создана новая автоматизация с выбором триггера «Сенсор»…
… «Обнаружение человека» (активация PIR-сенсора движения)
… и действия «Вебхук».
Добавлен URL вебхука, выбран формат Json, с содержимым вида:
{"content":"OMG! Somebody has just entered the bedroom!"}
После нажатия «Применить» процедура повторена для кухни и офиса.
Теперь перемещение по дому, фиксируемое PIR-сенсорами трёх плат, вызывает оповещения в Discord.
Успех! Функционал автоматизации эффективен, но работает только с Thread Dev Boards от GL.iNet. На вопрос о публикации исходного кода для адаптации под сторонние Thread-устройства ответ не получен.
Дополнительно
Как и другие сетевые устройства GL.iNet, GL-S200 поддерживает GoodCloud для удалённого доступа, но с ограничениями — функции Thread и Bluetooth недоступны.
Кнопка Mode Switch изначально предполагала переключение между BLE/Thread, но, как в ранних роутерах, управляет активацией WireGuard/OpenVPN.
Из-за ограниченного времени Bluetooth-модуль не протестирован, но интерфейс должен быть аналогичен мосту GL-S10 BLE-MQTT , рассмотренному ранее.
Благодарю GL.iNet за предоставленный GL-S200 Thread Border Router для тестирования. Комплект доступен за $154.00 + доставка , тогда как отдельно GL-S200 в предзаказе предлагается за $79 (после предзаказа — $99).
Выражаем свою благодарность источнику, с которого взята и переведена статья, сайту cnx-software.com.
Оригинал статьи вы можете прочитать здесь.