PunchBruno Fernandes’ home burgled while in Italy for Como matchEl ComercioMaría Corina Machado redobla la presión en Venezuela: protestas, elecciones, presos políticos y su regreso al paísInquirerClasses suspended in Pagudpud due to Typhoon RosalRTP DesportoI Liga: Jornada abre em GuimarãesDaily MaverickClaude Monet’s ‘Iris’ becomes most expensive artwork sold at auction in France, Sotheby’s saysBollywood HungamaNo football, no gym, no restaurants? Tiger Shroff shooting raises a FRIGHTENING question: Are Bollywood stars becoming PRISONERS of their own fame?ZDF heuteEntdecken Sie das ZDF-NachrichtenstudioRapplerRain eases in Batanes as Typhoon Rosal starts moving awayThe Jerusalem PostIsrael’s election is being cast as a historic showdown - but four trends tell a different storyVanguard2027: Adeleke backs Tinubu; maintains support for Accord legislative candidatesESPNCaleb Williams, Bears find just enough to hold off PatsRai NewsTG3 Fuori TG del 23/10/2026
The Daily Newsstand · Free, Always
Friday, October 23, 2026

Голос по LoRa: как плата для Meshtastic превращается в рацию без интернета

Translate
Шапка MeshTRX

Шапка MeshTRX

LoRa придумывали для датчиков: раз в несколько минут отправить десяток байт на пару километров и прожить на батарейке год. Говорить через неё голосом считается невозможным — канал слишком узкий. Мы проверили, насколько это «невозможно», и получился MeshTRX: бесплатная прошивка для недорогих плат Heltec WiFi LoRa 32 (тех же, что берут под Meshtastic), приложение для телефона и рация, которая работает там, где нет ни интернета, ни сотовой связи. Нажал кнопку — говоришь, отпустил — слушаешь.

Меня зовут Станислав (R7KIQ), я автор проекта. Ниже — как это устроено внутри: сколько байт уходит на 20 миллисекунд речи, почему голос не ходит через mesh‑сеть так же, как текст, во что обходится шифрование в пакете на 39 байт, какие ошибки нашлись только в поле — и сколько километров получается на самом деле, а не на бумаге.

Исходники: github.com/StanislavButkovsky/meshtrx. Сайт с прошивкой из браузера и документацией: meshtrx.ru.

Что это и из чего состоит

  • Плата. Heltec WiFi LoRa 32 V3, V4 (ревизия 4.2) или V4.3: ESP32-S3 + радиочип Semtech SX1262, диапазон 863–870 МГц. Никакой доработки, нужна только антенна на 868 МГц.

  • Прошивка. Ставится за минуту прямо из Chrome через Web Serial: meshtrx.ru/flash. Не понравится — плата так же за минуту прошивается обратно в Meshtastic, железо то же самое.

  • Приложение. Android (с сайта; в RuStore — на модерации), iPhone и настольный клиент на Python. Телефон подключается к плате по Bluetooth LE и служит экраном, микрофоном и динамиком.

  • Связь. Платы говорят друг с другом напрямую или через ретранслятор. Ретранслятором становится любая плата одной настройкой.

Кроме голоса: текстовые сообщения с отметками доставки, фото и файлы, карта и радар с позициями участников, вызов «всех» или одного абонента, шифрование эфира по кодовому слову группы, 23 канала с поиском самого тихого.

Главный экран приложения

Главный экран приложения

Почему голос по LoRa считается невозможным

Параметры радио в MeshTRX: SF7, полоса 250 кГц, избыточность 4/7. На бумаге это около 7,8 кбит/с — без учёта преамбулы, заголовков и пауз, так что на деле заметно меньше.

Для сравнения: голос в GSM — 13 кбит/с, самый скромный интернет‑звонок — 8–16 кбит/с. Привычные способы передать речь в такой канал не «работают плохо» — они в него просто не помещаются.

Codec2: голос как описание, а не как звук

