- добавлен ручной workflow Gitea Actions (.gitea/workflows/build-mqtt-firmwares.yml): сборка MQTT-прошивок на сервере и публикация релиза - добавлен posadmesh-tools/publish-gitea-release.sh для выгрузки собранных файлов в релиз Gitea (идемпотентно, фильтр по треку) - README: происхождение проекта переписано (форк EastMesh, доработка энтузиастов из Сергиева Посада, ориентация на meshcoretel.ru), добавлены раздел «Отличия от upstream MeshCore» и журнал «Изменения в проекте» - убраны упоминания Австралии, ссылки на eastmesh.au и региональные материалы; руководство по прошивке переведено на файлы релизов и esptool.py - posadmesh-build.sh: вывод PlatformIO очищается от \r — на Windows групповые команды сборки не находили ни одной цели; companion-команды удалены, добавлены build-mqtt-firmwares и list-mqtt - release-notes.yml: треки repeater-mqtt*, запись 2026.10.0 дополнена удалением companion и исправлением сборки, companion-wifi помечен как снятый с выпуска - AGENTS.md: правило дописывать изменения в README - .gitignore: .pio-home
229 lines
22 KiB
Markdown
229 lines
22 KiB
Markdown
# Собственные команды CLI
|
||
|
||
Эта страница описывает команды CLI, специфичные для PosadMesh, добавленные в этом репозитории.
|
||
|
||
Она не пытается повторять весь набор команд CLI апстримного MeshCore.
|
||
|
||
## С чего начать
|
||
|
||
Если вы выполняете первичную настройку, вот команды, которые нужны большинству пользователей прежде всего:
|
||
|
||
```text
|
||
set wifi.ssid <your-ssid>
|
||
set wifi.pwd <your-password>
|
||
get wifi.status
|
||
set mqtt.iata <code>
|
||
get mqtt.status
|
||
```
|
||
|
||
Для MQTT-репитеров с локальной веб-панелью также полезны:
|
||
|
||
```text
|
||
set web on
|
||
get web.status
|
||
set web off
|
||
```
|
||
|
||
Используйте `set web on` при настройке или диагностике, а затем `set web off`, когда стационарному MQTT-репитеру нужен максимальный запас памяти.
|
||
|
||
## Команды MQTT-репитера
|
||
|
||
Эти команды доступны в таргетах прошивки `*_repeater_mqtt`.
|
||
|
||
Команды `get` без аргументов нужно вводить точно так, как показано.
|
||
|
||
### Статус и маршрутизация MQTT
|
||
|
||
- `get mqtt.status`: показывает состояние Wi-Fi, NTP, IATA, эндпоинта, транспорт пользовательского эндпоинта, состояние публикации статуса, состояние TX и `leaked:<n>` (MQTT-клиенты, намеренно оставленные неосвобождёнными после сбоя целостности heap при завершении; должно оставаться `0`).
|
||
- `get mqtt.statuscfg`: показывает, включены ли периодические сообщения статуса, в виде простого значения `on` или `off`. Большинству пользователей достаточно `get mqtt.status`.
|
||
- `get mqtt.client_version`: показывает строку MQTT `client_version`, публикуемую репитером.
|
||
- `get mqtt.client_env`: показывает окружение PlatformIO, использованное для сборки прошивки репитера.
|
||
- `get mqtt.iata`: показывает код IATA/местоположения, используемый в топиках MQTT.
|
||
- `set mqtt.iata <code>`: задаёт код IATA/местоположения, например `MEL`.
|
||
- `set mqtt.iata UNSET`: помечает MQTT IATA как ещё не настроенный. Пока он `UNSET`, включённые MQTT-брокеры остаются отключёнными, пока не будет сохранён реальный код.
|
||
|
||
### Идентификация MQTT
|
||
|
||
- `get mqtt.owner`: показывает настроенный публичный ключ владельца.
|
||
- `set mqtt.owner <64-hex-char-public-key>`: задаёт публичный ключ владельца, используемый в метаданных JWT.
|
||
- `mqtt.owner <64-hex-char-public-key>`: сокращённая форма для задания публичного ключа владельца.
|
||
- `get mqtt.email`: показывает настроенный email владельца.
|
||
- `set mqtt.email <email>`: задаёт email владельца, используемый в метаданных JWT.
|
||
- `mqtt.email <email>`: сокращённая форма для задания email владельца.
|
||
|
||
### Управление сообщениями MQTT
|
||
|
||
- `get mqtt.packets`: показывает, публикуются ли сообщения с пакетами.
|
||
- `set mqtt.packets on|off`: включает или отключает публикацию пакетов.
|
||
- `get mqtt.raw`: показывает, публикуются ли необработанные payload пакетов.
|
||
- `set mqtt.raw on|off`: включает или отключает отдельный топик MQTT `raw`.
|
||
- `set mqtt.status on|off`: включает или отключает периодическую публикацию статуса MQTT.
|
||
- `get mqtt.tx`: показывает, включаются ли пакеты TX.
|
||
- `set mqtt.tx on|off`: включает или отключает публикацию пакетов TX.
|
||
|
||
### Эндпоинты MQTT
|
||
|
||
- `get mqtt.meshcoretel`
|
||
- `set mqtt.meshcoretel on|off`
|
||
- `get mqtt.custom`
|
||
- `set mqtt.custom on|off`
|
||
- `get mqtt.custom.host`
|
||
- `set mqtt.custom.host <host>`
|
||
- `get mqtt.custom.port`
|
||
- `set mqtt.custom.port <port>`
|
||
- `get mqtt.custom.transport`: показывает `tcp` или `wss`.
|
||
- `set mqtt.custom.transport tcp|wss`
|
||
- `get mqtt.custom.username`
|
||
- `set mqtt.custom.username <username>`
|
||
- `get mqtt.custom.password`: показывает `set`, когда пользовательский пароль настроен.
|
||
- `set mqtt.custom.password <password>`
|
||
|
||
Примечания:
|
||
|
||
- новые установки MQTT-репитеров по умолчанию задают для `mqtt.iata` значение `UNSET`
|
||
- одновременно можно включить максимум два MQTT-брокера
|
||
- если `mqtt.iata` имеет значение `UNSET`, включённые MQTT-брокеры не подключатся
|
||
- пользовательский MQTT использует настроенные имя пользователя и пароль, а не аутентификацию JWT
|
||
- пользовательский MQTT по умолчанию использует TCP; задайте `mqtt.custom.transport wss` для MQTT через защищённые WebSockets с фиксированным путём websocket `/mqtt` и корневым набором сертификатов CA x509 из ESP-IDF
|
||
- `get mqtt.status` выводит `> wifi:<up|down> ntp:<up|wait> iata:<code> meshcoretel:<state> custom:<transport>:<state> status:<on|off> tx:<on|off>`; состояния брокера: `up` (подключён), `conn` (подключение), `wait` (нет Wi-Fi или синхронизации времени), `backoff`, `retry`, `unconfigured`, `invalid iata` или `off`
|
||
- пользовательский MQTT использует те же топики `meshcore/<IATA>/<device>/<leaf>`, что и курируемые брокеры
|
||
- выключение подключённого брокера публикует retained-обновление статуса MQTT с `"status":"offline"` перед отключением клиента
|
||
- изменение `mqtt.iata` относительно настроенного значения также публикует retained offline-статус в старый топик статуса, перезапускает подключённые клиенты брокеров и переподключается по новому пути топика
|
||
|
||
Также принимаются устаревшие алиасы с точками:
|
||
|
||
- `mqtt.meshcoretel.ru`
|
||
|
||
### Настройки Wi-Fi для MQTT-репитеров
|
||
|
||
- `get wifi.status`: показывает SSID, состояние подключения, необработанный код статуса Wi-Fi, IP, канал и уровень сигнала при подключении, а также состояние шлюза (`gw:ok|lost`) и счётчик переподключений сторожевым таймером (`wd:<n>`).
|
||
- `get wifi.ssid`: показывает настроенный SSID Wi-Fi.
|
||
- `set wifi.ssid <ssid>`: задаёт SSID Wi-Fi.
|
||
- `set wifi.pwd <password>`: задаёт пароль Wi-Fi.
|
||
- `get wifi.powersaving`: показывает текущий режим энергосбережения Wi-Fi.
|
||
- `set wifi.powersaving none|min|max`: задаёт режим энергосбережения Wi-Fi.
|
||
- `wifi reconnect`: разрывает текущее соединение и переподключается с полным сканированием каналов. Используйте, когда узел сообщает о подключении, но недоступен по сети.
|
||
|
||
MQTT-репитеры также используют сторожевой таймер связи: пока Wi-Fi сообщает о подключении, узел каждые 30 секунд проверяет свой шлюз через ARP. Если шлюз молчит 3 минуты (например, точка доступа, которая продолжает рассылать beacon после потери проводного аплинка), узел сам принудительно выполняет полное переподключение, увеличивая интервал между попытками вплоть до 48 минут, пока сбой не прекратится. `wd:<n>` в `get wifi.status` считает такие принудительные переподключения с момента загрузки.
|
||
|
||
### Настройки NTP для MQTT-репитеров
|
||
|
||
- `get ntp.server1`: показывает основной NTP-сервер.
|
||
- `get ntp.server2`: показывает дополнительный NTP-сервер.
|
||
- `get ntp.server3`: показывает третий NTP-сервер.
|
||
- `set ntp.server1 <host>`: задаёт основной NTP-сервер и перезапускает синхронизацию времени.
|
||
- `set ntp.server2 <host>`: задаёт дополнительный NTP-сервер и перезапускает синхронизацию времени.
|
||
- `set ntp.server3 <host>`: задаёт третий NTP-сервер и перезапускает синхронизацию времени.
|
||
|
||
Серверы по умолчанию: `au.pool.ntp.org`, `time.google.com` и `time.cloudflare.com`.
|
||
|
||
### Настройки моста ESP-NOW для сборок MQTT ESP-NOW
|
||
|
||
Эти команды доступны в таргетах прошивки `*_repeater_mqtt_espnow`, использующих транспорт моста ESP-NOW.
|
||
|
||
Команды моста предназначены для локального использования моста ESP-NOW между близко расположенными репитерами, работающими на разных радиоконфигурациях MeshCore — например, с разной полосой пропускания и SF. Это не элементы управления MQTT-over-WAN, VPN или интернет-мостом.
|
||
|
||
- `get bridge.channel`: показывает настроенный канал моста ESP-NOW.
|
||
- `set bridge.channel <channel>`: задаёт канал моста ESP-NOW и перезапускает мост. Используйте значение от `1` до `14`.
|
||
- `get bridge.secret`: показывает настроенный секрет моста ESP-NOW.
|
||
- `set bridge.secret <secret>`: задаёт общий секрет моста ESP-NOW и перезапускает мост.
|
||
|
||
После выполнения `set bridge.channel` ожидайте кратковременного разрыва соединения моста и веб-панели, пока радио перезапускается. В текущих сборках MQTT ESP-NOW это может выглядеть как перезагрузка платы.
|
||
|
||
В сборках `*_repeater_mqtt_espnow`, подключённых к Wi-Fi, канал моста ESP-NOW должен совпадать с активным каналом Wi-Fi 2,4 ГГц:
|
||
|
||
1. Выполните `get wifi.status`.
|
||
2. Считайте значение `channel:<n>` из статуса подключённого Wi-Fi.
|
||
3. Выполните `get bridge.channel`.
|
||
4. Если значения различаются, выполните `set bridge.channel <n>`, подставив значение канала Wi-Fi.
|
||
5. Используйте одинаковые `bridge.channel` и `bridge.secret` на каждом узле моста ESP-NOW, которые должны взаимодействовать друг с другом.
|
||
|
||
Пример:
|
||
|
||
```text
|
||
> get wifi.status
|
||
> ssid:EastMesh-IoT status:connected code:3 state:connected ip:192.168.1.50 channel:6 rssi:-61 quality:78% signal:good gw:ok wd:0
|
||
> get bridge.channel
|
||
> 1
|
||
> set bridge.channel 6
|
||
OK
|
||
```
|
||
|
||
### Элементы управления веб-панели
|
||
|
||
- `get web`
|
||
- `get web.status`: показывает, доступна ли локальная HTTPS-панель, а также `heals:<n>` (сколько раз панель перезапускалась из-за слишком сильной фрагментации внутреннего heap для TLS-рукопожатия) и `deferred:<n>` (попытки запуска, отложенные до восстановления запаса heap).
|
||
- `get web.stats.status`: показывает, включены ли выделенная страница статистики и подсистема истории, активна ли последняя история, доступна ли история в PSRAM и смонтирован ли архив на SD. Когда это включено, сбор истории теперь охватывает и поддерживаемую телеметрию окружающей среды, а не только исходные серии по батарее и радио. Платы с активным GPS также записывают поминутные выборки по спутникам для исторического вида `/stats`. Если доступ к архиву пропадает, пока статистика остаётся включённой, репитер периодически повторяет монтирование SD.
|
||
- При загрузке восстановление статистики из архива использует ограниченное чтение последней сводки, событий и снимков соседей, чтобы повреждённые или неожиданно большие файлы архива не задерживали запуск MQTT или веб-панели.
|
||
- `set web on|off`
|
||
- `set.web on|off`: включает или отключает локальную HTTPS-панель.
|
||
- `set web.stats on|off`
|
||
- `set.web.stats on|off`: включает или отключает выделенную страницу `/stats` и сбор исторической статистики.
|
||
- `purge sd`: удаляет файлы и каталоги из смонтированного архива на SD-карте, затем заново создаёт пустой каталог архива `/stats`, чтобы сбор статистики во время работы мог продолжаться. Это не стирает внутреннюю файловую систему репитера или сохранённые настройки.
|
||
|
||
### Диагностика во время работы
|
||
|
||
- `memory`: показывает текущее использование heap и PSRAM.
|
||
- `stats-core`: показывает батарею, время работы, счётчик неустранимых ошибок и глубину очереди исходящих.
|
||
- `stats-radio`: показывает уровень шума радио, последний RSSI, последний SNR и время в эфире TX/RX.
|
||
- `stats-packets`: показывает суммарные значения приёма/передачи пакетов, разбивку flood/direct и ошибки приёма.
|
||
|
||
> Если `noise_floor` показывает `0`, проверьте `get agc.reset.interval`; если значение не `0`, попробуйте `set agc.reset.interval 0` и проверьте снова.
|
||
|
||
### Лимит пересылки flood
|
||
|
||
- `get flood.max.unscoped`: показывает лимит хопов для неограниченных flood-пакетов.
|
||
- `set flood.max.unscoped <0-64>`: задаёт лимит хопов для неограниченных flood-пакетов.
|
||
- `get flood.max.advert`: показывает лимит хопов для flood-пакетов advert.
|
||
- `set flood.max.advert <0-64>`: задаёт лимит хопов для flood-пакетов advert.
|
||
|
||
В сборках MQTT-репитеров `flood.max.unscoped` по умолчанию равен `64`. Меньшие значения могут ограничить, как далеко повторяется неограниченный flood-трафик, тогда как пересылка scoped/region flood остаётся под управлением `flood.max`.
|
||
|
||
### Отчётность о батарее платы
|
||
|
||
- В сборках MQTT-репитеров фоновый опрос батареи, используемый для истории MQTT/статуса, ограничен примерно одним разом в минуту. Явные запросы статуса и телеметрии по-прежнему обновляют показание сразу.
|
||
|
||
### Управление вентилятором T-Beam 1W
|
||
|
||
Эти команды доступны только в сборках репитера `LilyGo_TBeam_1W_*`.
|
||
|
||
- `get fan`: показывает текущий режим вентилятора, текущее состояние вентилятора и последнюю температуру платы по NTC, когда она доступна.
|
||
- `set fan auto`: возвращает вентилятор к автоматическому управлению и сохраняет этот режим после перезагрузки.
|
||
- `set fan on`: принудительно включает вентилятор и сохраняет этот режим после перезагрузки.
|
||
- `set fan off`: принудительно выключает вентилятор и сохраняет этот режим после перезагрузки.
|
||
- `set fan timeout <Ns>`: изменяет автоматическое окно удержания после TX в секундах и сохраняет его после перезагрузки, например `set fan timeout 45s`.
|
||
|
||
Поведение автоматического режима:
|
||
|
||
- принудительно включает вентилятор во время TX и оставляет его включённым на настроенный таймаут после этого
|
||
- в остальных случаях включает вентилятор при `48C`
|
||
- выключает его обратно при `42C`
|
||
- оставляет вентилятор включённым, если показание NTC недоступно
|
||
|
||
Примечания:
|
||
|
||
- режим вентилятора репитера по умолчанию — `auto`
|
||
- таймаут после TX по умолчанию — `30s`
|
||
- режим вентилятора и таймаут хранятся в prefs репитера и сохраняются после перезагрузки
|
||
- только сборки репитера `LilyGo_TBeam_1W_*` используют эти сохраняемые настройки вентилятора
|
||
- допустимый диапазон — от `0s` до `600s`
|
||
|
||
## Доступ к CLI через веб-панель
|
||
|
||
Когда веб-панель репитера включена и вы прошли аутентификацию, панель CLI в браузере может выполнять те же команды CLI, которые принимает репитер.
|
||
|
||
Примечания:
|
||
|
||
- панель по-прежнему использует для доступа пароль администратора репитера
|
||
- команды выполняются с той же осторожностью, как если бы вы вводили их напрямую в CLI репитера
|
||
- это предназначено для локального административного использования в доверенной сети
|
||
- `start ota` освобождает локальный слушатель HTTP-редиректа на порту `80`, чтобы слушатель OTA HTTP мог занять его, не останавливая остальные службы репитера, независимо от того, выполнена ли команда из веб-панели, последовательного CLI или удалённого сеанса CLI
|
||
- если старый слушатель редиректа не освободил порт `80` полностью, слушатель OTA повторяет попытки примерно до 30 секунд, после чего сдаётся
|
||
- кнопка `Purge SD` в веб-интерфейсе выполняет `purge sd` после подтверждения в браузере
|
||
- `start ota` использует существующий Wi-Fi-адрес репитера, если он уже подключён, или запускает точку доступа `MeshCore-OTA`, если Wi-Fi не подключён
|
||
- ярлык Regions в `/app` последовательно выполняет команды регионов MeshCore: `region put` и `region allowf` для базового региона и вложенного, затем `region save`
|
||
|
||
## Скрипт проверки состояния heap
|
||
|
||
`posadmesh-tools/web-heap-check.sh <host> [--stress] [--rounds N]` читает `memory`, `get web.status`, `get mqtt.status` и `get wifi.status` через HTTPS API, а с флагом `--stress` имитирует всплески загрузки страниц браузером перед повторным чтением `memory`. Аутентифицируйтесь с помощью `REPEATER_PASSWORD` или `REPEATER_TOKEN` в окружении (или введите пароль по запросу). Следите за `heap_max` (наибольший внутренний блок; для TLS нужно ~40KB), `heap_min` и счётчиками `heals`/`deferred`/`leaked`.
|