Skip to content

Commit

Permalink
Merge pull request #2 from jpizquierdo/change_telegram_library
Browse files Browse the repository at this point in the history
Change telegram library
  • Loading branch information
jpizquierdo authored Jul 9, 2023
2 parents 75199fe + f0d706d commit 4c08fa1
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 74 deletions.
12 changes: 12 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
History
-------

0.0.6 (2013-07-09)
++++++++++++++++++

- Transition of telepot to python-telegram-bot. Telepot is deprecated and not robust and has to be changed. ``telegram_interface.py`` has been fully updated with new library.
- PTB (python-telegram-bot) has been changed to python-telegram-bot[job-queue] to be able to use the asynchrnous logging.
- ``telegram_bot.py`` process has been updated to not wait for the end of the telegram_interface.init(). This is an infinite loop now.

0.0.5 (2013-07-05)
++++++++++++++++++

- Initial version of the transition of telepot to python-telegram-bot. Telepot is deprecated and not robust and has to be changed. ``telegram_interface.py`` has been fully updated with new library.

0.0.4 (2013-07-03)
++++++++++++++++++

Expand Down
6 changes: 0 additions & 6 deletions docs/telegram_commands.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@

Botfather commands list
=======================
random - Random number

date - Current date

photo - Photo from URL

status - System Status

pump - Toggle pump
Expand Down
148 changes: 93 additions & 55 deletions draco/interfaces/telegram_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
import queue
import os
import keyring
import random
import datetime
import telepot
from telepot.loop import MessageLoop
from functools import partial
from telegram import Update
from telegram.ext import (
Application,
CommandHandler,
ContextTypes,
MessageHandler,
filters,
CallbackContext,
)


class TelegramInterface(object):
Expand Down Expand Up @@ -46,6 +52,7 @@ def __init__(
)
)
self._pid = os.getpid()
self._name = name
self._allowed_users = []
self._api_key = ""

Expand All @@ -68,20 +75,78 @@ def init(
self._api_key = keyring.get_password(
self._config["namespace"], self._config["api"]
)
self._bot = telepot.Bot(self._api_key)
MessageLoop(self._bot, self._handle).run_as_thread()
# Create the Application and pass it your bot's token.
self.application = Application.builder().token(self._api_key).build()
# on different commands - answer in Telegram
self.application.add_handler(
CommandHandler(
command="status",
callback=self._check_status,
filters=filters.Chat(self._allowed_users),
)
)
self.application.add_handler(
CommandHandler(
command="pump",
callback=self._toggle_pump,
filters=filters.Chat(self._allowed_users),
)
)
self.application.add_handler(
CommandHandler(
command="valve1",
callback=partial(self._toggle_valve, valve_number=1),
filters=filters.Chat(self._allowed_users),
)
)
self.application.add_handler(
CommandHandler(
command="valve2",
callback=partial(self._toggle_valve, valve_number=2),
filters=filters.Chat(self._allowed_users),
)
)
self.application.add_handler(
CommandHandler(
command="valve3",
callback=partial(self._toggle_valve, valve_number=3),
filters=filters.Chat(self._allowed_users),
)
)
self.application.add_handler(
CommandHandler(
command="holidays",
callback=self._toggle_holidays,
filters=filters.Chat(self._allowed_users),
)
)
# on non command i.e message - echo the message on Telegram
self.application.add_handler(
MessageHandler(filters.TEXT & ~filters.COMMAND, None)
)
# Step log runninng al 200ms
context = CallbackContext(self.application)
context.job_queue.run_repeating(callback=self.step_log, interval=0.2)
# logging info
print(f"'{self._name}' - {self._pid} successfully initialized")
self.telegram_queue.put(
f"Process {self._pid} - '{self._name}' successfully initialized"
)
# Run the bot until the user presses Ctrl-C
self.application.run_polling(allowed_updates=Update.ALL_TYPES)
except Exception as error:
print(f"Process {self._pid} - " + repr(error))
success = False
return success

def step_log(self) -> None:
# update: Update, context: ContextTypes.DEFAULT_TYPE
async def step_log(self, context: CallbackContext) -> None:
"""
This methods will check the queue and log the messages from other processes to self.logging_chat_id
"""
try:
msg = self.telegram_queue.get_nowait()
self._bot.sendMessage(self.logging_chat_id, f"{msg}")
await context.bot.send_message(chat_id=self.logging_chat_id, text=msg)
except queue.Empty:
pass

Expand All @@ -96,87 +161,60 @@ def _get_allowed_users(self, **kwargs):
)
return allowed

def _handle(self, msg):
"""
Function that handles the telegram telepot received messages
"""
chat_id = msg["chat"]["id"]
command = msg["text"]
if "@" in command: # to fix messages inside groups
command = command.split("@")[0]
if chat_id in self._allowed_users:
print(f"Received command {command}")
if command == "/random":
self._bot.sendMessage(chat_id, random.randint(1, 6))
elif command == "/date":
self._bot.sendMessage(chat_id, str(datetime.datetime.now()))
elif command == "/photo":
self._bot.sendPhoto(
chat_id,
"https://sklad500.ru/wp-content/uploads/2019/09/teleport02-1000x526.jpeg",
)
elif command == "/status":
self._check_status(chat_id)
elif command == "/pump":
self._toggle_pump(chat_id)
elif command == "/valve1":
self._toggle_valve(chat_id, 1)
elif command == "/valve2":
self._toggle_valve(chat_id, 2)
elif command == "/valve3":
self._toggle_valve(chat_id, 3)
elif command == "/holidays":
self._toggle_holidays(chat_id)