Выход нашёлся в Codec2 Дэвида Роу. Это не обычный кодек, а вокодер: он не хранит звуковую волну совсем. В эфир уходит описание того, как была устроена речь в этот момент — основной тон, энергия, форма спектра, — а на другом конце речь синтезируется заново.

Режим 3200 — 3200 бит в секунду. Кадр — 20 мс звука, 160 отсчётов при 8 кГц, и он укладывается в 8 байт. Кодирование идёт на телефоне: приложение пишет микрофон, сжимает речь и отдаёт рации уже готовые кадры по Bluetooth. Прошивка и все клиенты используют один и тот же режим.

Что лежит в пакете

Каждые 80 мс уходит один пакет: четыре кадра Codec2 подряд — 32 байта — и 7 байт заголовка.

Устройство голосового пакета

Устройство голосового пакета

Байт

Поле

Зачем

0

type

аудио, текст, файл, служебное

1

channel

номер канала 0–22; старший бит — «нагрузка зашифрована»

2

seq

порядковый номер

3

flags

начало и конец передачи, голосовая активация

4

ttl

сколько ещё пересылок разрешено

5–6

sender

последние два байта MAC — кто говорит

На SF7/250 кГц/4/7 такой пакет висит в эфире 53,4 мс. Пакеты идут каждые 80 мс, значит, пока человек говорит, канал занят на две трети. Это ключевое число: оно объясняет почти все решения дальше.

Почему голос не ходит по mesh‑сети

Текстовое сообщение — это один пакет. Ему нужно одно удачное окно в эфире: не дошло — приложение повторит через несколько секунд, и человек этого даже не заметит.

Голос так не умеет. Двенадцать пакетов в секунду, и каждый должен успеть вовремя: повтор, пришедший через полсекунды, уже бесполезен. А при занятости канала 67% ретранслятору просто некогда повторять: пока он передаёт копию, исходная рация уже шлёт следующий пакет.

Поэтому в MeshTRX голос идёт напрямую или через ретранслятор, а не через произвольную сеть из многих узлов, как текст в Meshtastic. TTL у пакета — 2. От зацикливания защищает память ретранслятора: он помнит, что уже переслал (кольцевой кеш на 128 записей; отправитель + номер + тип), и дубль отбрасывает.

На этом мы и споткнулись. Номер голосового пакета — один байт, и сначала он сбрасывался в ноль на каждом нажатии кнопки: «приёмник видит ноль — значит, новая фраза». А ретранслятор помнил пересланное тридцать секунд. Вторая фраза через пять секунд приходила с теми же номерами от того же отправителя — и отбрасывалась целиком как дубль. На стенде это было однозначно: первая фраза — 10 пакетов из 10, вторая — 0 из 10, четвёртая через 40 секунд — снова 10 из 10. В поле это звучало как «через ретранслятор голос доходит через раз».

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

Радар: станции вокруг и ретранслятор

Радар: станции вокруг и ретранслятор

Шифрование в 39 байтах

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

Пакет

Время в эфире

Занято канала

без шифрования, 39 байт

53,4 мс

67%

+ подпись 4 байта

57,0 мс

71%

+ подпись 8 байт

60,5 мс

76%

+ полная подпись 16 байт

71,3 мс

89%

+ публичный ключ 32 байта

85,6 мс

107%

Последняя строка — не опечатка: пакет с публичным ключом X25519 в канал не помещается, передача не успевает закончиться до начала следующей. Поэтому обмена ключами в каждом пакете нет и не будет.

Что получилось:

  • Общий ключ группы из кодового слова. На всех рациях вводится одна и та же фраза, из неё выводится 256-битный ключ (PBKDF2-SHA256, 50 000 итераций — около трёх секунд на ESP32-S3, это защита от перебора). Фраза в телефоне не хранится и в эфир не уходит.

  • Шифр — AES-256 в режиме CTR, длина шифротекста равна длине открытого текста. Заголовок остаётся открытым: по нему ретранслятор делает дедупликацию и TTL, не зная ключа.

  • Подпись — AES‑CMAC, укороченная до 6 байт, плюс 2 байта эпохи. Итого +8 байт к пакету. Округление символов LoRa таково, что шесть байт подписи стоят не дороже четырёх.

  • Отпечаток ключа — четыре символа, по которым группа сверяет ключ вслух, не диктуя само слово. Если рядом говорят чужим ключом, приложение это показывает.

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

