Adjusted bot functions for new backend

This commit is contained in:
Remy Moll 2022-01-01 22:41:54 +01:00
parent 1c5092065b
commit 621c8cf6e3
11 changed files with 87 additions and 107 deletions

View File

@ -6,7 +6,8 @@ logger = logging.getLogger(__name__)
class WeatherFetch(): class WeatherFetch():
def __init__(self, key): def __init__(self, key):
self.last_fetch = datetime.datetime.fromtimestamp(0) self.last_fetch = datetime.datetime.fromtimestamp(0)
self.last_weather = "" self.last_fetch_location = []
self.last_weather = []
self.calls = 0 self.calls = 0
self.url = "https://api.openweathermap.org/data/2.5/onecall?" self.url = "https://api.openweathermap.org/data/2.5/onecall?"
@ -14,8 +15,10 @@ class WeatherFetch():
def show_weather(self, location): def show_weather(self, location):
delta = datetime.datetime.now() - self.last_fetch delta = datetime.datetime.now() - self.last_fetch
if delta.total_seconds()/60 > 60 or "\n" not in self.last_weather: # 1 hour passed: # 1 hour passed, error, or location change
if delta.total_seconds() > 3600 \
or len(self.last_weather) == 0\
or self.last_fetch_location != location:
data = {"lat" : location[0], "lon" : location[1], "exclude" : "minutely,hourly", "appid" : self.key, "units" : "metric"} data = {"lat" : location[0], "lon" : location[1], "exclude" : "minutely,hourly", "appid" : self.key, "units" : "metric"}
self.calls += 1 self.calls += 1
@ -35,11 +38,12 @@ class WeatherFetch():
"short" : day["weather"][0]["main"], "short" : day["weather"][0]["main"],
"temps" : [int(day["temp"]["min"]),int(day["temp"]["max"])] "temps" : [int(day["temp"]["min"]),int(day["temp"]["max"])]
}) })
except:
ret_weather = []
self.last_fetch_location = location
self.last_weather = ret_weather self.last_weather = ret_weather
self.last_fetch = datetime.datetime.now() self.last_fetch = datetime.datetime.now()
except:
ret_weather = []
else: else:
ret_weather = self.last_weather ret_weather = self.last_weather

View File