def _check_status(self, chat_id):
async def _check_status(
self, update: Update, context: ContextTypes.DEFAULT_TYPE
) -> None:
"""
This method sends to the bot the system status data
"""
self.system_status_lock.acquire()
info = self.system_status_proxy._getvalue()
self.system_status_lock.release()
self._bot.sendMessage(chat_id, "*__System Status__*", parse_mode="MarkdownV2")
await update.message.reply_markdown("*System Status*")
for key in info:
self._bot.sendMessage(chat_id, f"{key}: {info[key]}")
await update.message.reply_text(f"{key}: {info[key]}")

def _toggle_pump(self, chat_id):
async def _toggle_pump(
self, update: Update, context: ContextTypes.DEFAULT_TYPE
) -> None:
"""
This method toggle the value of the pump
"""
self.system_status_lock.acquire()
self.system_status_proxy["waterpump"] = int(
not self.system_status_proxy["waterpump"]
)
self._bot.sendMessage(
chat_id,
f"{__name__.split('.')[-1]}: Request Pump Status to {self.system_status_proxy['waterpump']}",
await update.message.reply_text(
f"{__name__.split('.')[-1]}: Request Pump Status to {self.system_status_proxy['waterpump']}"
)
self.system_status_lock.release()

def _toggle_valve(self, chat_id, valve_number):
async def _toggle_valve(
self, update: Update, context: ContextTypes.DEFAULT_TYPE, valve_number
) -> None:
"""
This method toggle the value of the valves 1, 2, 3
"""
self.system_status_lock.acquire()
self.system_status_proxy[f"valve{valve_number}"] = int(
not self.system_status_proxy[f"valve{valve_number}"]
)
self._bot.sendMessage(
chat_id,
f"{__name__.split('.')[-1]}: Request Valve {valve_number} Status to {self.system_status_proxy[f'valve{valve_number}']}",
await update.message.reply_text(
f"{__name__.split('.')[-1]}: Request Valve {valve_number} Status to {self.system_status_proxy[f'valve{valve_number}']}"
)
self.system_status_lock.release()

def _toggle_holidays(self, chat_id):
async def _toggle_holidays(
self, update: Update, context: ContextTypes.DEFAULT_TYPE
) -> None:
"""
This method toggle the value of the holidays mode
"""
self.system_status_lock.acquire()
self.system_status_proxy["holidays"] = int(
not self.system_status_proxy["holidays"]
)
self._bot.sendMessage(
chat_id,
f"{__name__.split('.')[-1]}: Request Holidays Mode to {self.system_status_proxy['holidays']}",
await update.message.reply_text(
f"{__name__.split('.')[-1]}: Request Holidays Mode to {self.system_status_proxy['holidays']}"
)
self.system_status_lock.release()
2 changes: 1 addition & 1 deletion draco/processors/GPIO_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def run(self) -> None:
sleep(0.1)
print(f"'{self._name}' - {pid} successfully initialized")
self.telegram_queue.put(
f"Process {pid} \- '{self._name}' successfully initialized"
f"Process {pid} - '{self._name}' successfully initialized"
)
while True:
# Update GPIO values
Expand Down
2 changes: 1 addition & 1 deletion draco/processors/system_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def run(self) -> None:
sleep(0.2)
print(f"'{self._name}' - {pid} successfully initialized")
self.telegram_queue.put(
f"Process {pid} \- '{self._name}' successfully initialized"
f"Process {pid} - '{self._name}' successfully initialized"
)
while True:
# Update scheduler
Expand Down
12 changes: 2 additions & 10 deletions draco/processors/telegram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,9 @@ def run(self) -> None:
telegram_queue=self.telegram_queue,
name=self._name,
)
while not success:
success = teleti.init()
sleep(0.5)
print(f"telegram bot '{self._name}' - {pid} successfully initialized")
self.telegram_queue.put(
f"Process {pid} \- telegram bot '{self._name}' successfully initialized"
)
while True:
# Log to telegram
teleti.step_log()
sleep(0.2)
# In this case, it wont termine the execution of init, it will be an infinite loop with asyncio functionalities
success = teleti.init()

except Exception as error:
print(f"Process {pid} - " + repr(error))
Expand Down
3 changes: 2 additions & 1 deletion requirements/requirements.txt → requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ adafruit-circuitpython-dht==4.0.2
RPi.GPIO==0.7.1
dbus-python==1.3.2; sys_platform == "linux"
keyring==24.2.0
telepot==12.7
python-telegram-bot[job-queue]==20.4
schedule==1.2.0
black==23.3.0

0 comments on commit 4c08fa1

Please sign in to comment.