DOCS / сеть и радио

Подключить LoRa-радио к Quiet Spaces — путь Meshtastic

Это не основной путь. Meshtastic в quite.space — экспериментальная функция: драйвер есть, узел к плате подключается, но продуктовый сценарий по радио на нём целиком не прогонялся. Проверен другой носитель — RNode, и начинать стоит с него: Радио в quite.space.

Этот документ остаётся полным руководством по Meshtastic — прошивка, регион, канал сегмента, профиль и проверка. Здесь же живёт всё про утилиты terminal radio * и quiet-radio; в документах RNode они не повторяются, только упоминаются ссылкой.

Пошагово, для Heltec WiFi LoRa 32 V3 и любого другого узла Meshtastic. Ничего не нужно знать заранее — каждый шаг объясняет, зачем он.


Что вообще происходит

Quiet Spaces сам по себе не управляет радиочипом. Он разговаривает с прошивкой Meshtastic, которая уже стоит на плате и умеет отправлять и принимать пакеты по воздуху. Наш узел подключается к ней по USB (или по Wi-Fi) и просит: «отправь вот эти байты».

Quiet Spaces  ──USB──▶  прошивка Meshtastic  ──LoRa──▶  другое радио

Отсюда два следствия, которые определяют весь процесс:

  1. На плате должна стоять Meshtastic. Заводская прошивка Heltec (та, что показывает на экранчике «LoRa mode 0») — это демо-программа производителя. Она не умеет разговаривать по протоколу Meshtastic, и наш узел с ней не соединится.
  2. Два радио слышат друг друга, только если у них совпадают три вещи: регион, скоростной пресет (modem preset) и ключ канала. Если хоть одна отличается — оба радио исправно передают, и ни одно ничего не слышит. Ошибки при этом не будет нигде: тишина неотличима от «рядом никого нет». Именно поэтому у нас есть отдельная утилита для проверки, см. шаг 5.

Шаг 0. Посмотреть, что вообще подключено

Подключите плату по USB и спросите:

terminal radio list

Команда обходит все последовательные порты и говорит про каждый, что на нём нашлось:

  /dev/cu.usbserial-0001           no Meshtastic here · chip esp32s3 (from its boot banner)
  /dev/cu.Bluetooth-Incoming-Port  Bluetooth port, not a USB radio

Три возможных ответа и что они значат:

Ответ Что делать
Meshtastic node … с регионом и пресетом прошивка уже стоит → шаг 3
no Meshtastic here · chip … нужна прошивка → шаг 1
busy — another program holds this port порт занят: закройте приложение Meshtastic, монитор порта или второй запущенный узел

Почему для «пустой» платы нужен отдельный трюк. Плата без Meshtastic не говорит на порт вообще ничего — ноль байт на любой скорости. Но каждый ESP32 при сбросе печатает строчку своего загрузочного ПЗУ, и radio list ради этого дёргает линию сброса. Отсюда и берётся chip esp32s3.

Это единственное, что можно узнать о неприлитой плате: семейство чипа. Модель платы из него не следует — на ESP32-S3 сидят десятки разных плат с разной распиновкой радио. Поэтому дальше модель выбираете вы, а не мы.

Если нужно посмотреть подробную конфигурацию уже работающего радио — quiet-radio читает её и ничего не меняет:

quiet-radio --radio serial:/dev/cu.usbserial-0001 --raw

Порт занимает только одна программа за раз. Если ваш узел terminal ui --mesh serial:... уже запущен, он держит порт, и quiet-radio к нему не подключится. Это нормально: остановите узел на время настройки.

Как отличить заводскую прошивку наверняка

Заводская прошивка Heltec после сброса печатает в порт примерно это:

ESP-ROM:esp32s3-20210327
rst:0x1 (POWERON),boot:0x9 (SPI_FAST_FLASH_BOOT)
select external 32K RTC
ESP32ChipID=08EAFCF61B44

и дальше молчит. Meshtastic вместо этого непрерывно пишет строки вида INFO | ??:??:?? ... и отвечает на запрос конфигурации.

Строка ESP-ROM:esp32s3 заодно говорит, что плата на чипе ESP32-S3, то есть это V3, а не V2 (у V2 обычный ESP32). Для выбора файла прошивки это важно.


