Skip to content

Commit 17a16c9

Browse files
committed
bot: use databases instead of PyMySQL
For consistency with the API. Also databases is natively async.
1 parent 75bb5a3 commit 17a16c9

File tree

2 files changed

+51
-85
lines changed

2 files changed

+51
-85
lines changed

WWCS/irrigation/telegramBot/bot.py

Lines changed: 49 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@
77
# Requirements
88
from apscheduler.schedulers.asyncio import AsyncIOScheduler
99
from apscheduler.triggers.interval import IntervalTrigger
10-
from dotenv import load_dotenv
10+
from databases import Database
1111
from telebot import types
1212
from telebot.async_telebot import AsyncTeleBot
13-
import pymysql
13+
import dotenv
1414

1515

1616
# Configuration
17-
load_dotenv()
17+
dotenv.load_dotenv()
1818
DB_USERNAME = os.environ.get('DB_USERNAME', 'wwcs')
1919
DB_PASSWORD = os.environ['DB_PASSWORD']
2020
BOT_TOKEN = os.environ['BOT_TOKEN']
2121
LANGUAGE = os.environ.get('LANGUAGE', 'en')
2222
TIMEZONE = os.environ.get('TIMEZONE') # Defaults to local timezone
2323

24+
# Database
25+
DATABASE_URL = f'mysql+asyncmy://{DB_USERNAME}:{DB_PASSWORD}@localhost:3306/WWCServices'
26+
database = Database(DATABASE_URL)
27+
2428
# Initialize gettext
2529
root = pathlib.Path(__file__).parent
2630
translation = gettext.translation(
@@ -97,35 +101,10 @@ async def remove_all_jobs(self, chat_id):
97101
22: 1.91,
98102
23: 2.13,
99103
24: 2.37,
100-
25: 2.63
104+
25: 2.63,
101105
}
102106

103107

104-
# Подключение к базе данных MySQL
105-
def get_db_connection():
106-
return pymysql.connect(
107-
host="localhost",
108-
user=DB_USERNAME,
109-
password=DB_PASSWORD,
110-
cursorclass=pymysql.cursors.DictCursor
111-
)
112-
113-
114-
async def execute_query(query, params=None):
115-
def sync_execute():
116-
connection = get_db_connection()
117-
try:
118-
with connection.cursor() as cursor:
119-
cursor.execute(query, params or ())
120-
result = cursor.fetchall()
121-
connection.commit()
122-
return result
123-
finally:
124-
connection.close()
125-
126-
return await asyncio.to_thread(sync_execute)
127-
128-
129108
async def get_irrigation_data():
130109
query = """
131110
SELECT
@@ -147,13 +126,13 @@ async def get_irrigation_data():
147126
WHERE s.irrigation = 1 AND i.PHIc < i.PHIt AND i.irrigationApp = 0
148127
AND i.date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
149128
"""
150-
return await execute_query(query)
129+
return await database.fetch_all(query=query)
151130

152131

153132
BUTTONS = {
154133
"send_recommendation": _("Send recommendation"),
155134
"no_water": _("No water"),
156-
"save_data": _("Save data")
135+
"save_data": _("Save data"),
157136
}
158137

159138

@@ -492,18 +471,16 @@ async def handle_send_data(message):
492471
area = float(row['area'])
493472
actual_mm = (data['total_used_m3'] * float(row['ie'])) / (10 * area * float(row['wa']))
494473

495-
await execute_query(
496-
"""UPDATE WWCServices.Irrigation
497-
SET irrigationApp = %s
498-
WHERE siteID = %s
499-
AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)""",
500-
(actual_mm, row['siteID'])
501-
)
502-
503-
await bot.send_message(
504-
chat_id,
505-
_("✅ Data saved! Used: {used_m3:.2f} m³").format(used_m3=data['total_used_m3'])
506-
)
474+
query = """
475+
UPDATE WWCServices.Irrigation SET irrigationApp = :actual_mm
476+
WHERE siteID = :siteID AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
477+
"""
478+
values = {'actual_mm': actual_mm, 'siteID': row['siteID']}
479+
await database.execute(query=query, values=values)
480+
481+
message = _("✅ Data saved! Used: {used_m3:.2f} m³").format(used_m3=data['total_used_m3'])
482+
await bot.send_message(chat_id, message)
483+
507484
data['is_active'] = False
508485
return
509486
except Exception as e:
@@ -521,7 +498,6 @@ async def handle_send_data(message):
521498
await bot.send_message(chat_id, _("❌ Your data was not found in the system"))
522499

523500

524-
525501
@bot.message_handler(func=lambda message: user_states.get(message.chat.id) == 'waiting_for_traditional_start')
526502
async def handle_traditional_start(message):
527503
chat_id = message.chat.id
@@ -539,8 +515,6 @@ async def handle_traditional_start(message):
539515
await bot.send_message(chat_id, _("⚠️ Type correct number (like 125.5)"))
540516

541517

