Skip to content

Repository files navigation

MeshDesk

Локален Linux клиент за Meshtastic с графичен интерфейс в браузъра. Важната разлика спрямо client.meshtastic.org е, че браузърът не комуникира директно с радиото:

  • backend процесът използва нативния Meshtastic TCP протокол на порт 4403;
  • Bluetooth LE се обслужва от Linux BlueZ през системния D-Bus;
  • USB Serial се обслужва директно през избрано /dev устройство;
  • UI е достъпен само локално на http://127.0.0.1:8765;
  • няма CORS, mixed-content или Linux Web Bluetooth зависимост.

Поддържа TCP/Wi-Fi, BLE и USB Serial свързване, BlueZ PIN сдвояване, discovery, node database, входящи пакети, broadcast/direct текстови съобщения, именуван избор на канал, ACK/NAK статус и редактиране на radio/module конфигурацията.

Документация и план

Проектната документация е отделена от краткото ръководство:

В „Конфигурация → Device“ има контекстен Role Advisor, който се отваря само при поискване от полето за role. Поясненията са информационни и не променят автоматично радиото. Бъдещите профили и масови операции ще минават през преглед на плана, snapshot, canary изпълнение, проверка и отчет.

Най-бързо стартиране с Devbox

Devbox изолира Python и uv; не инсталира Python пакети в системата.

devbox run setup
devbox run start

Отвори http://127.0.0.1:8765. За наличното Wi-Fi устройство стойностите вече са попълнени:

  • IP: 172.16.19.176
  • порт: 4403

При Bluetooth първо прекъсни други клиенти (телефон/web client), включи Bluetooth на радиото и:

  1. избери таба Bluetooth LE и натисни Сканирай;
  2. избери устройството и натисни Сдвои;
  3. MeshDesk веднага отваря PIN прозорец; когато радиото покаже random PIN (или използва fixed PIN), въведи го в този прозорец;
  4. след успешното сдвояване натисни Свържи.

TCP, BLE и USB Serial endpoint-ите могат да се запазят като именувани профили в картата Връзка. Те се пазят локално в logs/connection-profiles.json и не съдържат PIN, PSK или криптографски ключове. Ръчна промяна на избран профил се показва като незаписана, преди да бъде презаписан. След успешния handshake профилът се свързва с потвърдения Meshtastic node ID. Ако същият endpoint отговори като друго радио, MeshDesk показва identity mismatch и изисква изричен rebind.

Всеки запазен профил има отделен opt-in за Автоматично повторно свързване. При временна BLE/TCP грешка MeshDesk опитва отново с backoff 5 → 10 → 20 → 40 → 60 s, след което остава на максимум един опит в минута. Това е подходящо за BLE възли с power-save: клиентът изчаква нова реклама, вместо да обяви устройството за окончателно изгубено. Countdown, номерът на опита и причината се виждат в Connection health. Ръчно Прекъсни, смяна на endpoint, pairing проблем или различен Meshtastic node ID спират loop-а.

В таба USB Serial бутонът Открий USB показва Meshtastic-compatible портовете, USB идентификатори и дали процесът има read/write достъп. Когато Linux предоставя /dev/serial/by-id/..., MeshDesk предпочита този стабилен път пред /dev/ttyACM0/ttyUSB0, за да не се смени endpoint-ът след reboot. Подробности: USB Serial connection.

В TCP таба бутонът Открий търси _meshtastic._tcp.local. услуги в локалната мрежа. Избраният резултат само попълва host и port; свързването и записването като профил остават изрични действия. Discovery използва изолираната Python зависимост zeroconf и не изисква системни Avahi пакети. Резултатите показват IP, hostname, port, node ID, short name, platform и наличен MAC. Long name се добавя след handshake или от вече потвърден профил, защото обикновено не се публикува чрез mDNS.

Connection bar показва transport health и продължителност на сесията. Сгъваемите подробности разграничават ръчно прекъсване, загубена връзка, timeout, отказан TCP endpoint, липсващо BLE устройство и pairing проблем. Последната protocol активност и последният RX пакет се показват отделно; тиха mesh мрежа не се счита автоматично за повредена връзка.

