1+ """
2+ Telegram bot.
3+
4+ Commands:
5+ /start
6+ """
7+
8+
19from datetime import datetime , timedelta
210import asyncio
311import gettext
412import os
513import pathlib
614
715# Requirements
16+ from apscheduler .jobstores .base import JobLookupError
817from apscheduler .schedulers .asyncio import AsyncIOScheduler
18+ from apscheduler .triggers .date import DateTrigger
919from apscheduler .triggers .interval import IntervalTrigger
1020from databases import Database
1121from telebot import types
3646_ = translation .gettext
3747
3848
49+ scheduler = AsyncIOScheduler ()
50+
3951class NotificationManager :
40- def __init__ (self ):
41- self .jobs = {}
4252
43- async def add_job (self , chat_id , job_type , func , * args , ** kwargs ):
44- await self .remove_job (chat_id , job_type )
45- job = scheduler .add_job (func , * args , ** kwargs )
46- self .jobs [f"{ job_type } _{ chat_id } " ] = job
47- return job
53+ def add_job (self , chat_id , job_type , func , trigger ):
54+ job_id = f"{ job_type } _{ chat_id } "
55+ self .remove_job (chat_id , job_type )
56+ scheduler .add_job (func , trigger , id = job_id , args = [chat_id ])
4857
49- async def remove_job (self , chat_id , job_type ):
58+ def remove_job (self , chat_id , job_type ):
5059 job_id = f"{ job_type } _{ chat_id } "
51- if job_id in self .jobs :
52- try :
53- self .jobs [job_id ].remove ()
54- except Exception as e :
55- print (f"Error deleting task { job_id } : { e } " )
56- finally :
57- self .jobs .pop (job_id , None )
60+ try :
61+ scheduler .remove_job (job_id )
62+ except JobLookupError :
63+ pass
5864
59- async def remove_all_jobs (self , chat_id ):
65+ def remove_all_jobs (self , chat_id ):
6066 for job_type in ['water_check' , 'polyv_complete' ]:
61- await self .remove_job (chat_id , job_type )
67+ self .remove_job (chat_id , job_type )
6268
6369
6470notification_manager = NotificationManager ()
6571
6672
67-
68-
6973# Инициализация бота
7074bot = AsyncTeleBot (BOT_TOKEN )
71- scheduler = AsyncIOScheduler ()
7275
7376# Словари для хранения состояний
7477user_states = {}
7578user_irrigation_data = {} # Для хранения данных о поливе
76- notification_jobs = {} # Для хранения задач уведомлений
7779
7880# Таблица расхода воды (уровень в см -> расход в м³/мин)
7981WATER_FLOW_RATES = {
@@ -147,44 +149,29 @@ def create_reply_keyboard():
147149 return markup
148150
149151
150- async def start_irrigation_notifications (chat_id ):
151- await notification_manager .add_job (
152- chat_id ,
153- 'water_check' ,
154- send_water_check_notification ,
155- trigger = IntervalTrigger (minutes = 15 ),
156- args = [chat_id ]
157- )
152+ def start_irrigation_notifications (chat_id ):
153+ notification_manager .add_job (chat_id , 'water_check' , send_water_check_notification ,
154+ trigger = IntervalTrigger (minutes = 15 ))
158155
159156
160157async def send_water_check_notification (chat_id ):
161158 """Отправляет уведомление о проверке уровня воды"""
162159 if chat_id in user_irrigation_data :
163- await bot .send_message (
164- chat_id ,
165- _ ("🔄 Please check the current water level in the channel and send its value" )
166- )
160+ message = _ ("🔄 Please check the current water level in the channel and send its value" )
161+ await bot .send_message (chat_id , message )
167162
168163
169- async def schedule_polyv_completion_notification (chat_id , hours , minutes ):
164+ def schedule_polyv_completion_notification (chat_id , hours , minutes ):
170165 completion_time = datetime .now () + timedelta (hours = hours , minutes = minutes )
171- await notification_manager .add_job (
172- chat_id ,
173- 'polyv_complete' ,
174- notify_polyv_completion ,
175- trigger = 'date' ,
176- run_date = completion_time ,
177- args = [chat_id ]
178- )
166+ notification_manager .add_job (chat_id , 'polyv_complete' , notify_polyv_completion ,
167+ trigger = DateTrigger (run_date = completion_time ))
179168
180169
181170async def notify_polyv_completion (chat_id ):
182171 if chat_id in user_irrigation_data and user_irrigation_data [chat_id ].get ('is_active' , False ):
183- await bot .send_message (
184- chat_id ,
185- _ ("⏰ Watering time is over! Please click the 'Save data' button to save the results." )
186- )
187- await notification_manager .remove_job (chat_id , 'water_check' )
172+ message = _ ("⏰ Watering time is over! Please click the 'Save data' button to save the results." )
173+ await bot .send_message (chat_id , message )
174+ notification_manager .remove_job (chat_id , 'water_check' )
188175
189176
190177async def check_irrigation (chat_id ):
@@ -216,15 +203,10 @@ async def check_irrigation(chat_id):
216203 )
217204
218205 else :
219- text = _ (
220- "ERROR!"
221- )
206+ text = _ ("ERROR!" )
222207
223- await bot .send_message (
224- chat_id ,
225- text .format (first_name = row ['firstName' ], water = round (m3_needed , 2 )),
226- reply_markup = markup
227- )
208+ message = text .format (first_name = row ['firstName' ], water = round (m3_needed , 2 ))
209+ await bot .send_message (chat_id , message , reply_markup = markup )
228210 return True
229211 return False
230212
@@ -253,11 +235,11 @@ async def calculate_irrigation(chat_id, water_level, irrigation_need, area, ie,
253235 'total_needed_m3' : total_needed_m3 ,
254236 'total_used_m3' : 0 ,
255237 'history' : [(water_level , datetime .now ())],
256- 'is_active' : True
238+ 'is_active' : True ,
257239 }
258240
259- # Запускаем уведомления только для нового полива
260- await start_irrigation_notifications (chat_id )
241+ # We launch notifications only for new watering
242+ start_irrigation_notifications (chat_id )
261243 else :
262244 data = user_irrigation_data [chat_id ]
263245 time_elapsed = (datetime .now () - data ['last_update' ]).total_seconds ()
@@ -278,13 +260,13 @@ async def calculate_irrigation(chat_id, water_level, irrigation_need, area, ie,
278260 if remaining_time > 0 :
279261 hours = int (remaining_time )
280262 minutes = int ((remaining_time - hours ) * 60 )
281- await schedule_polyv_completion_notification (chat_id , hours , minutes )
263+ schedule_polyv_completion_notification (chat_id , hours , minutes )
282264
283265 return {
284266 'used_m3' : user_irrigation_data [chat_id ]['total_used_m3' ],
285267 'remaining_m3' : remaining_m3 ,
286268 'remaining_time' : remaining_time ,
287- 'is_completed' : remaining_m3 <= 0
269+ 'is_completed' : remaining_m3 <= 0 ,
288270 }
289271
290272
@@ -303,7 +285,7 @@ async def handle_recommendation(message):
303285 if str (chat_id ) == str (row ['telegramID' ]):
304286 if row ['type' ] == "channel" :
305287 user_states [chat_id ] = "waiting_for_water_level"
306- await bot .send_message (chat_id , _ ("Enter the current water level in the channel (in cm):" ))
288+ await bot .send_message (chat_id , _ ("Enter the current water level in the channel (in cm):" ))
307289
308290 elif row ['type' ] == "counter" :
309291 user_states [chat_id ] = "waiting_for_counter_start"
@@ -348,7 +330,7 @@ async def handle_counter_start(message):
348330 'start_counter' : start_counter ,
349331 'target_counter' : target_counter ,
350332 'is_active' : True ,
351- 'last_update' : datetime .now ()
333+ 'last_update' : datetime .now (),
352334 }
353335 user_states [chat_id ] = None
354336 return
@@ -381,7 +363,7 @@ async def handle_water_level(message):
381363 float (row ['irrigationNeed' ]),
382364 float (row ['area' ]),
383365 float (row ['ie' ]),
384- float (row ['wa' ])
366+ float (row ['wa' ]),
385367 )
386368
387369 if calculation ['is_completed' ]:
@@ -399,7 +381,7 @@ async def handle_water_level(message):
399381 hours = hours ,
400382 minutes = minutes ,
401383 used_m3 = calculation ['used_m3' ],
402- total_m3 = calculation ['used_m3' ] + calculation ['remaining_m3' ]
384+ total_m3 = calculation ['used_m3' ] + calculation ['remaining_m3' ],
403385 )
404386
405387 await bot .send_message (chat_id , msg )
@@ -410,13 +392,12 @@ async def handle_water_level(message):
410392 await bot .send_message (chat_id , _ ("⚠️ Please enter a valid number (water level in cm)" ))
411393
412394
413-
414395@bot .message_handler (func = lambda message : message .text == BUTTONS ["save_data" ])
415396async def handle_send_data (message ):
416397 chat_id = message .chat .id
417398
418- # Останавливаем все уведомления
419- await notification_manager .remove_all_jobs (chat_id )
399+ # Stop all notifications
400+ notification_manager .remove_all_jobs (chat_id )
420401
421402 rows = await get_irrigation_data ()
422403 for row in rows :
0 commit comments