Шаг 1. Поставить прошивку Meshtastic

Способ A — нашей командой

terminal radio flash

Что она делает по шагам:

  1. Находит подключённые платы и показывает список — с портом и тем, что на нём удалось определить.
  2. Спрашивает у Meshtastic, какая прошивка сейчас актуальна.
  3. Сужает список вариантов плат по семейству чипа и показывает его. Выбираете вы: можно ввести номер или набрать часть названия для фильтра (heltec → останутся только Heltec).
  4. Читает из релиза рецепт установки именно для этой платы: какие файлы писать и по каким адресам. Ни одного смещения мы не храним у себя — всё берётся из данных релиза, поэтому устареть не может.
  5. Показывает план целиком: плата, версия, файлы, адреса, объём загрузки, и предупреждение, что плата будет стёрта. Пишет только после yes.
  6. Качает нужные файлы (не весь архив на 170 МБ, а только их — через частичные HTTP-запросы) и сверяет каждый с MD5 из релиза. Не сошлось — на плату не пишется ничего.
  7. Прошивает через esptool и потом перечитывает плату: успехом считается только то, что устройство само ответило как узел Meshtastic.

Нужен установленный esptool — команда его не поставит за вас:

pip install esptool

Программа, которая молча скачивает исполняемый файл из интернета и запускает его на вашем железе, приняла решение, которое было вашим.

Способ B — веб-флешер

Если удобнее в браузере (Chrome или Edge):

https://flasher.meshtastic.org

  1. Подключите плату по USB.
  2. Выберите модель: Heltec V3 (для платы на ESP32-S3).
  3. Выберите стабильную версию (Stable).
  4. Нажмите Flash и выберите последовательный порт платы.

⚠️ Прошивка стирает заводскую программу. Вернуть её потом можно — Heltec выкладывает свои демо-прошивки, — но это отдельная операция. Убедитесь, что плата вам нужна именно как узел сети.

Альтернатива без браузера — esptool.py и файлы релиза с https://github.com/meshtastic/firmware/releases.

После прошивки плата перезагрузится, на экранчике появится логотип Meshtastic, а в порт пойдут логи. Проверьте шагом 0 ещё раз — теперь quiet-radio должен ответить.


Шаг 2. Выбрать регион — это решение, а не настройка

Регион определяет, на какой частоте плата выходит в эфир. Это вопрос законодательства вашей страны, а не удобства. Пока регион не выставлен, Meshtastic вообще не передаёт.

terminal radio region

Без имени команда ничего не пишет — она читает плату и показывает, на что та настроена сейчас, плюс список допустимых имён:

/dev/cu.usbserial-0001 says it is set to:
  region        UNSET
  modem preset  LONG_FAST
  hop limit     3

UNSET означает, что плата не передаёт вообще ничего. Чтобы задать:

terminal radio region EU_868

Команда покажет, что именно запишет, предупредит и спросит подтверждение; после перезагрузки платы перечитает её и покажет, что реально легло. Успехом считается только совпадение.

Опционально: --preset LONG_FAST и --hop 3. Без них меняется только регион — то, о чём не просили, не трогается.

Опечатка в имени региона — это ошибка, а не «ноль». EU868 вместо EU_868 было бы записано как UNSET, и плата выглядела бы настроенной, оставаясь немой. Поэтому имя, которого мы не знаем, отвергается со списком допустимых.

Имена регионов, которые понимает сборка:

US        EU_433    EU_868    CN        JP        ANZ       KR
TW        RU        IN        NZ_865    TH        LORA_24   UA_433
UA_868    MY_433    MY_919    SG_923    PH_433    PH_868    PH_915
ANZ_433

Пресеты: LONG_FAST (по умолчанию, дальше всех), LONG_SLOW, VERY_LONG_SLOW, MEDIUM_SLOW, MEDIUM_FAST, SHORT_SLOW, SHORT_FAST, LONG_MODERATE, SHORT_TURBO. Чем «длиннее» пресет, тем больше дальность и тем меньше скорость. Для начала берите LONG_FAST.

Выберите тот, что соответствует месту, где вы находитесь, и диапазону, на который рассчитана ваша плата (на Heltec это обычно написано на самой антенне или в описании товара: 433 МГц или 868 МГц).