@ -6,9 +6,10 @@ NAME, NEW, ACTION, ITEMADD, ITEMREMOVE = range(5)
class Lists(BotFunc): class Lists(BotFunc):
"""Create and edit lists""" """Create and edit lists"""
def __init__(self, db): def __init__(self, db_utils):
super().__init__(db) super().__init__(db_utils)
self.current_name = "" self.current_name = ""
# self.db_utils set through super()
def create_handler(self): def create_handler(self):
@ -38,10 +39,8 @@ class Lists(BotFunc):
def entry_point(self, update: Update, context: CallbackContext) -> None: def entry_point(self, update: Update, context: CallbackContext) -> None:
super().entry_point(update, context) super().entry_point(update, context)
# TODO Change DB lists = self.db_utils.list_get()
lists = self.db.lists.select() keyboard = [[InlineKeyboardButton(k, callback_data="list-"+k)] for k in lists] + [[InlineKeyboardButton("New list", callback_data="new")]]
sl = [l.name for l in lists]
keyboard = [[InlineKeyboardButton(k, callback_data="list-"+k)] for k in sl] + [[InlineKeyboardButton("New list", callback_data="new")]]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
super().log_activity(read=True, execute=False, send=True) super().log_activity(read=True, execute=False, send=True)
@ -96,12 +95,12 @@ class Lists(BotFunc):
def new_listname(self, update: Update, context: CallbackContext) -> None: def new_listname(self, update: Update, context: CallbackContext) -> None:
name = update.message.text name = update.message.text
try: try:
data = self.db.lists(name=name, content="") self.db_utils.list_create(name)
data.save()
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("To the menu!", callback_data="overview")]] keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("To the menu!", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
self.current_name = name self.current_name = name
update.message.reply_text("Thanks. List " + name + " was successfully created.", reply_markup=reply_markup) update.message.reply_text("Thanks. List " + name + " was successfully created.", reply_markup=reply_markup)
super().log_activity(read=False, execute=True, send=True)
return ACTION return ACTION
except Exception as e: except Exception as e:
update.message.reply_text("Oh no! Encountered exception: {}".format(e)) update.message.reply_text("Oh no! Encountered exception: {}".format(e))
@ -118,8 +117,7 @@ class Lists(BotFunc):
def list_remove(self, update: Update, context: CallbackContext) -> None: def list_remove(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query query = update.callback_query
query.answer() query.answer()
it = self.db.lists.get(self.db.lists.name == self.current_name) sl = self.db_utils.list_get(self.current_name)
sl = it.content.split("<-->")
keyboard = [[InlineKeyboardButton(k, callback_data=i)] for i,k in enumerate(sl)] keyboard = [[InlineKeyboardButton(k, callback_data=i)] for i,k in enumerate(sl)]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
@ -131,7 +129,7 @@ class Lists(BotFunc):
def list_clear(self, update: Update, context: CallbackContext) -> None: def list_clear(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query query = update.callback_query
query.answer() query.answer()
self.db.lists.update(content="").where(self.db.lists.name == self.current_name).execute() self.db_utils.list_update(self.current_name, replace=[])
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]] keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text("List " + self.current_name + " cleared", reply_markup=reply_markup) query.edit_message_text("List " + self.current_name + " cleared", reply_markup=reply_markup)
@ -141,7 +139,7 @@ class Lists(BotFunc):
def list_delete(self, update: Update, context: CallbackContext) -> None: def list_delete(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query query = update.callback_query
query.answer() query.answer()
self.db.lists.delete().where(self.db.lists.name == self.current_name).execute() self.db_utils.list_delete(self.current_name)
query.edit_message_text("List " + self.current_name + " deleted") query.edit_message_text("List " + self.current_name + " deleted")
return ConversationHandler.END return ConversationHandler.END
@ -149,10 +147,9 @@ class Lists(BotFunc):
def list_print(self, update: Update, context: CallbackContext) -> None: def list_print(self, update: Update, context: CallbackContext) -> None:
query = update.callback_query query = update.callback_query
query.answer() query.answer()
it = self.db.lists.get(self.db.lists.name == self.current_name) it = self.db_utils.list_get(self.current_name)
if it: if it:
content = it.content.split("<-->") content = "\n".join(it)
content = "\n".join(content)
else: else:
content = "List empty" content = "List empty"
@ -164,14 +161,7 @@ class Lists(BotFunc):
def list_add_item(self, update: Update, context: CallbackContext) -> None: def list_add_item(self, update: Update, context: CallbackContext) -> None:
item = update.message.text item = update.message.text
it = self.db.lists.get(self.db.lists.name == self.current_name) self.db_utils.list_update(self.current_name, append=item)
if it:
sl = it.content
else:
sl = ""
sl += item + "<-->"
self.db.lists.update(content=sl).where(self.db.lists.name == self.current_name).execute()
keyboard = [[InlineKeyboardButton("Add some more", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]] keyboard = [[InlineKeyboardButton("Add some more", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("Added " + item, reply_markup=reply_markup) update.message.reply_text("Added " + item, reply_markup=reply_markup)
@ -183,13 +173,9 @@ class Lists(BotFunc):
ind = int(query.data) ind = int(query.data)
query.answer() query.answer()
it = self.db.lists.get(self.db.lists.name == self.current_name) old = self.db_utils.list_get(self.current_name)
old = it.content.split("<-->")
# todo make better
name = old.pop(ind) name = old.pop(ind)
new = "<-->".join(old) self.db_utils.list_update(self.current_name, replace=old)
self.db.lists.update(content=new).where(self.db.lists.name == self.current_name).execute()
keyboard = [[InlineKeyboardButton("Remove another", callback_data="remove"), InlineKeyboardButton("Back to the menu", callback_data="overview")]] keyboard = [[InlineKeyboardButton("Remove another", callback_data="remove"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)

View File

@ -3,8 +3,8 @@ from .template import *
class Plain(BotFunc): class Plain(BotFunc):
"""Not a command: just keeps logs and usage_data""" """Not a command: just keeps logs and usage_data"""
def __init__(self, db): def __init__(self, db_utils):
super().__init__(db) super().__init__(db_utils)
def create_handler(self): def create_handler(self):
h = MessageHandler(Filters.text, callback=self.add_to_log) h = MessageHandler(Filters.text, callback=self.add_to_log)

View File

@ -3,8 +3,6 @@ from .template import *
import datetime import datetime
import requests import requests
import socket import socket
import numpy as np
import os
import json import json
@ -13,8 +11,8 @@ FIRST = 1
class Status(BotFunc): class Status(BotFunc):
"""Shows a short status of the program.""" """Shows a short status of the program."""
def __init__(self, name, version, db): def __init__(self, name, version, db_utils):
super().__init__(db) super().__init__(db_utils)
self.start_time = datetime.datetime.now() self.start_time = datetime.datetime.now()
self.name = name self.name = name
self.version = version self.version = version
@ -63,13 +61,13 @@ class Status(BotFunc):
message += "URL: [" + u + "](" + u + ")\n" message += "URL: [" + u + "](" + u + ")\n"
# TODO new DB # TODO new DB
tot_r = self.db.chats.select().where(self.db.chats.read == True).count() tot_r = self.db_utils.chat_count("read")
message += "Total messages read: `{}`\n".format(tot_r) message += "Total messages read: `{}`\n".format(tot_r)
tot_s = self.db.chats.select().where(self.db.chats.send == True).count() tot_s = self.db_utils.chat_count("send")
message += "Total messages sent: `{}`\n".format(tot_s) message += "Total messages sent: `{}`\n".format(tot_s)
tot_e = self.db.chats.select().where(self.db.chats.execute == True).count() tot_e = self.db_utils.chat_count("execute")
message += "Total commands executed: `{}`\n".format(tot_e) message += "Total commands executed: `{}`\n".format(tot_e)
if update.message: if update.message:
@ -101,6 +99,5 @@ class Status(BotFunc):
for i in res_json["tunnels"]: for i in res_json["tunnels"]:
if i['name'] == 'command_line': if i['name'] == 'command_line':
return i['public_url'] return i['public_url']
break
except: except:
return "Not available" return "Not available"

View File

@ -15,25 +15,13 @@ import datetime
class BotFunc(): class BotFunc():
"""Base class for a specific bot-functionality""" """Base class for a specific bot-functionality"""
def __init__(self, db): def __init__(self, db_utils):
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.db = db self.db_utils = db_utils
def log_activity(self, **kwargs):
# def log_activity(self, **kwargs): # mark that a new command has been executed
# # mark that a new command has been executed self.db_utils.sensor_log(**kwargs)
# try:
# data = self.db.chats(
# time=datetime.datetime.now(),
# **kwargs
# )
# # kwargs can look like
# # receive=True,
# # execute=True,
# # send=False,
# data.save()
# except Exception as e:
# self.logger.error("sql error: {}".format(e))
def entry_point(self, update: Update, context: CallbackContext) -> None: def entry_point(self, update: Update, context: CallbackContext) -> None:
if update.message.text: if update.message.text:

View File

@ -75,7 +75,7 @@ class Weather(BotFunc):
forecast_time = query.data.replace("time-","") forecast_time = query.data.replace("time-","")
weather = self.get_weather(self.city, forecast_time) weather = self.get_weather(self.city, forecast_time)
query.edit_message_text( query.edit_message_text(
text = "Weather: \n\n" + weather, text = "Broadcast for {}: \n\n{}".format(self.city, weather),
parse_mode = ParseMode.HTML parse_mode = ParseMode.HTML
) )
super().log_activity(read = True, execute = True, send = True) super().log_activity(read = True, execute = True, send = True)

View File

@ -36,7 +36,7 @@ class ChatBot():
def add_commands(self): def add_commands(self):
# Mark modules as available # Mark modules as available
db = self.db db = self.db_utils
self.help_module = self.commands.help.Help(db) self.help_module = self.commands.help.Help(db)
self.sub_modules = { self.sub_modules = {
"weather": self.commands.weather.Weather(self.api_weather, db), "weather": self.commands.weather.Weather(self.api_weather, db),
@ -60,7 +60,7 @@ class ChatBot():
self.help_module.add_commands(self.sub_modules) self.help_module.add_commands(self.sub_modules)
def start(self): def start(self):
self.sub_modules = {"clock" : self.commands.clock.Clock(self.db, self.modules["clock"], self.api_art)} self.sub_modules = {"clock" : self.commands.clock.Clock(self.db_utils, self.modules["clock"], self.api_art)}
self.add_commands() self.add_commands()
self.telegram.start_polling( self.telegram.start_polling(
poll_interval=0.2, poll_interval=0.2,

View File

@ -22,8 +22,7 @@ db_connection = PooledMySQLDatabase(
) )
def auto_connect_db(action): def auto_connect_db(func):
def decorated(func):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
#before: #before:
db_connection.connect() db_connection.connect()
@ -34,7 +33,6 @@ def auto_connect_db(action):
return ret return ret
return wrapper return wrapper
return decorated
@ -57,20 +55,21 @@ class DatabaseUtils:
else: # does not exist else: # does not exist
return -1 return -1
@auto_connect_db
def chat_log(self, **kwargs): def chat_log(self, **kwargs):
models.ChatMetric(**kwargs) models.ChatMetric(**kwargs)
@auto_connect_db
def list_get(self, list_name=""): def list_get(self, list_name=""):
if not list_name: # return all if not list_name: # return all
return models.List.select() cursor = models.List.select(models.List.name).execute()
return [k.name for k in cursor]
else: else:
return models.List.get(models.List.name == list_name) return models.List.get(models.List.name == list_name).content_as_list
@auto_connect_db
def list_update(self, list_name, append="", replace=[]): def list_update(self, list_name, append="", replace=None):
if replace: if replace != None:
models.List.get(models.List.name == list_name).set_content(replace) models.List.get(models.List.name == list_name).set_content(replace)
elif append: elif append:
l_obj = models.List.get(models.List.name == list_name) l_obj = models.List.get(models.List.name == list_name)
@ -80,9 +79,14 @@ class DatabaseUtils:
else: else:
logger.warning("Empty update_list() query was made. Ignoring") logger.warning("Empty update_list() query was made. Ignoring")
@auto_connect_db
def list_create(self, list_name):
models.List(name=list_name).save()
@auto_connect_db
def list_delete(self, list_name): def list_delete(self, list_name):
models.List.delete().where(self.db.lists.name == list_name).execute() models.List.delete().where(models.List.name == list_name).execute()
@auto_connect_db
def sensor_log(self, **kwargs): def sensor_log(self, **kwargs):
models.SensorMetric(**kwargs).save() models.SensorMetric(**kwargs).save()

View File

@ -45,11 +45,12 @@ class ErrorMetric(Metric):
class List(DBModel): class List(DBModel):
name = CharField(unique=True) name = CharField(unique=True)
content = TextField() # unlimited length, use to serialise list into content = TextField(default="") # unlimited length, use to serialise list into
@property @property
def content_as_list(self): def content_as_list(self):
return json.loads(self.content) return json.loads(self.content or '[]')
def set_content(self, list_content): def set_content(self, list_content):
self.content = json.dumps(list_content) self.content = json.dumps(list_content)
self.save()

View File

@ -1,17 +1,17 @@
Adafruit-Blinka==6.10.3 Adafruit-Blinka>=6.10.3
adafruit-circuitpython-dht==3.6.1 adafruit-circuitpython-dht>=3.6.1
Adafruit-PlatformDetect==3.14.2 Adafruit-PlatformDetect>=3.14.2
Adafruit-PureIO==1.1.9 Adafruit-PureIO>=1.1.9
board==1.0 board>=1.0
importlib-metadata==4.6.0 importlib-metadata>=4.6.0
pkg-resources==0.0.0 pkg-resources>=0.0.0
psycopg2==2.9.1 psycopg2>=2.9.1
psycopg2-binary==2.9.1 psycopg2-binary>=2.9.1
pyftdi==0.53.1 pyftdi>=0.53.1
pyserial==3.5 pyserial>=3.5
pyusb==1.1.1 pyusb>=1.1.1
rpi-ws281x==4.3.0 rpi-ws281x>=4.3.0
RPi.GPIO==0.7.0 RPi.GPIO>=0.7.0
sysv-ipc==1.1.0 sysv-ipc>=1.1.0
typing-extensions==3.10.0.0 typing-extensions>=3.10.0.0
zipp==3.4.1 zipp>=3.4.1

View File

@ -28,7 +28,7 @@ class BroadcastLauncher(launcher.Launcher):
"""Launcher for all server-side modules. The hard-computations""" """Launcher for all server-side modules. The hard-computations"""
def __init__(self): def __init__(self):
self.bot_module = main.ChatBot(name="Norbit", version="4.0a") # ??? self.bot_module = main.ChatBot(name="Norbit", version="4.1a") # ???
self.clock_backend_module = c_back.ClockBackend() # threaded through threading.Timer self.clock_backend_module = c_back.ClockBackend() # threaded through threading.Timer
self.broadcast_module = b_out.BroadcastUpdates(port="1111") # Thread self.broadcast_module = b_out.BroadcastUpdates(port="1111") # Thread
# self.dashboard_module = d_out.DashBoard(port="80") # ??? threaded as Thread # self.dashboard_module = d_out.DashBoard(port="80") # ??? threaded as Thread