Простой Telegram-бот для получения информации через MQTT
- среда, 5 мая 2021 г. в 00:36:22
Этот бот был разработан для просмотра информации, находящейся на 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