Никогда не включайте передачу без антенны. Плата без подключённой антенны может выйти из строя при первой же передаче.


Шаг 3. Создать канал сегмента

«Сегмент» — это ваша группа радиоузлов, которые слышат друг друга. У неё есть свой канал со своим ключом, отдельный от общедоступного.

Запустите узел с подключённым радио:

terminal ui --data ~/.quiet-places --name myname --mesh serial:/dev/cu.usbserial-0001

Откройте интерфейс, зайдите на экран Gateway и нажмите Prepare this device. Узел прочитает радио и выдаст:

  • ссылку и QR-код канала — их надо открыть в приложении Meshtastic на телефоне, спаренном с радио, и выбрать ADD, а не Replace (Replace стёр бы все каналы, которые уже есть на плате);
  • готовые команды для официальной CLI, если удобнее так;
  • профиль сегмента — текстовый файл, см. шаг 4;
  • отпечаток ключа (fingerprint) — короткая строка, по которой можно убедиться, что на другом радио тот же ключ, не показывая сам ключ.

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

Почему мы даём ссылку, а не пишем в радио сами: чтобы получить ключ, его пришлось бы прочитать с платы, а наш читатель конфигурации намеренно хеширует ключи в момент чтения и выбрасывает открытый текст. Мы можем быть источником ключа, но не его извлекателем.

Ту же самую ссылку нужно применить на каждом радио сегмента. Разные ключи — гарантированная тишина.

Если удобнее через командную строку

Экран Prepare выдаёт готовые строки такого вида (N подставится сам — это первый свободный слот канала на вашей плате):

meshtastic --port /dev/cu.usbserial-0001 --ch-add mysegment
meshtastic --port /dev/cu.usbserial-0001 --ch-index N --ch-set psk base64:...
meshtastic --port /dev/cu.usbserial-0001 --ch-index N --ch-set name mysegment

Третья команда не лишняя: официальная CLI стирает имя канала, когда записывает в него ключ. Без неё канал останется безымянным, и два радио разойдутся в том, какой канал считать одним и тем же.

И, если регион с пресетом ещё не выставлены:

meshtastic --port /dev/cu.usbserial-0001 --set lora.region EU_868
meshtastic --port /dev/cu.usbserial-0001 --set lora.modem_preset LONG_FAST --set lora.use_preset true
meshtastic --port /dev/cu.usbserial-0001 --set lora.hop_limit 3

Шаг 4. Сохранить профиль сегмента

Профиль — обычный текстовый файл, который описывает, как должно быть настроено каждое радио сегмента. Ключа в нём нет, только отпечаток, поэтому его можно спокойно передавать и класть в репозиторий.

Выглядит он так:

# Quiet Spaces radio profile — the settings every node on
# this segment must share. Contains no keys: `channel_key` is a
# fingerprint, which identifies a key without revealing it.
name          = mysegment
region        = EU_868
modem_preset  = LONG_FAST
hop_limit     = 3
tx_enabled    = true
channel_index = 1
channel_name  = mysegment
channel_key   = private:9f2a...

Экран Prepare отдаёт его сразу. Если радио уже настроено вручную, профиль можно снять с него:

quiet-radio --radio serial:/dev/cu.usbserial-0001 \
  --channel 1 --save-profile mysegment.profile

--channel указывает, какой именно канал снимать. По умолчанию берётся первичный (индекс 0), а он на большинстве плат — общедоступный канал со стандартным ключом; профиль с него описывал бы не ваш сегмент.


Шаг 5. Проверить каждое радио по профилю

Это и есть та проверка, ради которой всё затевалось: она превращает молчаливое несовпадение в конкретную строку «вот это поле не то».

quiet-radio --radio serial:/dev/cu.usbserial-0001 \
  --profile mysegment.profile

Коды возврата различаются осмысленно:

код значение
0 всё проверенное совпало
1 что-то не совпало — будет названо, какое поле
3 ничего не противоречит, но что-то не удалось проверить (старая прошивка не прислала это поле)
2 не разобрал аргументы или не смог подключиться

Разница между 1 и 3 намеренная: «это радио настроено неправильно» и «это радио мне не рассказало» требуют разных действий. И то, чего узел не сообщил, у нас считается неизвестным, а не «значением по умолчанию» — описывать чужое железо догадкой мы не хотим.


