Telegram bot api how to schedule a notification? - python

I've made a bot that gets today football matches and if the user wants he can get a reminder 10 min before a selected match.
while current_time != new_hour:
now = datetime.now()
current_time = now.strftime("%H:%M")
#return notification
text_caps = "Your match starts in 10 minutes"
context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps)
Obviously while the loop runs i can not use another command . I am new to programming how could i implement this so i still get the notification but while that runs i can use other commands?
Thank you!

Try to use an aiogram and you can make scheduled tasks with aiocron (store users who wants to get notification in database or in global dict)

You can schedule a job.
Let's say you have a CommandHandler("watch_match", watch_match) that listens for a /watch_match conmmand and 10 minutes later a message is supposed to arrive
def watch_match(update: Update, context: CallbackContext):
chat_id = update.effective_chat.id
ten_minutes = 60 * 10 # 10 minutes in seconds
context.job_queue.run_once(callback=send_match_info, when=ten_minutes, context=chat_id)
# Whatever you pass here as context is available in the job.context variable of the callback
def send_match_info(context: CallbackContext):
chat_id = context.job.context
context.bot.send_message(chat_id=chat_id, text="Yay")
A more detailed example in the official repository
And in the official documentation you can see the run_once function

Related

telegram bot in python for sending files doesnt work, but I dont know why [duplicate]

Hi i want to send message from bot in specific time (without message from me), for example every Saturday morning at 8:00am.
Here is my code:
import telebot
import config
from datetime import time, date, datetime
bot = telebot.TeleBot(config.bot_token)
chat_id=config.my_id
#bot.message_handler(commands=['start', 'help'])
def print_hi(message):
bot.send_message(message.chat.id, 'Hi!')
#bot.message_handler(func=lambda message: False) #cause there is no message
def saturday_message():
now = datetime.now()
if (now.date().weekday() == 5) and (now.time() == time(8,0)):
bot.send_message(chat_id, 'Wake up!')
bot.polling(none_stop=True)
But ofc that's not working.
Tried with
urlopen("https://api.telegram.org/bot" +bot_id+ "/sendMessage?chat_id=" +chat_id+ "&text="+msg)
but again no result. Have no idea what to do, help please with advice.
I had this same issue and I was able to solve it using the schedule library. I always find examples are the easiest way:
import schedule
import telebot
from threading import Thread
from time import sleep
TOKEN = "Some Token"
bot = telebot.TeleBot(TOKEN)
some_id = 12345 # This is our chat id.
def schedule_checker():
while True:
schedule.run_pending()
sleep(1)
def function_to_run():
return bot.send_message(some_id, "This is a message to send.")
if __name__ == "__main__":
# Create the job in schedule.
schedule.every().saturday.at("07:00").do(function_to_run)
# Spin up a thread to run the schedule check so it doesn't block your bot.
# This will take the function schedule_checker which will check every second
# to see if the scheduled job needs to be ran.
Thread(target=schedule_checker).start()
# And then of course, start your server.
server.run(host="0.0.0.0", port=int(os.environ.get('PORT', 5000)))
I hope you find this useful, solved the problem for me :).
You could manage the task with cron/at or similar.
Make a script, maybe called alarm_telegram.py.
#!/usr/bin/env python
import telebot
import config
bot = telebot.TeleBot(config.bot_token)
chat_id=config.my_id
bot.send_message(chat_id, 'Wake up!')
Then program in cron like this.
00 8 * * 6 /path/to/your/script/alarm_telegram.py
Happy Coding!!!
If you want your bot to both schedule a message and also get commands from typing something inside, you need to put Thread in a specific position (took me a while to understand how I can make both polling and threading to work at the same time).
By the way, I am using another library here, but it would also work nicely with schedule library.
import telebot
from apscheduler.schedulers.blocking import BlockingScheduler
from threading import Thread
def run_scheduled_task():
print("I am running")
bot.send_message(some_id, "This is a message to send.")
scheduler = BlockingScheduler(timezone="Europe/Berlin") # You need to add a timezone, otherwise it will give you a warning
scheduler.add_job(run_scheduled_task, "cron", hour=22) # Runs every day at 22:00
def schedule_checker():
while True:
scheduler.start()
#bot.message_handler(commands=['start', 'help'])
def print_hi(message):
bot.send_message(message.chat.id, 'Hi!')
Thread(target=schedule_checker).start() # Notice that you refer to schedule_checker function which starts the job
bot.polling() # Also notice that you need to include polling to allow your bot to get commands from you. But it should happen AFTER threading!

Mongodb finding latest entry not updating after new insert