Картата Администрация показва firmware, hardware, role и публикуваните от радиото DeviceMetadata capabilities. За локалното радио данните идват от handshake-а. За remote-admin възел бутонът Провери възможностите изпраща отделна PKI admin заявка. MeshDesk блокира операция само когато metadata изрично доказва, че тя не се поддържа (например software shutdown или изключен firmware module). Липсващ capability flag се показва като unknown и не се превръща в измислена firmware несъвместимост. Конфигурационните секции имат същите supported/unsupported/unknown обозначения. Подробности: Capability preflight. Категоричният PKI/admin отказ се показва в картата с точния error code и време на проверката. NO_ROUTE, timeout и временна transport грешка се означават отделно като недостъпност, а не като липса на административни права.

Ако BlueZ пази старо/невалидно сдвояване и връзката продължава да изтича по timeout, отметни Забрави старото сдвояване и сдвои отново. Това премахва само локалния Bluetooth bond за избраното устройство.

Каналите на свързаното радио се зареждат автоматично като разговори. За лично съобщение натисни + в списъка с разговори или Пиши до конкретен възел; може и ръчно да въведеш ID във формат !1234abcd. Чатът показва входящи и изходящи балончета и отделни състояния в радио опашката, предадено на радиото, ↗ Relay (чуто препредаване), ✓ Доставено (destination ACK), NAK и timeout. При channel broadcast implicit ACK означава само чуто препредаване; не се представя като доказана gateway, MQTT или web-client доставка. Непрочетените съобщения се броят отделно за всеки канал или личен разговор. Enter изпраща, а Shift+Enter добавя нов ред. Историята на съобщенията, статусите и diagnostic заявките се пази криптирано в logs/ и се разделя по node ID на локалното gateway радио. Така едно и също радио има обща история през TCP, BLE и USB, но различни радиа не смесват разговорите си. При свързване MeshDesk буферира и пакетите, които firmware-ът връща още по време на първоначалния handshake, и автоматично изпраща CLIENT_HISTORY заявка към локалния Store & Forward модул. Бутонът Синхронизирай повтаря заявката ръчно. Възстановените съобщения са означени с ↻ от радиото. Това изисква firmware и Store & Forward конфигурация, които поддържат history replay; локалният MeshDesk лог не може сам да възстанови пакет, който никой node не е съхранил. Суровите събития остават в сгъваемия панел Диагностика.

Табът Настройки → Primary и Secondary канали показва всички slots, включително disabled. От нея могат да се добавят, редактират и премахват Secondary канали, да се промени името, MQTT uplink/downlink и position precision, както и да се запази или замени PSK. Ключът е скрит по подразбиране, но може да бъде показан и копиран чрез explicit no-store reveal за избрания зареден target. Не се записва в browser storage, plaintext audit events или chat history. Преди всеки реален write MeshDesk показва backend-валидирания diff и изисква отделно потвърждение. След него, но преди промяната, всички channel protobuf-и и PSK bytes се запазват в AES-GCM криптиран snapshot под logs/. Slot 0 остава PRIMARY, а нов Secondary се добавя само в първия свободен slot. Position privacy се избира с човешки presets (без позиция, приблизителна зона или пълна GPS точност); Advanced режимът запазва достъп до всички protocol стойности 0–32. Preview diff-ът показва едновременно bits и приблизителната зона. Подробности: Channel Manager.

При прекъсване на връзката device-bound изгледите за разговори, канали, конфигурация и администрация се изчистват, без да се трие криптираната история. При следващо свързване към същото радио историята се зарежда отново.

Полето i до настройка или административно действие показва кратка контекстна помощ при hover, click или keyboard focus. Обясненията покриват предназначение, единици, връзка с хардуера и риск от загуба на достъп. Критичните предупреждения остават постоянно видими, а непознати полета от по-нов firmware получават безопасен type-aware fallback. Всяко scalar поле получава автоматично protobuf тип, protocol default, типов домейн и консервативна препоръка. За параметрите с потвърдени Meshtastic ограничения се показват отделно firmware default, min/max, единица и практическа препоръка. Така protobuf 0 не се представя погрешно като реалния role-aware firmware default. Непозната стойност от по-нов firmware се запазва като избор, вместо формата тихо да я замени.

Картата Мрежа поддържа търсене, филтриране по direct/mesh/MQTT и сортиране по активност, име, сигнал, хопове или батерия. Подробности отваря страничен Node Inspector с пълния NodeDB запис, telemetry, позиция, radio маршрут и следните действия:

  • traceroute с маршрут и SNR за всеки върнат хоп;
  • device, environment, air-quality, power, local-stats, host и PAX telemetry;
  • заявка за позиция;
  • User Info и Neighbor Info заявки;
  • добавяне/премахване от любими и игнориране на възел — директно от картата или от Node Inspector;
  • директно отваряне на личен разговор.