542-
543-
544518
@bot.message_handler(func=lambda message: user_states.get(message.chat.id) == 'waiting_for_traditional_end')
545519
async def handle_traditional_end(message):
546520
chat_id = message.chat.id
@@ -566,23 +540,19 @@ async def handle_traditional_end(message):
566540
area = float(row['area'])
567541
actual_mm = (used_m3 * float(row['ie'])) / (10 * area * float(row['wa']))
568542

569-
await execute_query(
570-
"""UPDATE WWCServices.Irrigation
571-
SET irrigationApp = %s
572-
WHERE siteID = %s
573-
AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)""",
574-
(actual_mm, row['siteID'])
575-
)
543+
query = """
544+
UPDATE WWCServices.Irrigation SET irrigationApp = :actual_mm
545+
WHERE siteID = :siteID AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
546+
"""
547+
values = {'actual_mm': actual_mm, 'siteID': row['siteID']}
548+
await database.execute(query=query, values=values)
576549

577550
await bot.send_message(
578551
chat_id,
579552
_("✅ Data saved!\n"
580553
"Water used: {used_m3:.2f} m³\n"
581554
"Equivalent to: {actual_mm:.2f} mm"
582-
).format(
583-
used_m3=used_m3,
584-
actual_mm=actual_mm
585-
)
555+
).format(used_m3=used_m3, actual_mm=actual_mm)
586556
)
587557
break
588558

@@ -599,7 +569,6 @@ async def handle_traditional_end(message):
599569
del user_irrigation_data[chat_id]
600570

601571

602-
603572
@bot.message_handler(func=lambda message: user_states.get(message.chat.id) == 'waiting_for_counter_end')
604573
async def handle_counter_end(message):
605574
chat_id = message.chat.id
@@ -627,13 +596,12 @@ async def handle_counter_end(message):
627596
area = float(row['area'])
628597
actual_mm = (used_m3 * float(row['ie'])) / (10 * area * float(row['wa']))
629598

630-
await execute_query(
631-
"""UPDATE WWCServices.Irrigation
632-
SET irrigationApp = %s
633-
WHERE siteID = %s
634-
AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)""",
635-
(actual_mm, row['siteID'])
636-
)
599+
query = """
600+
UPDATE WWCServices.Irrigation SET irrigationApp = :actual_mm
601+
WHERE siteID = :siteID AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
602+
"""
603+
values = {'actual_mm': actual_mm, 'siteID': row['siteID']}
604+
await database.execute(query=query, values=values)
637605

638606
await bot.send_message(
639607
chat_id,
@@ -660,7 +628,6 @@ async def handle_counter_end(message):
660628
del user_irrigation_data[chat_id]
661629

662630

663-
664631
@bot.message_handler(func=lambda message: user_states.get(message.chat.id) == 'waiting_for_actual_data')
665632
async def handle_actual_data(message):
666633
chat_id = message.chat.id
@@ -673,13 +640,12 @@ async def handle_actual_data(message):
673640
area = float(row['area'])
674641
actual_mm = (actual_m3 * float(row['ie'])) / (10 * area * float(row['wa']))
675642

676-
await execute_query(
677-
"""UPDATE WWCServices.Irrigation
678-
SET irrigationApp = %s
679-
WHERE siteID = %s
680-
AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)""",
681-
(actual_mm, row['siteID'])
682-
)
643+
query = """
644+
UPDATE WWCServices.Irrigation SET irrigationApp = :actual_mm
645+
WHERE siteID = :siteID AND date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
646+
"""
647+
values = {'actual_mm': actual_mm, 'siteID': row['siteID']}
648+
await database.execute(query=query, values=values)
683649

684650
await bot.send_message(
685651
chat_id,
@@ -735,23 +701,22 @@ async def send_recommendation(chat_id, fieldtype, irrigation_need, area, ie, wa,
735701

736702

737703
async def main():
738-
# Очищаем старые задания при запуске
739-
for job in scheduler.get_jobs():
740-
job.remove()
741-
742-
scheduler.add_job(
743-
check_all_users,
744-
'cron',
745-
hour=7,
746-
minute=0, # Every day at 7 am
747-
timezone=TIMEZONE,
748-
)
704+
await database.connect()
705+
706+
# Clearing old tasks on startup
707+
# XXX Do we need this? It's AsyncIOScheduler so jobs should not persist
708+
scheduler.remove_all_jobs()
709+
710+
# Check irrigation for all users, every day at 7 am
711+
scheduler.add_job(check_all_users, 'cron', hour=7, minute=0, timezone=TIMEZONE)
749712
scheduler.start()
750713

714+
# Start bot
751715
try:
752716
await bot.polling()
753717
finally:
754718
scheduler.shutdown()
719+
await database.disconnect()
755720

756721

757722
if __name__ == "__main__":
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
aiohttp
22
APScheduler
3-
PyMySQL
3+
asyncmy
4+
databases
45
pyTelegramBotAPI
56
python-dotenv

0 commit comments

Comments
 (0)