I am trying learning async programming by making a discord bot, and for the discord bot I am trying to create a bump reminder function.
My goal for the bump reminder function is to log the first bump, wait two hours, send the reminder message, then wait for a user to bump, validate the bump and log for the second bump, for every successful bump, the bump time will be logged into a mongodb database.
I will also need to design it so that if the bot restart itself, during anytime, it will send the bump reminder based on the most recent bump time that is logged in the mongodb database.
This is my bump reminder class:
https://gist.github.com/bensonchow123/02f321e182d2ce251ce8d08ceb88456e
A bump time out is 2 hours, and there is a bump check loop that is looped for every 10 seconds
#tasks.loop(seconds=10)
async def _bump_reminder(self):
if not self.waiting_bump:
bump_now = await self._check_bump()
if bump_now:
await self._send_reminder_message()
And for my question, the line if now > (last_bump_time + timedelta(hours=2)):doesn't seems to work, it will return true anyways, resulting in the bot keep sending the bump reminder message again and again.
The function to receive the time of last bump from the most recent sucessful bump insert is this:
async def _last_bump_time(self):
last_bump = bump_db.find_one(sort=[('$natural',ASCENDING)])
last_bump = last_bump["date"]
return datetime.strptime(last_bump,"%S:%M:%H:%d:%m:%Y:%z")
I think the reason that causes this is because in this last_bump_time function, this line last_bump = bump_db.find_one(sort=[('$natural',ASCENDING)]) which is used to find the most recent database insert, don't seem to update after a successful bump. resulting in the bot keep sending the reminder message as now is still > last bump time.
This is the function to find the current time
async def _now(self):
return datetime.now(timezone.utc)
The function that logs the successful bump into my database is this:
async def _log_successful_bump(self, bumper_id):
now = await self._now()
bumper = {"id": bumper_id, "date": now.strftime("%S:%M:%H:%d:%m:%Y:%z")}
bump_db.insert_one(bumper)
Example of a successful bump insert
_id
:
629385d8a441ee722cc76336
id
:
736933464292589568
date
:
"24:40:14:29:05:2022:+0000"

Pubsub from a Function published in the background?

The whole reason I use PubSub is in order to not make my Cloud Function to wait, so things happens auto. To publish a topic from a Function, the code Google Docs show is :
# Publishes a message to a Cloud Pub/Sub topic.
def publish(topic_name,message):
# Instantiates a Pub/Sub client
publisher = pubsub_v1.PublisherClient()
if not topic_name or not message:
return ('Missing "topic" and/or "message" parameter.', 400)
# References an existing topic
topic_path = publisher.topic_path(PROJECT_ID, topic_name)
message_json = json.dumps({
'data': {'message': message},
})
message_bytes = message_json.encode('utf-8')
# Publishes a message
try:
publish_future = publisher.publish(topic_path, data=message_bytes)
publish_future.result() # Verify the publish succeeded
return 'Message published.'
except Exception as e:
print(e)
return (e, 500)
Which means Function is waiting for respond, but i want my Function to spend 0 seconds on this. How can I publish and forget ? not wait for respond? (without more dependencies?)
As you can see from the comments in the code, it is waiting to make sure that the publish succeeded. It's not waiting for any sort of response from any of the subscribers on that topic. It's extremely important the code wait until the publish succeeds, otherwise the message might not actually be sent at all, and you risk losing that data entirely. This is because Cloud Functions terminates the code and locks down CPU and I/O after the function returns.
If you really want to risk it, you could try removing the call to result(), but I don't think it's a good idea if you want a reliable system.
You can schedule your functions to run at certain times of the day or every 'interval' time. In this example, this would go into your index.js file and deployed to your functions.
The code would run 'every minute' in the background. The error would simply return to your logs in google cloud console.
If you are using firestore and need to manage documents, you can make the function run on specific events like on document create or update etc..
https://firebase.google.com/docs/functions/firestore-events
EDIT: Not exactly sure if this example matches your use case but hope this example helps
exports.scheduledFx = functions.pubsub.schedule('every minute').onRun(async (context) => {
// Cron time string Description
// 30 * * * * Execute a command at 30 minutes past the hour, every hour.
// 0 13 * * 1 Execute a command at 1:00 p.m. UTC every Monday.
// */5 * * * * Execute a command every five minutes.
// 0 */2 * * * Execute a command every second hour, on the hour.
try {
//your code here
} catch (error) {
return error
}
})

Running a cron scheduler within a running thread