За да се пази LoRa airtime, MeshDesk прилага същите основни ограничения като актуалния Android клиент: traceroute има общ 30-секунден cooldown за всички възли, а Neighbor Info — 180 секунди за конкретния възел. Бутонът показва оставащото време и backend-ът също отказва преждевременна повторна заявка с 429/Retry-After. Това умишлено не блокира chat или различен вид telemetry заявка. Ако firmware TX опашката е пълна, съобщението остава видимо като в радио опашката, докато meshtastic-python получи свободен slot.

Neighbor Info резултатът има специализиран изглед: отчитащ възел, LoRa relay marker, broadcast interval, radio метрики на отговора и таблица на директно чуваните съседи с node име/ID и SNR. Колони като per-neighbor last RX и interval се показват само ако реално присъстват — firmware умишлено не ги изпраща през LoRa. Липсващ optional SNR е , а не измерена нула. Пълният protobuf packet е достъпен само в сгъваемото Raw Neighbor Info packet.

Telemetry и position резултатите се форматират в операторски метрики: battery percent, V/A, channel utilization и airtime в %, SNR/RSSI в dB/dBm, разстояния и височини в mm/m, GPS координати, DOP, timestamps, packet counters и memory в четими единици. Meshtastic sentinel стойност над 100 за battery level се показва като ⚡ външно захранване, а не като невъзможен процент; тя не се интерпретира като доказателство за charging. CamelCase/snake_case, encoded latitude_i и derived latitude, както и вложеният raw слой се обединяват само по известни protobuf aliases. Пълният оригинален payload остава в сгъваемия Raw панел. Raw field path остава като ненатрапчив вторичен ред. Traceroute показва краткото име върху hop-а, node ID под него и пълното име в tooltip, за да остане четим и при имена с emoji.

В Node Inspector може да се избере чия NodeDB се променя: на локалното gateway радио или на разрешен remote-admin node. Remote операцията изисква PKI достъп и MeshDesk изчаква ACK/NAK, преди да я отчете като успешна. Локалните флагове не описват NodeDB на избраното remote радио, затова при Remote избор текущото състояние е означено като неизвестно и са налични отделни Добави, Премахни, Игнорирай и Спри действия. ACK означава „командата е приета“, а не read-back потвърждение; подробният резултат остава непроверено. При stale admin session MeshDesk подновява ключа и повтаря обратимата команда веднъж. Собственият node е означен отделно и няма favorite/ignore действия. Виж Remote NodeDB favorite/ignore.

До всяко чат съобщение има ненатрапчив бутон Детайли. Packet Inspector показва from/to, channel, packet/request/reply ID, RSSI/SNR на последния радио линк, hop_start, оставащ hop limit, общ брой хопове, MQTT флаг, relay, priority и encryption данни. За изходящо съобщение показва и evidence-first верига локално радио → mesh потвърждение → gateway/MQTT → downstream клиент. Ненаблюдаваните етапи са неизвестни, а не автоматично успешни или неуспешни. Пълният raw пакет е сгънат по подразбиране. Виж Delivery and gateway diagnostics.

В сгъваемата Диагностика → Наблюдатели на маршрута има ръчна read-only проверка само на TCP профили, които операторът изрично е маркирал като диагностични наблюдатели. Обикновените, откритите и старите профили не се включват автоматично. Всеки probe работи в изолиран subprocess, за да не смесва глобалния meshtastic-python event bus с историята на активното радио. Матрицата показва verified identity, firmware/role, UDP/MQTT състояние, region/modem съвместимост, channel name+PSK match и кога наблюдателят последно е видял активното радио. Това доказва NodeDB наблюдение, но не и пътя на конкретен packet. PSK bytes и временните comparison signatures не се връщат към браузъра. Проверката не изпраща LoRa packet и не записва конфигурация; тя може временно да стане receive client на TCP наблюдателя.

