Skip to content

Rusik636/MeshtacticTelegramBot_MQTT

Repository files navigation

Meshtastic MQTT Telegram Bot

Добро пожаловать! Этот проект позволяет получать сообщения от вашей Meshtastic ноды через MQTT брокер и автоматически отправлять их в Telegram. Отлично подходит для мониторинга сети Meshtastic и получения уведомлений прямо в Telegram.

🚀 Быстрая установка (5 минут)

Если вы никогда не работали с Docker или Python - не переживайте! Я постарался сделать установку максимально простой. Следуйте шагам по порядку.

Что вам понадобится

  1. Компьютер с установленным Docker (Windows, Mac или Linux)

    • Если Docker не установлен, скачайте с официального сайта
    • После установки Docker Desktop запустите его и дождитесь полной загрузки
  2. Telegram бот (бесплатно, создается за 2 минуты)

    • Откройте Telegram и найдите бота @BotFather
    • Отправьте команду /newbot и следуйте инструкциям
    • Сохраните токен бота (выглядит как 123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
  3. Meshtastic нода (уже должна быть настроена и работать)

Шаг 1: Скачайте проект

Откройте терминал (или PowerShell на Windows) и выполните:

git clone <repository-url>
cd Meshtastic_MQTT_bot

Если у вас нет Git, просто скачайте проект как ZIP-архив и распакуйте его.

Шаг 2: Настройте конфигурацию

  1. Найдите файл env.example в папке проекта

  2. Скопируйте его и переименуйте в .env (точка в начале важна!)

  3. Откройте файл .env в любом текстовом редакторе (Блокнот, Notepad++, VS Code - что угодно)

  4. Заполните обязательные поля:

# Вставьте токен вашего бота (получили от @BotFather)
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz

# ID группового чата (пока оставьте пустым, настроим позже)
TELEGRAM_GROUP_CHAT_ID=

# Ваши Telegram ID (можно оставить пустым для доступа всем)
TELEGRAM_ALLOWED_USER_IDS=

# Настройки MQTT брокера (для Docker оставьте как есть)
MQTT_SOURCE_HOST=mosquitto
MQTT_SOURCE_PORT=1883
MQTT_SOURCE_TOPIC=msh/#

Важно: Не используйте кавычки вокруг значений! Просто пишите значение после знака =

Шаг 3: Запустите бота

В терминале (в папке проекта) выполните:

docker-compose up -d

Эта команда:

  • Скачает необходимые образы (если их еще нет)
  • Запустит MQTT брокер (Mosquitto)
  • Запустит Telegram бота
  • Все будет работать в фоновом режиме

Шаг 4: Проверьте, что все работает

Посмотрите логи бота:

docker-compose logs -f telegram-bot

Вы должны увидеть что-то вроде:

INFO - Инициализация Meshtastic Telegram Bot
INFO - Запуск Meshtastic Telegram Bot
INFO - Успешно подключен к MQTT брокеру
INFO - Приложение запущено и готово к работе

Если видите ошибки - переходите к разделу "Решение проблем" ниже.

Шаг 5: Настройте групповой чат

  1. Создайте группу в Telegram (или используйте существующую)
  2. Добавьте вашего бота в группу
  3. Дайте боту права администратора (опционально, но рекомендуется)
  4. Отправьте в группе команду /get_chat_id
  5. Бот ответит с ID чата (обычно отрицательное число, например -1001234567890)
  6. Откройте файл .env и вставьте этот ID:
    TELEGRAM_GROUP_CHAT_ID=-1001234567890
  7. Перезапустите бота:
    docker-compose restart telegram-bot

Готово! Теперь сообщения от вашей Meshtastic ноды будут приходить в Telegram.


📡 Настройка Meshtastic ноды

Чтобы нода отправляла данные на ваш MQTT брокер, нужно настроить MQTT в приложении Meshtastic.

Определите IP адрес вашего сервера

На Windows:

  1. Откройте командную строку (Win+R, введите cmd)
  2. Выполните: ipconfig
  3. Найдите "IPv4-адрес" (обычно что-то вроде 192.168.1.100)

На Linux/Mac:

ip addr show  # или ifconfig

Настройте MQTT в Meshtastic

  1. Откройте приложение Meshtastic на телефоне
  2. Перейдите в настройки ноды
  3. Найдите раздел "MQTT" или "Network"
  4. Включите MQTT
  5. Укажите:
    • MQTT Server: ВАШ_IP_АДРЕС:1883
      • Например: 192.168.1.100:1883
    • MQTT Topic: выберите один из вариантов:
      • msh - режим ALL (все сообщения - и в группу, и пользователям)
      • msh/group - режим GROUP (только групповые сообщения)
      • msh/private/{ваш_telegram_id} - режим PRIVATE (только личные сообщения)
        • Узнайте ваш Telegram ID через команду /id в боте
        • Например: msh/private/123456789
      • msh/private/{ваш_telegram_id}/group - режим PRIVATE_GROUP (личные + группа)
    • Client Proxy Enabled: выключите (если не нужна двусторонняя связь)
  6. Шифрование: откл. (так как protobuf формат не работает с шифрованием)
  7. Сохраните настройки

Примечание: Режим работы бота определяется по структуре MQTT топика. Вы можете настроить разные ноды для разных режимов работы.

Проверьте подключение

  1. Посмотрите логи Mosquitto:

    docker-compose logs -f mosquitto
  2. Вы должны увидеть что-то вроде:

    New client connected from 192.168.1.50:54321 as !698535e0
    
  3. Если видите ошибки - проверьте:

    • Правильно ли указан IP адрес
    • Открыт ли порт 1883 в файрволе
    • Находятся ли нода и сервер в одной сети Wi-Fi

🏗️ Структура проекта: что за что отвечает

Давайте разберемся, как устроен этот бот. Не пугайтесь - я объясню простыми словами.

Общая архитектура

Бот построен по принципу "слоеного пирога" - каждый слой отвечает за свою задачу:

┌─────────────────────────────────────┐
│   Application (Оркестрация)         │  ← Управляет всем процессом
├─────────────────────────────────────┤
│   Handlers (Обработчики)            │  ← Реагируют на события
├─────────────────────────────────────┤
│   Services (Бизнес-логика)          │  ← Обрабатывают данные
├─────────────────────────────────────┤
│   Repositories (Хранилища)          │  ← Работают с внешними системами
├─────────────────────────────────────┤
│   Domain (Модели данных)            │  ← Описывают структуру данных
└─────────────────────────────────────└

Структура папок

Meshtastic_MQTT_bot/
├── src/                          # Весь исходный код
│   ├── application/              # Главный "дирижер" оркестра
│   │   └── app.py                # Запускает и останавливает все компоненты
│   │
│   ├── domain/                   # Модели данных (как "чертежи")
│   │   └── message.py            # Описывает, как выглядит сообщение
│   │
│   ├── repo/                     # Работа с внешними системами
│   │   ├── mqtt_repository.py    # Читает сообщения из MQTT
│   │   └── telegram_repository.py # Отправляет в Telegram
│   │
│   ├── service/                  # Бизнес-логика (обработка данных)
│   │   ├── message_service.py    # Парсит MQTT сообщения
│   │   ├── mqtt_proxy_service.py # Пересылает в другие брокеры
│   │   ├── node_cache_service.py # Хранит информацию о нодах
│   │   ├── topic_routing_service.py # Определяет режим работы по топику
│   │   ├── message_processing_strategy.py # Стратегии обработки сообщений
│   │   └── message_grouping_service.py # Группировка сообщений от разных нод
│   │
│   ├── handlers/                 # Реагируют на события
│   │   ├── mqtt_handler.py       # Обрабатывает MQTT сообщения (legacy)
│   │   ├── telegram_commands.py  # Обрабатывает команды бота (/start, /help)
│   │   ├── message_handler_chain.py # Цепочка обработчиков (Chain of Responsibility)
│   │   ├── handler_registry.py   # Реестр обработчиков
│   │   ├── handler_factory.py    # Фабрика для создания обработчиков
│   │   ├── concrete_handlers.py  # Конкретные реализации обработчиков
│   │   └── message_handler_adapter.py # Адаптер для совместимости
│   │
│   └── config.py                 # Все настройки приложения
│
├── main.py                        # Точка входа (отсюда все начинается)
├── docker-compose.yml             # Настройки Docker
├── Dockerfile                     # Как собрать образ бота
├── requirements.txt               # Список библиотек Python
├── .env                           # Ваши настройки (создаете сами)
└── mqtt_config.yaml.example       # Пример конфигурации MQTT (опционально)

📚 Подробное описание компонентов

1. Domain (Доменные модели) - src/domain/

Это "чертежи" данных. Описывают, как выглядят сообщения от Meshtastic.

message.py - Модель сообщения

Класс: MeshtasticMessage

Это основной класс, который описывает сообщение от Meshtastic. Представьте его как форму, которую нужно заполнить.

Основные поля (атрибуты):

  • topic - откуда пришло сообщение (MQTT топик)
  • from_node - кто отправил (ID ноды, например !698535e0)
  • from_node_name - имя отправителя (например, "NCH.PT.0.63 (Ruslan)")
  • from_node_short - короткое имя (например, "35e0")
  • to_node - кому отправлено (или "Всем" если 4294967295)
  • text - текст сообщения
  • timestamp - когда отправлено (Unix timestamp)
  • rssi - качество сигнала (чем ближе к 0, тем лучше)
  • snr - отношение сигнал/шум
  • hops_away - сколько раз ретранслировано (0 = прямая доставка)
  • message_type - тип сообщения (text, nodeinfo, position)

Методы:

  • format_for_telegram() - превращает сообщение в красивый текст для Telegram

    • Добавляет эмодзи
    • Форматирует дату и время
    • Добавляет ссылку на местоположение (если есть координаты)
    • Экранирует HTML для безопасности
  • format_for_telegram_with_grouping() - форматирует сообщение с учетом группировки нод-получателей

    • Показывает список всех нод, которые получили сообщение
    • Опционально показывает время получения каждой нодой
    • Отображает качество сигнала для каждой ноды
    • Блок "📥 Получено нодами:" расположен над блоком местоположения
  • get_rssi_quality_emoji() - определяет цвет эмодзи по качеству сигнала

    • 🟢 Отличный (> -80 dBm)
    • 🟡 Нормальный (-80 до -100 dBm)
    • 🔴 Плохой (-100 до -120 dBm)
    • ⚫ Очень плохой (< -120 dBm)
  • get_snr_quality_emoji() - аналогично для SNR


2. Repository (Хранилища) - src/repo/

Эти классы работают напрямую с внешними системами - MQTT брокером и Telegram API.

mqtt_repository.py - Работа с MQTT

Класс: AsyncMQTTRepository

Отвечает за подключение к MQTT брокеру и получение сообщений.

Методы:

  • connect() - подключается к брокеру

    • Создает MQTT клиент
    • Устанавливает соединение
    • Настраивает параметры (username, password, keepalive)
  • disconnect() - отключается от брокера

    • Корректно закрывает соединение
    • Освобождает ресурсы
  • subscribe(topic, qos) - подписывается на топик

    • topic - на какой топик подписаться (например, msh/# для всех сообщений)
    • qos - уровень качества (0, 1 или 2)
  • publish(topic, payload, qos) - публикует сообщение

    • Используется прокси-сервисом для пересылки

Как это работает:

  1. Бот подключается к MQTT брокеру (Mosquitto)
  2. Подписывается на топик msh/# (получает все сообщения от Meshtastic)
  3. Когда Meshtastic нода отправляет сообщение, брокер получает его
  4. Брокер передает сообщение боту
  5. Бот автоматически определяет формат (JSON или Protobuf) и парсит сообщение
  6. Бот обрабатывает сообщение и отправляет в Telegram

telegram_repository.py - Работа с Telegram

Класс: AsyncTelegramRepository

Отвечает за отправку сообщений в Telegram.

Методы:

  • send_message(chat_id, text, parse_mode) - отправляет сообщение в чат

    • chat_id - ID чата (группы или пользователя)
    • text - текст сообщения
    • parse_mode - формат (HTML для ссылок и форматирования)
    • Возвращает ID отправленного сообщения
  • send_to_group(text) - отправляет в групповой чат

    • Использует group_chat_id из конфигурации
    • Возвращает ID отправленного сообщения (для группировки)
  • send_to_user(user_id, text) - отправляет пользователю в личный чат

    • Проверяет, разрешен ли пользователь
  • edit_message(chat_id, message_id, text, parse_mode) - редактирует существующее сообщение

    • Используется для группировки сообщений
    • Обновляет текст сообщения, добавляя информацию о новых нодах-получателях
  • edit_group_message(message_id, text) - редактирует сообщение в групповом чате

    • Удобный метод для редактирования групповых сообщений
  • is_user_allowed(user_id) - проверяет доступ пользователя

    • Если allowed_user_ids не задан - разрешает всем
    • Иначе проверяет, есть ли пользователь в списке

3. Service (Бизнес-логика) - src/service/

Здесь происходит обработка данных - парсинг, кэширование, пересылка.

message_service.py - Парсинг сообщений

Класс: MessageService

Превращает сырые MQTT сообщения в структурированные объекты. Поддерживает два формата: JSON и Protobuf.

Методы:

  • parse_mqtt_message(topic, payload) - парсит MQTT сообщение
    • Принимает топик и данные (байты)
    • Автоматически определяет формат по топику и настройке payload_format
    • Использует соответствующий парсер (JSON или Protobuf)
    • Извлекает информацию о нодах из кэша
    • Определяет тип сообщения (text, nodeinfo, position)
    • Возвращает объект MeshtasticMessage

Парсеры:

Бот использует два отдельных парсера для разных форматов:

  1. JsonMessageParser - для JSON сообщений

    • Декодирует UTF-8 текст
    • Парсит JSON структуру
    • Извлекает поля напрямую из JSON
  2. ProtobufMessageParser - для Protobuf сообщений

    • Декодирует бинарный protobuf через meshtastic.protobuf.mqtt_pb2
    • Определяет тип сообщения по portnum (TEXT_MESSAGE_APP, NODEINFO_APP, POSITION_APP и т.д.)
    • Декодирует payload в зависимости от типа:
      • Текстовые сообщения - декодирует UTF-8
      • Сжатые тексты - распаковывает через Unishox2 (если доступен)
      • Nodeinfo - парсит через mesh_pb2.User
      • Position - парсит через mesh_pb2.Position
      • Telemetry - парсит через telemetry_pb2.Telemetry
      • И другие типы по необходимости
    • Вычисляет hops_away как hop_start - hop_limit

Как это работает:

  1. Получает сырые данные от MQTT брокера
  2. Определяет формат по топику:
    • Топики с /e/ (без /json/) - protobuf формат
    • Топики с /json/ - JSON формат
  3. Выбирает соответствующий парсер
  4. Парсер извлекает данные и определяет тип сообщения
  5. Если это nodeinfo - обновляет кэш нод (имена, ID)
  6. Если это position - обновляет координаты в кэше
  7. Если это text - извлекает текст и информацию об отправителе
  8. Создает объект MeshtasticMessage со всей информацией

Настройка формата:

В .env или mqtt_config.yaml можно указать:

  • MQTT_SOURCE_PAYLOAD_FORMAT=json - только JSON (по умолчанию)
  • MQTT_SOURCE_PAYLOAD_FORMAT=protobuf - только Protobuf
  • MQTT_SOURCE_PAYLOAD_FORMAT=both - оба формата (может быть дублирование)

node_cache_service.py - Кэш информации о нодах

Класс: NodeCacheService

Хранит информацию о нодах Meshtastic: имена, координаты, когда обновлялись.

Зачем это нужно:

Meshtastic ноды отправляют разные типы сообщений:

  • text - текстовые сообщения (часто без полной информации об отправителе)
  • nodeinfo - информация о ноде (имя, ID)
  • position - координаты ноды

Чтобы показывать красивые имена вместо ID, бот кэширует информацию о нодах.

Методы:

  • update_node_info(node_id, longname, shortname) - обновляет информацию о ноде

    • Всегда обновляет имена в памяти (при получении nodeinfo)
    • На диск сохраняет только раз в 3 дня (чтобы не изнашивать диск)
    • Используется при получении nodeinfo сообщений
    • Важно: Имена обновляются сразу, независимо от интервала сохранения на диск
  • update_node_position(node_id, latitude, longitude, altitude) - обновляет координаты

    • Всегда обновляет в памяти
    • На диск сохраняет только раз в 3 дня (чтобы не изнашивать диск)
  • get_node_name(node_id) - получает имя ноды из кэша

    • Сначала ищет в памяти
    • Если не находит - загружает с диска
  • get_node_shortname(node_id) - получает короткое имя

  • get_node_position(node_id) - получает координаты ноды

Где хранится:

  • В памяти (быстро, но теряется при перезапуске)
  • На диске в файле data/nodes_cache.json (сохраняется между перезапусками)

Структура файла кэша:

{
  "nodes": [
    {
      "node_id": "!698535e0",
      "longname": "NCH.PT.0.63 (Ruslan)",
      "shortname": "35e0",
      "latitude": 55.756899,
      "longitude": 52.463371,
      "altitude": 125,
      "last_updated": "2025-12-10T00:18:00",
      "last_position_updated": "2025-12-10T00:18:00"
    }
  ],
  "last_saved": "2025-12-10T00:18:00"
}

message_grouping_service.py - Группировка сообщений

Класс: MessageGroupingService

Группирует сообщения от разных нод с одинаковым message_id в одно Telegram сообщение.

Зачем это нужно:

Когда одно и то же сообщение получают несколько нод, вместо отправки отдельного сообщения для каждой ноды, бот:

  1. Отправляет одно сообщение при первом получении
  2. Редактирует это сообщение, добавляя информацию о других нодах-получателях
  3. Показывает компактный список всех нод, которые получили сообщение

Методы:

  • get_or_create_group(message_id, telegram_message_id) - получает или создает группу сообщений
  • add_received_node(message_id, message, receiver_node_id) - добавляет ноду-получателя в группу
  • is_grouping_active(message_id) - проверяет, активна ли еще группировка (не истек таймаут)
  • cleanup_expired_groups() - удаляет устаревшие группы

Настройки:

  • message_grouping_enabled - включить/выключить группировку (по умолчанию true)
  • message_grouping_timeout - таймаут группировки в секундах (по умолчанию 30)
  • show_receive_time - показывать время получения каждой нодой (по умолчанию false)

Пример работы:

  1. Нода A получает сообщение с message_id=123 → отправляется новое Telegram сообщение
  2. Нода B получает то же сообщение (message_id=123) → редактируется существующее сообщение, добавляется "Нода B"
  3. Нода C получает то же сообщение → редактируется сообщение, добавляется "Нода C"
  4. Через 30 секунд (таймаут) новые ноды больше не добавляются

topic_routing_service.py - Определение режима работы по топику

Класс: TopicRoutingService

Определяет режим обработки сообщений на основе структуры MQTT топика.

Поддерживаемые режимы:

  • ALL - все пакеты (топик msh)
  • PRIVATE - только личные сообщения (топик msh/private/{tg_id})
  • GROUP - только групповые сообщения (топик msh/group)
  • PRIVATE_GROUP - личные + группа (топик msh/private/{tg_id}/group)

Методы:

  • detect_mode_from_topic(topic) - определяет режим из топика
  • set_user_mode(tg_id, mode) - устанавливает режим для пользователя (переопределяет топик)
  • get_user_mode(tg_id) - получает режим пользователя
  • get_effective_mode(topic, tg_id) - определяет итоговый режим (с учетом переопределений)

Как это работает:

  1. Нода публикует сообщения в определенный топик (например, msh/private/123456789)
  2. Бот анализирует топик и определяет режим работы
  3. Сообщение обрабатывается согласно режиму (отправляется в личный чат, в группу, или и туда, и туда)

message_processing_strategy.py - Стратегии обработки сообщений

Класс: MessageProcessingStrategy (абстрактный)

Реализует паттерн Strategy для разных режимов обработки сообщений.

Реализации:

  • PrivateModeStrategy - обработка в режиме PRIVATE (только личные сообщения)
  • GroupModeStrategy - обработка в режиме GROUP (только групповые сообщения)
  • AllModeStrategy - обработка в режиме ALL (все сообщения)

Методы:

  • should_process(message) - проверяет, нужно ли обрабатывать сообщение
  • process_message(message, telegram_repo, node_cache_service) - обрабатывает сообщение

mqtt_proxy_service.py - Пересылка в другие брокеры

Класс: MQTTProxyService

Пересылает сообщения в другие MQTT брокеры (например, в облачный брокер для мониторинга).

Зачем это нужно:

  • Отправка данных в облако для анализа
  • Синхронизация с другими системами
  • Резервное копирование сообщений

Класс: MQTTProxyTarget

Представляет один целевой брокер для прокси.

Методы:

  • connect() - подключается к целевому брокеру
  • disconnect() - отключается
  • publish_message(message) - публикует сообщение

Класс: MQTTProxyService

Управляет несколькими целевыми брокерами.

Методы:

  • start() - подключается ко всем брокерам параллельно

    • Использует asyncio.gather() для одновременного подключения
    • Если один брокер недоступен - остальные все равно подключатся
  • stop() - отключается от всех брокеров параллельно

  • proxy_message(message) - пересылает сообщение во все брокеры параллельно

    • Это ключевое улучшение! Все брокеры получают сообщение одновременно
    • Если один брокер медленный - остальные не ждут

Пример работы:

До улучшения (последовательно):

  • Брокер 1: 100 мс
  • Брокер 2: 100 мс
  • Брокер 3: 100 мс
  • Итого: 300 мс

После улучшения (параллельно):

  • Все брокеры одновременно: 100 мс
  • Итого: 100 мс (в 3 раза быстрее!)

4. Handlers (Обработчики) - src/handlers/

Эти классы реагируют на события - приход MQTT сообщений или команд в Telegram.

mqtt_handler.py - Обработка MQTT сообщений (Legacy)

Класс: MQTTMessageHandlerImpl

Старая реализация обработчика MQTT сообщений. Сохранена для обратной совместимости.

Новая архитектура обработчиков:

Бот использует паттерны Chain of Responsibility, Strategy, Registry и Factory для гибкой обработки сообщений:

  1. Handler Chain (message_handler_chain.py) - цепочка обработчиков

    • Каждый обработчик может обработать сообщение или передать следующему
    • Порядок обработки определяется приоритетом
  2. Handler Registry (handler_registry.py) - реестр обработчиков

    • Централизованное управление обработчиками
    • Легко добавлять новые обработчики
  3. Handler Factory (handler_factory.py) - фабрика обработчиков

    • Создает цепочку обработчиков из конфигурации
    • Инжектирует зависимости
  4. Concrete Handlers (concrete_handlers.py) - конкретные реализации

    • ProxyHandler - пересылка в другие брокеры
    • TelegramHandler - отправка в Telegram

Как это работает:

  1. Сообщение приходит от MQTT брокера
  2. Определяется режим работы через TopicRoutingService (по топику)
  3. Выбирается стратегия обработки (MessageProcessingStrategy)
  4. Сообщение проходит через цепочку обработчиков:
    • ProxyHandler - пересылает в другие брокеры (если режим не PRIVATE)
    • TelegramHandler - отправляет в Telegram согласно стратегии
  5. Если включена группировка (message_grouping_enabled=true):
    • Сообщения с одинаковым message_id группируются
    • Первое сообщение отправляется как новое
    • Последующие редактируют существующее сообщение, добавляя информацию о новых нодах-получателях

Режимы работы:

  • PRIVATE (msh/private/{tg_id}) - только личные сообщения пользователю
  • GROUP (msh/group) - только групповые сообщения
  • ALL (msh) - все сообщения (и в группу, и пользователям)
  • PRIVATE_GROUP (msh/private/{tg_id}/group) - личные + группа

Фильтрация сообщений:

  • В Telegram отправляются только сообщения типа text
  • nodeinfo и position обрабатываются для кэша, но не отправляются
  • Это работает для обоих форматов (JSON и Protobuf)

telegram_commands.py - Команды бота

Класс: TelegramCommandsHandler

Обрабатывает команды, которые пользователи отправляют боту в личном чате.

Доступные команды:

  • /start - приветствие и краткая информация
  • /help - справка по всем командам
  • /status - текущий статус бота
    • Подключен ли к MQTT
    • Работает ли Telegram polling
    • Количество прокси-брокеров
  • /info - детальная информация
    • ID группового чата
    • Разрешенные пользователи
    • Настройки MQTT прокси
  • /get_chat_id - получить ID текущего чата
  • /id - получить ваш Telegram ID и пример приватного топика
    • Показывает ваш user_id, username, имя
    • Выводит пример топика для приватного режима (например, msh/private/123456789)
  • /mode - управление режимом работы бота
    • Просмотр текущего режима
    • Установка режима для пользователя (переопределяет режим из топика)

Контроль доступа:

Перед обработкой команды проверяется, разрешен ли пользователь:

  • Если TELEGRAM_ALLOWED_USER_IDS не задан - доступ у всех
  • Если задан - только указанные пользователи

Метод: register_handlers(bot)

Регистрирует все обработчики команд в боте.


5. Application (Оркестрация) - src/application/

Это "дирижер оркестра" - управляет всеми компонентами.

app.py - Главный класс приложения

Класс: MeshtasticTelegramBotApp

Собирает все компоненты вместе и управляет жизненным циклом приложения.

Что делает при инициализации:

  1. Загружает конфигурацию
  2. Создает все сервисы:
    • MQTTRepository - для работы с MQTT
    • TelegramRepository - для работы с Telegram
    • MessageService - для парсинга сообщений
    • NodeCacheService - для кэша нод
    • MQTTProxyService - для пересылки
    • MQTTMessageHandler - для обработки MQTT
    • TelegramCommandsHandler - для команд

Методы:

  • start() - запускает приложение

    1. Подключается к MQTT брокеру
    2. Подписывается на топик
    3. Запускает Telegram polling (получение команд)
    4. Запускает прокси-сервис
    5. Запускает обработку MQTT сообщений в фоне
  • stop() - останавливает приложение

    1. Останавливает Telegram polling
    2. Отключается от MQTT
    3. Останавливает прокси-сервис
    4. Корректно закрывает все соединения
  • run_forever() - запускает и работает до получения сигнала остановки

    • Обрабатывает сигналы (Ctrl+C, SIGTERM)
    • Корректно завершает работу

Асинхронные задачи:

  • _subscribe_task - обрабатывает входящие MQTT сообщения
  • _telegram_polling_task - обрабатывает команды Telegram

6. Config (Конфигурация) - src/config.py

Здесь хранятся все настройки приложения.

Основные классы конфигурации

MQTTBrokerConfig - настройки основного MQTT брокера (источник данных)

  • host - адрес брокера (mosquitto для Docker, localhost для локального запуска)
  • port - порт (обычно 1883)
  • username / password - для аутентификации (если требуется)
  • topic - топик для подписки (msh/# для всех сообщений)
  • client_id - идентификатор клиента
  • qos - уровень качества (0, 1 или 2)

MQTTProxyTargetConfig - настройки одного прокси-брокера

  • name - имя (для логирования)
  • host / port - адрес целевого брокера
  • username / password - аутентификация
  • topic_prefix - префикс для топика (опционально)
  • enabled - включен ли этот прокси
  • qos - уровень качества
  • tls - использовать TLS/SSL соединение (обычно true для порта 8883)
  • tls_insecure - отключить проверку сертификата (только для самоподписанных сертификатов, не рекомендуется для продакшена)

TelegramConfig - настройки Telegram бота

  • bot_token - токен бота (обязательно)
  • group_chat_id - ID группового чата (опционально)
  • group_topic_id - ID темы в группе для форумов (опционально)
  • allowed_user_ids - список разрешенных пользователей (опционально)
  • show_receive_time - показывать время получения каждой нодой в группированных сообщениях (по умолчанию false)
  • message_grouping_enabled - включить группировку сообщений по message_id (по умолчанию true)
  • message_grouping_timeout - таймаут группировки в секундах (по умолчанию 30)

MessageProcessingConfig - настройки обработки сообщений

  • default_mode - режим обработки по умолчанию: private, group, all (по умолчанию group)
  • group_mode_send_to_users - отправлять личные сообщения в режиме GROUP (по умолчанию false)
  • handlers - конфигурация обработчиков (порядок и приоритет)

AppConfig - главная конфигурация

Собирает все настройки вместе.

Методы:

  • load_from_yaml(yaml_path) - загружает конфигурацию из YAML файла

    • Если файл не найден - использует .env
    • Если файл найден - объединяет с .env (переменные окружения имеют приоритет)
  • setup_logging() - настраивает логирование


⚙️ Конфигурация

Способ 1: Через .env файл (простой)

Создайте файл .env в корне проекта и заполните настройки (см. env.example).

Преимущества:

  • Просто и понятно
  • Подходит для одного прокси-брокера

Недостатки:

  • Неудобно для множественных прокси-брокеров

Способ 2: Через YAML файл (продвинутый)

Создайте файл mqtt_config.yaml на основе mqtt_config.yaml.example.

Преимущества:

  • Удобно для множественных прокси-брокеров
  • Структурированная конфигурация
  • Легко добавлять/удалять брокеры

Пример:

mqtt_source:
  host: mosquitto
  port: 1883
  topic: msh/#
  payload_format: json  # json | protobuf | both
  qos: 1

mqtt_proxy_targets:
  - name: cloud_broker
    host: cloud.mqtt.example.com
    port: 1883
    username: user1
    password: pass1
    enabled: true
    qos: 1
    tls: false  # Обычный MQTT (порт 1883)
  
  - name: secure_broker
    host: secure.mqtt.example.com
    port: 8883  # Стандартный порт для MQTT over TLS
    username: user2
    password: pass2
    enabled: true
    qos: 1
    tls: true  # Включить TLS для порта 8883
    tls_insecure: false  # Проверять сертификат (рекомендуется)
  
  - name: internal_broker
    host: internal.mqtt.local
    port: 8883
    enabled: true
    qos: 1
    tls: true
    tls_insecure: true  # Отключить проверку для самоподписанного сертификата

Приоритет настроек:

  1. Переменные окружения (.env) - наивысший приоритет
  2. YAML файл - средний приоритет
  3. Значения по умолчанию - низкий приоритет

🔧 Решение проблем

Бот не запускается

Ошибка: "TELEGRAM_BOT_TOKEN не задан"

Решение:

  1. Проверьте, что файл .env существует
  2. Убедитесь, что токен указан правильно (без кавычек)
  3. Пересоберите контейнер: docker-compose build telegram-bot && docker-compose up -d

Бот не получает сообщения от ноды

Проверьте:

  1. Нода подключена к брокеру?

    docker-compose logs mosquitto | grep "New client connected"

    Должны увидеть подключение вашей ноды.

  2. Правильный IP адрес?

    • В настройках ноды должен быть IP вашего сервера
    • Нода и сервер должны быть в одной сети Wi-Fi
  3. Правильный топик?

    • В ноде: msh (без решетки - подписка на все сообщения)
    • В боте: msh/№ (с решеткой - получает все сообщения)
    • Бот автоматически определяет формат (JSON или Protobuf) по топику
  4. Порт открыт?

    • Проверьте файрвол
    • Убедитесь, что порт 1883 доступен

Сообщения не приходят в Telegram

  1. Бот добавлен в группу?

    • Добавьте бота в группу
    • Дайте права администратора
  2. Правильный ID чата?

    • Используйте команду /get_chat_id в группе
    • Убедитесь, что ID отрицательный (начинается с -)
  3. Проверьте логи:

    docker-compose logs -f telegram-bot

    Ищите ошибки отправки сообщений.

Прокси не работает

  1. Прокси включен?

    • Проверьте MQTT_PROXY_TARGET_ENABLED=true в .env
    • Или enabled: true в YAML
  2. Брокер доступен?

    • Проверьте адрес и порт
    • Убедитесь, что брокер работает
  3. Проверьте логи:

    docker-compose logs telegram-bot | grep proxy

Пересборка после изменений

Если вы изменили код и хотите применить изменения:

# Остановить контейнеры
docker-compose down

# Пересобрать образ бота
docker-compose build telegram-bot

# Запустить заново
docker-compose up -d

# Или одной командой:
docker-compose up --build -d

📊 Мониторинг и логи

Просмотр логов

Логи бота:

docker-compose logs -f telegram-bot

Логи MQTT брокера:

docker-compose logs -f mosquitto

Все логи:

docker-compose logs -f

Уровни логирования

В файле .env можно настроить уровень логирования:

LOG_LEVEL=DEBUG  # Показывает все, включая отладочную информацию
LOG_LEVEL=INFO   # Обычная информация (по умолчанию)
LOG_LEVEL=WARNING # Только предупреждения и ошибки
LOG_LEVEL=ERROR  # Только ошибки

Проверка статуса

Статус контейнеров:

docker-compose ps

Health checks: Docker автоматически проверяет здоровье контейнеров. Если контейнер нездоров - он будет перезапущен.


🎯 Полезные команды

Docker Compose

# Запустить
docker-compose up -d

# Остановить
docker-compose down

# Перезапустить
docker-compose restart telegram-bot

# Просмотр логов
docker-compose logs -f telegram-bot

# Пересобрать
docker-compose build telegram-bot

# Остановить и удалить все (включая данные)
docker-compose down -v

Работа с кэшем нод

Кэш нод хранится в data/nodes_cache.json. Вы можете:

  • Просмотреть содержимое (текстовым редактором)
  • Удалить для сброса кэша
  • Вручную отредактировать (не рекомендуется)

🔒 Безопасность

Рекомендации

  1. Не публикуйте .env файл

    • Он содержит секреты (токены, пароли)
    • Уже добавлен в .gitignore
  2. Не публикуйте mqtt_config.yaml

    • Может содержать пароли
    • Уже добавлен в .gitignore
  3. Используйте сильные пароли

    • Для MQTT брокера (если требуется)
    • Для прокси-брокеров
  4. Ограничьте доступ

    • Настройте TELEGRAM_ALLOWED_USER_IDS
    • Не давайте всем доступ к командам бота
  5. Файрвол

    • Откройте только необходимые порты (1883 для MQTT)
    • Ограничьте доступ к порту 1883 только вашей локальной сети

📝 FAQ (Часто задаваемые вопросы)

Q: Сколько прокси-брокеров можно добавить?
A: Неограниченно! Добавляйте столько, сколько нужно.

Q: Можно ли использовать без Docker?
A: Да, но нужно установить Python 3.11+ и все зависимости. См. раздел "Локальная установка" в старом README.

Q: Как часто обновляется кэш нод?
A: Имена нод (longname, shortname) всегда обновляются в памяти при получении nodeinfo. На диск сохраняются раз в 3 дня (чтобы не изнашивать диск). Координаты обновляются в памяти всегда, на диск - раз в 3 дня.

Q: Что такое группировка сообщений?
A: Когда одно и то же сообщение получают несколько нод, бот группирует их в одно Telegram сообщение. Вместо нескольких отдельных сообщений вы видите одно с компактным списком всех нод-получателей. Можно включить/выключить через TELEGRAM_MESSAGE_GROUPING_ENABLED.

Q: Как работают режимы работы бота?
A: Бот определяет режим работы по структуре MQTT топика:

  • msh - режим ALL (все сообщения)
  • msh/private/{tg_id} - режим PRIVATE (только личные)
  • msh/group - режим GROUP (только группа)
  • msh/private/{tg_id}/group - режим PRIVATE_GROUP (личные + группа)

Вы можете переопределить режим через команду /mode в Telegram.

Q: Почему не все сообщения попадают в Telegram?
A: В Telegram отправляются только сообщения типа text. Технические сообщения (nodeinfo, position) обрабатываются для кэша, но не отправляются. Это работает для обоих форматов - JSON и Protobuf. Также сообщения могут не отправляться в зависимости от режима работы (PRIVATE/GROUP/ALL) и настроек обработки.

Q: Какой формат сообщений использовать - JSON или Protobuf?
A: По умолчанию используется JSON (payload_format=json). Protobuf более компактный, но требует дополнительных зависимостей. Можно использовать оба формата одновременно (payload_format=both), но это может привести к дублированию сообщений, так как Meshtastic часто отправляет один и тот же пакет в обоих форматах.

Q: Можно ли изменить формат сообщений?
A: Да, отредактируйте метод format_for_telegram() в файле src/domain/message.py.

Q: Как добавить новый прокси-брокер?
A: Добавьте новую запись в mqtt_config.yaml в секцию mqtt_proxy_targets или используйте переменные окружения с другим префиксом.


🏛️ Архитектурные паттерны

Проект использует следующие паттерны проектирования для обеспечения гибкости и расширяемости:

Strategy Pattern

Различные стратегии обработки сообщений (MessageProcessingStrategy):

  • PrivateModeStrategy - обработка личных сообщений
  • GroupModeStrategy - обработка групповых сообщений
  • AllModeStrategy - обработка всех сообщений

Chain of Responsibility

Цепочка обработчиков (MessageHandler):

  • Каждый обработчик может обработать сообщение или передать следующему
  • Порядок определяется приоритетом из конфигурации

Registry Pattern

Централизованный реестр обработчиков (HandlerRegistry):

  • Упрощает добавление новых обработчиков
  • Единая точка регистрации

Factory Pattern

Фабрика для создания обработчиков и стратегий (HandlerFactory):

  • Инкапсулирует логику создания объектов
  • Упрощает управление зависимостями

Adapter Pattern

Адаптер для совместимости (MessageHandlerAdapter):

  • Адаптирует новую архитектуру обработчиков к существующему интерфейсу

🚀 Дальнейшее развитие

Если вы хотите улучшить проект:

  1. Добавьте фильтрацию сообщений (по отправителю, содержимому)
  2. Реализуйте дополнительные команды для управления ботом через Telegram
  3. Добавьте метрики и мониторинг (Prometheus, Grafana)
  4. Создайте веб-интерфейс для управления
  5. Добавьте поддержку других протоколов (например, HTTP API)
  6. Расширьте группировку сообщений (например, группировка по времени)

📄 Лицензия

См. файл LICENSE


🙏 Благодарности

Спасибо всем, кто использует этот проект! Если у вас есть вопросы или предложения - создавайте Issues в репозитории.

Удачной работы с Meshtastic! 📡

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published