Содержание
Telegram-Bot на PowerShell (часть 1)
В продолжение статьи «Система наблюдения и Telegram-бот» описание того, с чего начать создание своего Telegram-бота на PowerShell. В этих статьях я не буду рассматривать процесс регистрации бота. Эту информацию достаточно легко найти как в официальной документации Telegram, так и на просторах интернета. Здесь же я буду рассматривать исключительно создание бота в контексте PowerShell.
С чего начать?
Так как бот подразумивает некую интерактивность, для начала следует определиться, как нам получать обновления (новые события) от него. В документации описаны два варианта:
- POLLING – регулярный опрос сервера Telegram на появление новых событий
- Прост в реализации
- Не требует дополнительной настройки фаервола
- Не требует наличия статического IP-адреса (или настройки динамического DNS)
- Маленький, но всё же «лишний» трафик из-за регулярных запросов (в дачных условиях может быть критичным)
- Менее эффективный и быстрый
- WEBHOOKS – подразумивает наличие некой службы с Вашей стороны, которая будет слушать и принимать информацию о новых событиях, посылаемых сервером Telegram в Вашу сторону
- Эффективен и практически не потребляет трафика
- Сложнее в реализации
- Требует настройки фаервола
- Требует статический IP-адрес
Самым простым в реализации является первый вариант, его мы и будем рассматривать, но в перспективе следует задуматься о реализации варианта номер два.
Опрашиваем бота
Итак мы определились, что будем использовать пуллинг, т.е. ручной запрос к серверу Telegram. В упоминаемой выше документации написано, что пулинг надо производить используя метод getUpdates. В контексте данного метода самым интересным является параметр offset
, этим параметром мы можем определить, как и в каком количестве получать обновления:
0
– получать все обновления (новые, старые, все…)-1
– получить только последнее обновление (одно!)id последнего обновления + 1
– получить только новые события и отметить их просмотренными (логично, что id последнего обновления мы должны заранее знать и, само собой, не забыть сохранить новое)
Пример простого скрипта для получания массива всех обновлений бота посредством Invoke-WebRequest:
- Get-TelegramBotUpdates.ps1
# определяем переменные $token = <ваш_токен> # указываем свой токен $ChatTimeout = 3 # таймаут в секундах $allowed_updates = @("message","channel_post","inline_query","chosen_inline_result","callback_query") # ограничиваем тип получаемых событий $allowed_updates = ConvertTo-Json -InputObject $allowed_updates # конвертируем тип обновлений в json $UpdateId = 0 # какие события получаем? 0 - все, -1 только последнее, lastid+1 - получить новые и отметить их просмотренными # формируем URL $URL = "https://api.telegram.org/bot$token/getUpdates?offset=$UpdateId&allowed_updates=$allowed_updates&timeout=$ChatTimeout" # делаем запрос и преобразуем ответ из json $Request = Invoke-WebRequest -Uri $URL -Method Get $content = ConvertFrom-Json $Request.content # смотрим, что получили, но из содержания массива $content "вытащим" только текст сообщений $content.result.message.text
Разумеется, если мы хотим получить «говорящего» бота, нужно регулярно проверять обновления, чтобы вовремя реагировать на них.
Создаём задание в планировщике
Итак, у нас есть бот, мы умеем «читать» сообщения из чата с ним, теперь нам осталось как-то это автоматизировать. Проще всего запускать наш скрипт заданием из планировщика Windows.
Правда здесь есть одна проблема: планировщик Windows не умеет запускать задачи чаще чем раз в пять минут, а это, согласитесь, достаточно долгая пауза для проверки чата. Но можно обойти это ограничение, просто создав несколько триггеров с необходимым интервалом между ними. Сделаем такую задачу в планировщике (не забудьте изменить путь к скрипту):
# создаём массив из триггеров $triggers = @() $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:00 -Once $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:10 -Once $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:20 -Once $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:30 -Once $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:40 -Once $triggers += New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([System.TimeSpan]::MaxValue) -At 12:00:50 -Once # определяем действие (запуск нашего скрипта) $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-File ".\Get-TelegramBotUpdates.ps1"' # путь изменить на свой $settings = New-ScheduledTaskSettingsSet # формируем задачу... $task = New-ScheduledTask -Action $action -Trigger $triggers -Settings $settings # ...и создаём её в планировщике Register-ScheduledTask 'TelegramBot' -InputObject $task
Вот и всё. Теперь мы проверяем обновления нашего чата каждые 10 секунд.
Продолжение следует…
Обсуждение
Доброго времени суток! Спасибо за очень познавательную статью! Но, есть пара нюансов: при выполнении кода «$Request = Invoke-WebRequest -Uri «https://api.telegram.org/bot$token/getUpdates?offset=-1&timeout=1″ -Method Get» получаю ошибку «Invoke-WebRequest : {«ok»:false,»error_code»:409,»description»:»Conflict: can’t use getUpdates method while webhook is active»}» Как побороть, пока не разобрался….
Здравствуйте. Прошу прощения за долгий ответ, сейчас немного занят. Ну и приветствую Вас в клубе интересных и познавательных, но чрезвычайно самобытных powershell-костылей для Telegram. )))
Как я написал немного выше, мне сейчас не совсем удобно (а точнее, скорее лениво) проверять все нюансы, но вероятно у вас настроен webhook для бота, который является ограничением в работе метода getUpdates. Проверьте наличие «прослушивателя».
А вообще, конечно хотелось бы собраться силами и запилить ещё несколько частей про бота. Мне вроде как удалось более или менее что-то работоспособное сделать для дома, даже отчасти модульное. После статей оно, быть может, обрело бы структуру и было готовым лечь на github… Может в ближайший месяц, если ещё будет для кого это делать.
Добрый день! Спасибо за ответ! В общем, я разобрался в чем суть проблемы: у меня есть бот, который является вторым админом (помимо меня) в приватном канале, и может публиковать и получать инфу из него — с этим все нормально. Т.е. с публикацией в канал от имени бота. Но тут другой нюанс — у бота есть и своя лента, в которую я (как хозяин бота) так же могу постить. И тут возникает коллизия — при отработке getUpdates, сначала (в цикле) проверяется наличие новых сообщений в каналах (в которых добавлен бот), а потом непосредственно лента самого бота! Т.е. если я что-то пишу в ленте бота, то через getUpdates четко получаю текст сообщения. Но, т.к. мне нужна инфа только(!) из канала — в ленте бота всегда пусто — то, на выходе я получаю пустой массив! Т.е. используя ваш вариант скрипта — полученные данные из любого канала всегда будут перезатираться «пустым» массивом из ленты бота. Видимо, нужна доработка, которая будет в цикле проверять все «chat»:{«id»: в которых добавлен админом бот, что бы собирать из них сообщения. Думаю получилось донести свою мысль)) Оговорюсь сразу, такое происходит только в случае, если кто-то постит в канал, в котором мой бот-админ. Если постить непосредственно боту — тогда все Ok! Сообщения апдейтятся успешно под катом пример кода:
Вот что получаю на выходе:
Собственно, в это
«text»:«5555»
— мне и нужно как-то выдрать из массива Json!Ещё раз прошу прощения за долгий ответ.
У Вас явно лишнее определение переменной
$var
Зачем Вы её создаёте и заполняете
$Request.Content
, если перед этим вы определили переменную$obj
и заполнили её этими же данными, при этом логично преобразовав их из JSON?Ниже Ваш код, но работающий. Удалена переменная
$var
, а$props
заполняется значениями из$obj
.Я советую Вам выполнять этот код в PowerShell ISE. Это будет нагляднее, да и Вы сможете после выполнения просмотреть значения каждой переменной, что, поможет как-то улучшить понимание работы кода.
Добрый день! К сожалению, ни чего не получилось - бот может получать команду либо от канала, либо от себя. Настроить параллельно обработку событий в канале и в своей ленте, у меня так и не получилось.
При условии
$UpdateId = -1
бот получает только самое новое сообщение, про какую параллельность здесь может идти речь? Это же только пример работы. В вашем случае нужно видимо$UpdateId = $last_id + 1
, где переменную$last_id
читаем в самом начале скрипта и перезаписываем в конце (извне, например в файл).