От същата секция може да се стартира bounded Packet observer за 1, 2 или 5 минути. След identity handshake MeshDesk изчаква началният TCP backlog да се оттече и показва ready; едва тогава packet ID наблюденията се използват като delivery evidence. Събират се само metadata за пакети от активното радио — без текстов payload. Точният observer и via_mqtt evidence се виждат ненатрапчиво в чата и в Packet Inspector. Избирането на профил не стартира постоянна връзка: активният bounded прозорец се вижда до composer-а като ◎ N/N · seconds. Inspector различава липсваща, синхронизираща, изтекла и активна-but-not-seen сесия. Потвърдените sightings се пазят в криптираната device history.

Конфигурационният модул е сгънат по подразбиране. Най-отгоре има отделна секция Потребител / име за дълго име, кратко име, радиолюбителски лиценз и unmessagable флага; след нея са radio и module protobuf секциите. Формулярът записва само действително променените полета. Има безопасен JSON Export/Import, който умишлено не включва пароли, fixed PIN, private keys, public/admin keys и други bytes полета.

Remote administration

От Подробности → Remote admin може да се избере remote node и да се заяви отделна конфигурационна секция. Заявката използва PKI-encrypted Meshtastic admin packet. Публичният ключ на локалното gateway радио трябва предварително да е добавен в security.admin_key на remote устройството. След зареждане секцията се редактира и записва от същия Configuration формуляр. По една секция на заявка е умишлено — пълното изтегляне през LoRa е бавно и натоварва mesh-а.

Същият target selector е наличен в Primary и Secondary канали. Remote slots се зареждат само след Зареди през LoRa (до осем последователни admin заявки). Записът има target-bound preview, encrypted snapshot за remote node-а, последователен ACK/NAK/timeout резултат и повторно прочитане на засегнатите slots. Промяна на PRIMARY име/PSK може да прекъсне последващия remote достъп.

Remote admin не е отделен chat transport. Direct и channel съобщенията продължават да минават през локалното TCP/BLE/USB gateway радио и споделените канали, независимо дали изпращачът има admin права.

Сгъваемият панел Администрация предоставя reboot, shutdown, NodeDB reset, configuration reset и full factory reset както за локалното радио, така и за PKI-разрешен remote node. Опасните reset операции изискват текстово потвърждение. При локален NodeDB reset може да се запазят favorite/ignore флаговете; MeshDesk ги snapshot-ва и прилага отново. Това не е достъпно за remote NodeDB, защото стандартният admin протокол не позволява предварително изтегляне на целия чужд NodeDB.

Криптирана история

При първия запис MeshDesk генерира 256-bit AES-GCM master key в logs/.history.key с права 0600. Всеки event се криптира отделно и използва device profile ID като authenticated context. logs/ е изключена от Git.

За production може ключът да бъде подаден отвън като 32-byte hex или URL-safe base64:

export MESHDESK_HISTORY_KEY='64-hex-characters'
devbox run start

Ключът на Meshtastic устройството не се използва за локалните файлове: ако историята се криптира с неговия public key, само firmware-ът с private key би могъл да я отвори, а MeshDesk не би могъл да я зареди след рестарт.

Стартиране с Docker

docker compose up --build

Compose използва host networking за директен достъп до 172.16.19.176 и монтира read/write системния D-Bus socket за BlueZ. ./logs се монтира в контейнера, за да не се губи криптираната история. На AppArmor системи е зададено apparmor=unconfined, защото стандартният Docker профил блокира BlueZ AddMatch заявките. Контейнерът е изграден само от файловете в този проект, но Devbox вариантът остава по-ограниченият и препоръчителен начин за Bluetooth.

USB устройствата не се предоставят автоматично на контейнера. Добави само конкретното радио чрез локален compose.override.yaml, например:

services:
  meshdesk:
    devices:
      - /dev/ttyACM0:/dev/meshtastic0

В контейнера избери /dev/meshtastic0. Не е необходимо да се монтира цялата host /dev директория.

Спиране:

docker compose down

Проверка

devbox run check

Интерактивната API документация е на http://127.0.0.1:8765/docs.

Диагностика

Проверка на нативния Meshtastic TCP порт без допълнителни пакети:

timeout 3 bash -c '</dev/tcp/172.16.19.176/4403' && echo open

Bluetooth изисква активна системна услуга и свободно радио:

systemctl is-active bluetooth
bluetoothctl show

USB Serial диагностика:

ls -l /dev/serial/by-id /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
id

Meshtastic устройствата обикновено приемат само една активна клиентска връзка. Затвори Android приложението или друг клиент, ако MeshDesk не може да се свърже.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages