Простой Telegram-бот для получения информации через MQTT

    Этот бот был разработан для просмотра информации, находящейся на mqtt сервере внутри локальной сети. Он может работать на одном компьютере с mqtt сервером (в том числе на Raspberry PI или подобном) или отдельно. Задача удалённого управления не ставилась, только предоставление доступа к данным.

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

    На mqtt сервере публикуются данные телеметрии с различных датчиков - допустим, это метеостанция и термометры в теплицах. Для их просмотра на десктопе я раньше делал виджет, веб-страницу, потом захотелось иметь эти данные всегда под рукой. Конечно, можно было пробросить доступ к серверу наружу или разместить его в облаке, но тут возникает ещё целый ряд проблем. Тема использования бота в мессенджере для меня не новая - ещё пятнадцать лет назад я использовал ICQ клиента на мобильном телефоне, чтобы с помощью ICQRemote и скрипта на AutoIt переключать треки в Winamp на десктопе. Сейчас средний телефон гораздо мощнее того десктопа и имеет почти столько же постоянной памяти, но проблема внешнего подключения к устройству в локальной сети по-прежнему существует. И боты всё так же отлично справляются с решением этой проблемы. В общем, было решено делать Телеграм-бота, который просто предоставляет по запросу необходимую информацию.

    Я не буду рассказывать про регистрацию имени бота и получение токена, так как это всё уже есть в каждой предыдущей статье про телеграм-ботов. Перейду сразу к программе на Python. Она разрабатывалась под Windows, но я не вижу препятствий для её запуска под другими системами - используемые библиотеки python-telegram-bot и paho-mqtt это позволяют.

    Настройки программы хранятся в ini файле. В секции TELEGRAM прописывается токен для бота, в секции MQTT адрес и логин/пароль mqtt сервера, а также топик для получения данных (если несколько - через запятую, без пробелов). При запуске бот подключается к mqtt серверу и подписывается на необходимые топики. Глубина вложенности уровней может быть любой. Поступающие данные попадают в словарь alldata, ключом является полный топик:

    {
    'greenhouse/1/temp': '24.76',
    'greenhouse/1/upd': '22.04 18:20:30',
    'greenhouse/2/temp': '22.95',
    'greenhouse/3/temp': '28.91',
    'air/outdoor/1/temp': '17.32',
    'air/outdoor/1/upd': '22.04 18:21:25',
    'air/outdoor/1/pressure': '739',
    'air/outdoor/1/humidity': '58.3'
    }

    При необходимости чтения из этого словаря формируется разбитый на уровни вложенный словарь tree - дерево данных. Это преобразование выполняет функция maketree.

    def maketree(group, items, path):
        def sep(s):
            return s.split('/', 1)
    
        head = [i for i in items if len(sep(i)) == 2]
        tail = [i for i in items if len(sep(i)) == 1]
        if len(tail) == 1:
            return group, tail[0]
        gv = groupby(sorted(head), lambda i: sep(i)[0])
        return group, dict([(i, path) for i in tail] + [maketree(g, [sep(i)[1] for i in v], '') for g, v in gv])
    

    В результате получается такая структура:

    {
        "air": {
            "outdoor": {
                "1": {
                    "humidity": "58.3",
                    "pressure": "739",
                    "temp": "17.32",
                    "upd": "22.04 18:21:25"
                }
            }
        },
        "greenhouse": {
            "1": {
                "temp": "24.76",
                "upd": "22.04 18:20:30"
            },
            "2": {
                "temp": "22.95"
            },
            "3": {
                "temp": "28.91"
            }
        }
    }
    

    Из такого словаря очень легко получить нужные данные. Например, температура в 1 теплице находится по адресу tree[greenhouse][1][temp]. Так как данные обновляются намного чаще, чем запрашиваются, преобразование в момент запроса достаточно эффективно. При более частых запросах лучше будет формировать и обновлять такое дерево сразу при поступлении данных.

    Затем идёт подключение к серверу Телеграм. Бот предназначен для работы в локальной сети без возможности пробросить необходимый для веб-хука порт, поэтому для подключения он использует Long Polling запросы. Используется библиотека python-telegram-bot версии 12.8, так как в 13 версии разработчики что-то поломали. Установить её можно командой pip3 install python-telegram-bot==12.8

    Для упрощения работы с ботом не используются команды: в ответ на знакомое слово он отсылает информацию, на незнакомое выдаёт кнопки выбора. В моём случае кнопок две, они прописаны в функции get_keyb:

    def get_keyb():
        return [[InlineKeyboardButton('Погода', callback_data='1'),
                InlineKeyboardButton('Теплицы', callback_data='2')]]
     

    А также в словаре, строчными буквами для удобства сравнения:

    keys = {'погода': '1', 'теплицы': '2', 'приборы': '3'}

    Ключ "приборы" добавлен для отладки, на него ответ всегда "40"

    Вариант диалога
    Вариант диалога

    Кнопки можно многократно использовать для обновления информации.

    В принципе, подобного бота можно использовать и для управления чем-либо, например через публикацию команд в те же mqtt топики - это ограничивается только Вашей фантазией. Но тогда нужно будет добавить авторизацию и список контактов. Полный код бота на GitHub

    Комментарии 3

      +7
      — Приборы!
      — 120!
      — Что 120?
      — А что приборы?
        0
        Если управляемое устройство чуть мощнее то на него тоже можно ставить Телеграм и управлять напрямую без MQTT.
          0
          Тоже хороший вариант! Так можно собрать полностью автономное устройство со своей сим-картой.
          У меня данные собираются с нескольких устройств, поэтому объединил их на MQTT сервере. Планирую ещё статью про модульную систему сбора информации по различным каналам (http, modbus, Siemens S7, mqtt)

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое