I'm trying to make a telegram bot that will interface with an IoT system i'm developing. Actually i'm stuck in programming the python telegram bot; her's my problem: inside the bot's chat the user is able recall the InlineKeyboardButtons to turn on/off a light or set a timer. When the user choose "timer" buttone i would like to open another InlineKeyboardButtons to make the user select other parameters but with my current code i'm not able to to this beacuse the code jumps to the "callback handler". Any suggestion? I'll post the whole code:
from MyMQTT import *
import time
from datetime import datetime, timedelta
import json
import requests
import random
import telepot
from telepot.loop import MessageLoop
from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup
test=1
class tg_pub(object):
def __init__(self, clientID, broker, port, topic):
self.clientID = clientID
# self.topic = str(topic)
# self.topic = '/'.join([self.topic])
self.client = MyMQTT(clientID, broker, port, self)
self.__message = {
"bn": "TelegramBot",
"ip": "",
"e": [
{
"n": "lights_command",
"u": "boolean",
"t": "2021-04-15 16:59:12.586822",
"v": "ON"
},
{
"n": "conditioner_command",
"u": "boolean",
"t": "2021-04-15 16:59:12.586822",
"v": "OFF"
}
]
}
def sendData(self, topic, output):
message = self.__message
message['e'][0]['v'] = output
message['e'][0]['t'] = str(datetime.now())
self.client.myPublish(topic, message)
def start(self):
self.client.start()
def stop(self):
self.client.stop()
class Room_Bot:
def __init__(self, token, broker, port, topic):
# the bot token is to be saved in the Catalog !!!!
self.tokenBot = token # local token
# self.tokenBot = requests.get("http://catalogIP/telegram_token").json()["telegramToken"] # Catalog token
self.bot= telepot.Bot(self.tokenBot)
self.client = MyMQTT("telegramBot", broker, port, None) # to be a publisher
self.client.start()
self.topic = topic
self.__message={
"bn": "TelegramBot",
"ip": "",
"e": [
{
"n": "lights_command",
"u": "boolean",
"t": "2021-04-15 16:59:12.586822",
"v": "ON"
},
{
"n": "conditioner_command",
"u": "boolean",
"t": "2021-04-15 16:59:12.586822",
"v": "OFF"
}
]
}
### USING MESSAGES ###
# MessageLoop(self.bot,{'chat': self.on_chat_message}).run_as_thread()
### USING BUTTONS -> query callback ###
MessageLoop(self.bot, {'chat': self.on_chat_message, 'callback_query': self.on_callback_query}).run_as_thread()
def sendMessage(self, topic):
message=self.__message
message['e'][0]['v']=random.randint(0,1) # 0 = no movement detected
message['e'][0]['t']=str(datetime.now())
self.client.myPublish(topic, message)
def start (self):
self.client.start()
def stop (self):
self.client.stop()
#HANDLING THE MESSAGES
def on_chat_message(self, msg):
content_type, chat_type ,chat_ID = telepot.glance(msg)
message = msg['text'] #retrieve the message from the key 'text' in the json
### USING MESSAGES ###
# if message == "/switch_Lights_ON":
# payload = self.__message.copy()
# payload['e'][0]['v'] = "on"
# payload['e'][0]['t'] = str(datetime.now())
# self.client.myPublish(self.topic,payload)
# self.bot.sendMessage(chat_ID,text = "Lights switched on")
# else:
# self.bot.sendMessage(chat_ID, text="Command not supported")
## USING BUTTONS ###
if message == "/start":
#self.bot.sendMessage(chat_ID, text="Welcome, I am HioTel. Please press one of the available buttons to get started.")
keyboard = ReplyKeyboardMarkup(keyboard=[['Lights', 'Heater'], ['Status Info']])
self.bot.sendMessage(chat_ID, text='Welcome, I am HioTel. Please press one of the available buttons to get started.', reply_markup=keyboard)
elif message == "Lights":
#Matrix of buttons
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[
InlineKeyboardButton(text=f'Lights on ', callback_data=f'direct ON '),
InlineKeyboardButton(text=f'Lights off ⚫', callback_data=f'direct OFF')
],
[
InlineKeyboardButton(text=f'Set timer ⏲️', callback_data=f'light_timer',test=0)
]
])
self.bot.sendMessage(chat_ID, text='Lights menu:', reply_markup=keyboard) #REPLY TO USER
elif message == "Heater":
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[
InlineKeyboardButton(text=f'Heat on ', callback_data=f'heater_on'),
InlineKeyboardButton(text=f'Heat off ⚫', callback_data=f'heater_off')
],
[
InlineKeyboardButton(text=f'Heat up ☀️', callback_data=f'heat_up'),
InlineKeyboardButton(text=f'Heat down ❄️', callback_data=f'heat_down')
],
[
InlineKeyboardButton(text=f'Set timer ⏲️', callback_data=f'heater_timer')
]
])
self.bot.sendMessage(chat_ID, text='Heater menu:', reply_markup=keyboard)
elif message == "Status Info":
self.bot.sendMessage(chat_ID, text=' Lights: ON\n\n Air conditioner: ON, set on tot°\nCurrent room conditions:\n tot° - umidiccio')
else:
self.bot.sendMessage(chat_ID, text="Command not supported")
#HANDLING THE CALLBACKS
def on_callback_query(self, msg):
query_ID , chat_ID , query_data = telepot.glance(msg, flavor='callback_query')
payload = self.__message.copy()
#if query_data=="light_timer":
#keyboard = InlineKeyboardMarkup(inline_keyboard=[
#[
# InlineKeyboardButton(text=f'5 minutes', callback_data=f'durati ON 5'),
#InlineKeyboardButton(text=f'15 minutes', callback_data=f'durati ON 15')
#],
# [
# InlineKeyboardButton(text=f'30 minutes ', callback_data=f'durati ON 30')
#]
# ])
# self.bot.sendMessage(chat_ID, text='Set timer:', reply_markup=keyboard)
payload['e'][0]['v'] = query_data #SET AS MESSAGE WHAT USER SELECTED IN CHAT BUTTONS
payload['e'][0]['t'] = str(datetime.now())
self.client.myPublish(self.topic, payload) #PUBLISH MQTT MESSAGE
self.bot.sendMessage(chat_ID, text=f"{query_data}: done ✔") #FEEDBACK FOR THE USER
print(test)
if __name__ == '__main__':
url = "xxxxxx"
clientID = 'telegram'
settings = requests.post(url)
config = list(settings.json())
broker = config[0]["settings"][0]["broker"]
port = config[0]["settings"][0]["port"]
token = config[0]["settings"][0]["botToken"]
baseTopic = config[0]["settings"][0]["baseTopic"]
topic_pub_l = baseTopic + config[0]["settings"][0]["lightControlTopic"]
topic_pub_c = baseTopic + config[0]["settings"][0]["conditControlTopic"]
topic = baseTopic + topic_pub_l
pub_l = tg_pub(clientID, broker, port, topic_pub_l)
pub_l.start()
output = None
pub_l.sendData("hotel/catalog", output)
time.sleep(random.randint(1,10))
requests.post(url)
bot = Room_Bot(token,broker,port,topic)
while True:
time.sleep(2)
That's correct as pressing on any of the buttons (
InlineKeyboardButtons
) will trigger theCallbackHandler
which is responsible to process the response.One option is to refactor your code to create methods to send a given response, for example
You can invoke the new method (
send_lights
) from the CallbackHandler when the user presses a given button.A second option would be to have a single method which processes both messages and callbacks: I am not sure how you do that with
telepot
to be honest, but with PythonTelegramBot is possible: in this case you deal with all responses in the same place.