23 канала и соседи по диапазону

На 868 МГц живёт много кто: домофоны, метеостанции, счётчики, автосигнализации. В городе это заметный и неравномерный фон. Рация умеет пройти по всем 23 каналам (863,15–869,75 МГц с шагом 300 кГц) и померить шум. Уровень берётся как максимум серии, а не среднее: помеха бьёт вспышками, и по среднему канал выглядит тихим, хотя раз в секунду в нём проезжает чужой пакет — ровно то, что убивает голос. Первый же замер на столе показал 15 дБ между самым тихим и самым шумным каналом.

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

Настройки: канал, поиск свободного, ключ группы

Настройки: канал, поиск свободного, ключ группы

Сообщение дойдёт, даже если телефон выключен

У телефона садится батарея, человек закрыл приложение — а рация на поясе продолжает работать. Если адресат без телефона, его рация принимает сообщение и складывает в память: кольцевой буфер на 8 КБ, а на платах с PSRAM — на 128 КБ. Когда места не хватает, выбрасываются самые старые. Отправитель видит отметку «принято нодой», а когда адресат подключит телефон, сообщение придёт с пометкой, сколько оно пролежало.

Попутно пришлось перестать врать про доставку. Раньше подтверждение терялось на обратном пути, и у отправителя стоял крестик «не доставлено» на сообщении, которое давно прочитали. Теперь у сообщения честные состояния: отправлено, принято нодой, доставлено.

Чат с отметкой «принято нодой»

Чат с отметкой «принято нодой»

Сколько километров на самом деле

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

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

Ошибки, которые нашлись только в поле

Самая дорогая находка — внешний усилитель на одной из ревизий платы. Приём работал, передача работала, связь была, только дальность — хуже ожидаемой. Оказалось, нога, которая переключает усилитель между передачей и приёмом, стояла не в том состоянии, и сигнал шёл мимо него. Уровень у соседней рации: −78 дБм до правки и −20 дБм после, разница 58 дБ. Ничего не падало и не ругалось — просто «работает» и «работает как задумано» оказались разными вещами. Отсюда же в мастере прошивки обязательный выбор ревизии платы: у V4 rev 4.2 и V4.3 разные усилители и разные выводы управления.

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

Как это проверяется

Две реальные платы на столе подключены к компьютеру, а вместо телефона — эмулятор протокола Bluetooth на Python. Он гоняет сценарии: голос туда и обратно, сообщения при «выключенном» телефоне, смену канала, ретранслятор. В прошивке для стенда есть тестовая консоль, через которую видно, что рация приняла, переслала и отбросила. Многие таблицы из этой статьи сняты именно так.

Стек: прошивка — PlatformIO + Arduino для ESP32-S3, RadioLib для SX1262, NimBLE‑Arduino для Bluetooth, Codec2, mbedTLS. Android — Kotlin, iOS — SwiftUI, настольный клиент — Python.

Попробовать и поучаствовать

Понадобятся две платы Heltec WiFi LoRa 32 (V3, V4 или V4.3) с антеннами на 868 МГц и два телефона. Прошивка — meshtrx.ru/flash, приложение — meshtrx.ru/download. Помните, что 863–870 МГц — диапазон для маломощных устройств, и правила его использования в разных странах свои.

Проект некоммерческий, исходники открыты под лицензией CC BY‑NC 4.0: свободно для некоммерческого использования с указанием авторства. Больше всего проекту помогают замеры дальности, отчёты об ошибках и фото ваших сборок — антенн, корпусов, ретрансляторов на крышах.

73! Станислав, R7KIQ

Meshtastic® — зарегистрированный товарный знак его владельцев; MeshTRX с проектом Meshtastic не связан.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.