Шаг 6. Запустить узел на этом сегменте

terminal ui \
  --data ~/.quiet-places --name myname \
  --mesh serial:/dev/cu.usbserial-0001 \
  --mesh-channel 1 \
  --radio-profile mysegment.profile

Что делает каждый флаг:

  • --mesh serial:PATH — подключиться к радио по USB. Для радио, доступного по Wi-Fi, вместо этого --mesh tcp:192.168.1.50.
  • --mesh-channel N — на каком канале говорить. Это важно: канал 0 — первичный канал платы, обычно общедоступный. Пакеты на нём видят и ретранслируют все, кто в радиусе (содержимое остаётся зашифрованным нашим собственным слоем, но сам факт обмена виден). Ставьте номер своего канала.
  • --radio-profile FILE — экран Gateway будет сверять радио с профилем и называть любое расхождение. Профиль заодно задаёт номер канала.

Если всё сошлось, узел напечатает:

mesh: channel 1 · connected as node 1234567890 via serial:/dev/cu.usbserial-0001 (raw wire, summaries every 60s — LoRa airtime)

Шаг 7. Проверить, что связь действительно есть

Нужны два узла с двумя радио, настроенными по одному профилю. Оба узла можно запустить на одной машине — по одному радио в каждый USB-порт.

⚠️ Главная ловушка: выключите остальные пути. Два узла на одной машине найдут друг друга по локальной сети за секунду, сообщение долетит мгновенно, и вы решите, что радио работает. Оно при этом может быть даже не подключено. То же самое сделает реле, если оно настроено.

Поэтому в тесте радио: --no-lan на обоих узлах и ни одного реле в настройках (у свежей папки данных его и нет). Тогда единственный оставшийся путь — эфир, и результат означает ровно то, что означает.

Каждому узлу нужно своё: папка данных, имя, порт веб-интерфейса и, конечно, свой последовательный порт. Папка данных заблокирована на один процесс — два узла на одной папке не запустятся, и это правильно.

# первый
terminal ui --passphrase p1 --data /tmp/qp-a --name alice \
  --no-lan --port 8801 --mesh serial:/dev/cu.usbserial-0001 --mesh-channel 1

# второй, в другом терминале
terminal ui --passphrase p2 --data /tmp/qp-b --name bob \
  --no-lan --port 8802 --mesh serial:/dev/cu.usbserial-0002 --mesh-channel 1

Порт второй платы подскажет terminal radio list — он покажет обе.

  1. Создайте пространство на первом узле и пригласите второй.
  2. Напишите сообщение и дождитесь его на втором.
  3. Отключите одно радио и убедитесь, что сообщения перестали доходить. Это половина теста: без неё вы не знаете, что доставляло именно радио.

Про расстояние: разнесите платы на разные комнаты или на улицу. Лежащие рядом радио иногда «оглушают» друг друга — приёмник перегружается передатчиком в десяти сантиметрах, и связь на столе может оказаться хуже, чем через два этажа.

О скорости. LoRa — это единицы килобит в секунду на всех сразу. Текст ходит нормально; фотографии и звук по радио ходить не будут. Наш узел печатает сводку раз в 60 секунд именно потому, что эфир — общий и ограниченный ресурс.


Если ничего не слышно

Идите по списку сверху вниз — он отсортирован по частоте причины.

Признак Скорее всего
no Meshtastic here на плате не Meshtastic — шаг 1
Serial port busy порт держит другой процесс — приложение Meshtastic, второй terminal, монитор порта
Узел подключился, но пакеты не доходят разные ключи канала — сверьте fingerprint профилем (шаг 5)
То же самое, ключи совпадают разный регион или пресет — та же проверка их назовёт
Радио вообще не передаёт регион не выставлен (UNSET) или tx_enabled = false
Пакеты доходят через раз слишком далеко, нет антенны, или маленький hop_limit

Главное правило отладки здесь: тишина не является диагнозом. Правильно настроенное радио, рядом с которым никого нет, выглядит ровно так же, как радио, настроенное на другой регион. Не гадайте — прогоните шаг 5.


Отладка без железа

Всю радиочасть можно отлаживать без единой платы: terminal meshhub поднимает поддельную сеть Meshtastic локально, и узлы подключаются к ней через --mesh tcp:ADDR.