I'm writing a telegram bot and I want to schedule it to send an automated message every day at a specific timing, cron style. I am using apscheduler to do it but I could not get the cron function to work. The interval scheduling works fine but it is not what I want.
I don't want to execute the .py file outside because I need the telegram bot to detect user's /start message.
So what I wanted to do was to detect user's /start message and then start the scheduler. Thereafter, the bot will send a message to the user everyday 8pm night.
Cron scheduling doesn't start and I don't know why. I suspect it is because it can't run within the main thread that I am running? Any advice would be helpful! Thank you.
import time
import telepot
import json
from telepot.loop import MessageLoop
from telepot.namedtuple import ReplyKeyboardMarkup # for custom keyboard
from telepot.delegate import pave_event_space, per_chat_id, create_open
from apscheduler.schedulers.blocking import BlockingScheduler
## Load token
TOKEN = 'TOKEN NUMBER'
# The main body
class main(telepot.helper.ChatHandler): # Implement continuous dialogue with user using DelegatorBot
global counter1
counter1 = 0
global counter2
counter2 = 0
def __init__(self, *args, **kwargs):
super(main, self).__init__(*args, **kwargs)
# Initialize and create empty dictionary for storing data.
self.indicator = '0'
self.data = {} # initialize an empty dictionary for storing data.
def on_chat_message(self, msg):
content_type, chat_type, chat_id = telepot.glance(msg) # this is very important.
# Debugging
print(content_type, chat_type, chat_id)
print(msg['text'])
global counter1
global counter2
scheduler = BackgroundScheduler()
#scheduler_cron = BlockingScheduler()
# Survey function
def survey():...
return
def repeat_message():
bot.sendMessage(chat_id, text='type /survey to repeat survey.')
print("Reminder sent.")
scheduler_cron.add_job(repeat_message, 'cron', day='*', week='*', day_of_week='*', hour=20, minute=00)
# Detect start messages.
while True:
if counter2 == 11: # If survey ends AKA 11 Qns done. Restart the counters.
counter1 = 0
counter2 = 0
# once bot starts, ask user to repeat survey at a specific time of the day.
if counter1 == 0: # If survey ends or at the very beginning of using the bot.
# Start message.
if msg['text'] == '/start': # /starts initiates bot. User gets greeted with a welcome message describing what the bot will do.
bot.sendMessage(chat_id,
text='Hello there.',
parse_mode='Markdown')
scheduler_cron.start()
print("Scheduler started.")
# Start survey after initializing the bot
elif msg['text'] == '/survey': # /survey initiates survey.
print("Survey started...")
#counter1 = 0
counter1 += 1
else:
bot.sendMessage(chat_id, text='I do not recognise your message.')
msg['text'] = '' # resets msg.
# User starts survey
if counter1 == 1: # if user types /survey, counter1 +=1 and when counter1 == 1, run survey function.
survey() # starts survey
counter2 += 1
break
bot = telepot.DelegatorBot(TOKEN, [pave_event_space()(per_chat_id(), create_open, main, timeout=60),])
MessageLoop(bot).run_as_thread() # Initiates the bot on telegram. Listens for user's response. If this is stopped, the entire bot stops.
print('Listening...')
while True:
time.sleep(1)
EDIT: I found out that apscheduler's cron does not work if I have another thread running in the background as stated in their documents:
BlockingScheduler: use when the scheduler is the only thing running in your process
BackgroundScheduler: use when you’re not using any of the frameworks below, and want the scheduler to run in the background inside your application
So it means I can't use apscheduler to make my bot work. Anyone know of any cron-like alternatives that allows me to schedule my telegram bot to fire message to users at specific timings of the day? Preferably, it has to be something that works with the telegram API.

how to schedule a telegram bot to send a message?

I am trying to create a Telegram bot that sends a message at a specific time, 5:30pm. However, the ways a was trying are not correct.
I wanted to trigger send_message regarding to the time and without the necessity of the user to send any /command.
import telebot
import datetime
TOKEN = 'MyToken'
bot = telebot.TeleBot(TOKEN)
#bot.message_handler(commands=['start'])
def send_welcome(message):
message_id=message.chat.id
bot.reply_to(message,"Welcome")
bot.polling()
Until now I was trying to add something like that, of course it is not python but kind of pseudocode just to explain:
if currenttime=17:30
send_message(idchat, "mymessage")
Thank you in advance.
If I understand correctly, you need to check your system time before sending a message, you could use the following code [source]:
from datetime import datetime
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Current Time =", current_time)
To send a message you could use the following code [source]:
def test_send_message():
text = 'CI Test Message'
tb = telebot.TeleBot(TOKEN)
ret_msg = tb.send_message(CHAT_ID, text)
assert ret_msg.message_id
To compare the time, you may use:
if current_time=='17:30:00':
test_send_message()
You can use schedule python library.
First of all import the necessary modules
import schedule
import time
import telegram
Then you have to create a function that will repeat in every x time.
Here the bot will send me message in every 5 seconds.
TOKEN='your_token'
bot = telegram.Bot(token=TOKEN)
def job():
bot.sendMessage(chat_id=<chat_id>, text="Hello")
schedule.every(5).seconds.do(job)
while True:
schedule.run_pending()
time.sleep(1)
For more informations about schedule Read the documentation

Categories

Resources