diff --git a/.gitignore b/.gitignore index e6b99fd..075724e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Persistence -prst.db.* - +prst.* +log.txt # API-Key (keep secret at all times) keys.py diff --git a/bot/api/telegram.py b/bot/api/telegram.py index bb6b96b..38e3425 100644 --- a/bot/api/telegram.py +++ b/bot/api/telegram.py @@ -1,23 +1,21 @@ import emoji import requests -import Levenshtein as lev import datetime import bot.api.keys class TelegramIO(): - def __init__(self, persistence, commands): + def __init__(self, persistence): """Inits the Telegram-Interface """ self.base_url = "https://api.telegram.org/bot" + bot.api.keys.telegram_api + "/" self.persistence = persistence - self.commands = commands # Dynamic variables for answering self.chat_id = "" self.offset = 0 self.message_id = "" - + self.message_queue = [] def update_commands(self,commands): @@ -35,38 +33,37 @@ class TelegramIO(): try: result = requests.post(update_url,data=data) result = result.json()["result"] + self.message_queue = result except: - result = "" + result = [] - return result + return len(result) - def handle_result(self, result): - """Inspects the message and reacts accordingly. Can easily be extended""" - message_data = result[0] + def process_message(self): + """Inspects the first message from self.message_queue and reacts accordingly.""" + message_data = self.message_queue.pop(0) self.persistence["bot"]["messages_read"] += 1 self.offset = message_data["update_id"] + 1 if "edited_message" in message_data: - return "nothing", "happened" + return message = message_data["message"] self.message_id = message["message_id"] self.chat_id = message["chat"]["id"] author = message["from"] - chat_members = self.persistence["bot"]["chat_members"] - if str(author["id"]) not in chat_members: + if author["id"] not in self.persistence["bot"]["chat_members"]: name = "" if "first_name" in author: name += author["first_name"] + " " if "last_name" in author: name += author["last_name"] if len(name) == 0: - name += "anonymous" - chat_members[author["id"]] = name - self.persistence["bot"]["chat_members"] = chat_members + name = "anonymous" + self.persistence["bot"]["chat_members"][author["id"]] = name self.send_message("Welcome to this chat " + name + "!") if "text" in message: @@ -75,45 +72,12 @@ class TelegramIO(): if "entities" in message: for entry in message["entities"]: if entry["type"] == "bot_command": - return self.handle_command(message["text"][1:]) + return message["text"] #self.handle_command(message["text"][1:]) elif "photo" in message: print("Photo received, what do I do?") - return "nothing", "happened" - - - def handle_command(self, command): - """Handles commands and stuff, using a bash-like syntax: - /[command] [argument 1] [argument 2] ... - """ - full = command.split(" ") - command = self.fuzzy_match_command(full[0]) - if len(command) != 1: - if command[0] == "EXACT": - self.persistence["bot"]["commands_executed"] += 1 - return command[1], full[1:] - else: - send = "Did you mean <code>" + command[1] + "</code>" - for i in range(2,len(command)): - send += " or <code>" + command[1] + "</code>" - send += "?" - self.send_message(send) - else: - self.send_message("Command <code>" + full[0] + "</code> not found. Please try again.") - - return "nothing", ["happened"] - - - def fuzzy_match_command(self, input): - matches = ["not exact"] - for command in self.commands.keys(): - if lev.ratio(input.lower(),command) > 0.8: - matches.append(command) - if lev.ratio(input.lower(),command) == 1: - return ["EXACT", command] - - return matches + return def send_thinking_note(self): @@ -154,7 +118,7 @@ class TelegramIO(): out += " @ " + "telegram.send_message" out += " --> " + "did not send:\n" + message self.persistence["bot"]["log"] += [out] - + def send_photo(self, url, caption): print("SENDING PHOTO: " + url) diff --git a/bot/framework.py b/bot/framework.py new file mode 100644 index 0000000..17fed77 --- /dev/null +++ b/bot/framework.py @@ -0,0 +1,138 @@ +import datetime +from bot.api import telegram, google, weather, reddit +import Levenshtein as lev + +class BotFramework(): + """Main functionality for a bot """ + + def __init__(self, name, version, prst): + """Inits the Bot with a few conf. vars + Args: -> name:str - Name of the bot + -> version:str - Version number + -> prst:shelveObj - persistence + """ + + self.version = version + self.name = name + + # Persistent variable + self.persistence = prst + # Uptime counter + self.start_time = datetime.datetime.now() + + self.emoji_dict = { + "a" : ":regional_indicator_symbol_letter_a:", + "b" : ":regional_indicator_symbol_letter_b:", + "c" : ":regional_indicator_symbol_letter_c:", + "d" : ":regional_indicator_symbol_letter_d:", + "e" : ":regional_indicator_symbol_letter_e:", + "f" : ":regional_indicator_symbol_letter_f:", + "g" : ":regional_indicator_symbol_letter_g:", + "h" : ":regional_indicator_symbol_letter_h:", + "i" : ":regional_indicator_symbol_letter_i:", + "j" : ":regional_indicator_symbol_letter_j:", + "k" : ":regional_indicator_symbol_letter_k:", + "l" : ":regional_indicator_symbol_letter_l:", + "m" : ":regional_indicator_symbol_letter_m:", + "n" : ":regional_indicator_symbol_letter_n:", + "o" : ":regional_indicator_symbol_letter_o:", + "p" : ":regional_indicator_symbol_letter_p:", + "q" : ":regional_indicator_symbol_letter_q:", + "r" : ":regional_indicator_symbol_letter_r:", + "s" : ":regional_indicator_symbol_letter_s:", + "t" : ":regional_indicator_symbol_letter_t:", + "u" : ":regional_indicator_symbol_letter_u:", + "v" : ":regional_indicator_symbol_letter_v:", + "w" : ":regional_indicator_symbol_letter_w:", + "x" : ":regional_indicator_symbol_letter_x:", + "y" : ":regional_indicator_symbol_letter_y:", + "z" : ":regional_indicator_symbol_letter_z:", + "0" : ":keycap_digit_zero:", + "1" : ":keycap_digit_one:", + "2" : ":keycap_digit_two:", + "3" : ":keycap_digit_three:", + "4" : ":keycap_digit_four:", + "5" : ":keycap_digit_five:", + "6" : ":keycap_digit_six:", + "7" : ":keycap_digit_seven:", + "8" : ":keycap_digit_eight:", + "9" : ":keycap_digit_nine:", + } + + self.telegram = telegram.TelegramIO(self.persistence) + + def react_chats(self): + """Checks unanswered messages and answers them""" + num = self.telegram.fetch_updates() + for i in range(num): + self.react_command() + + + def react_command(self): + """Reacts if a new command is present + + Returns command, params iff the command is a hardware-one (for the clock), else None""" + message = self.telegram.process_message() + if message == None: + return + + message = message[1:] #remove first "/" + tmp = message.split(" ") + cmd = tmp[0] + params = tmp[1:] + + def call_command(cmd, par): + result = self.commands[cmd](*par) + # *params means the list is unpacked and handed over as separate arguments. + self.telegram.send_message(result) + + if self.is_command(cmd): # first word + call_command(cmd, params) + elif cmd in self.persistence["bot"]["aliases"]: + dealias = self.persistence["bot"]["aliases"][cmd].split(" ") # as a list + new_cmd = dealias[0] + params = dealias[1:] + params + self.telegram.send_message("Substituted <code>" + cmd + "</code> to <code>" + self.persistence["bot"]["aliases"][cmd] + "</code> and got:") + call_command(new_cmd, params) + else: + self.telegram.send_message("Command <code>" + tmp[0] + "</code> not found.") + + + def is_command(self, input): + """checks if we have a command. Returns true if yes and False if not + + Also sends a mesage if close to an existing command + """ + max_match = 0 + command_candidate = "" + for command in self.commands.keys(): + match = lev.ratio(input.lower(),command) + if match > 0.7 and match > max_match: + max_match = match + command_candidate = command + if max_match == 1: + return True + if max_match != 0: + self.telegram.send_message("Did you mean <code>" + command_candidate + "</code>") + return False + + + def emojify_word(self,word): + """""" + string_emoji = "" + for letter in word: + if letter in self.emoji_dict: + string_emoji += self.emoji_dict[letter.lower()] + else: + string_emoji += letter + return string_emoji + + + def write_bot_log(self, function_name, error_message): + """""" + out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M") + out += " @ " + function_name + out += " --> " + error_message + self.persistence["bot"]["log"] += [out] + + \ No newline at end of file diff --git a/bot/main.py b/bot/main.py index 612e608..c290d34 100644 --- a/bot/main.py +++ b/bot/main.py @@ -1,33 +1,27 @@ -# -*- coding: utf-8 -*- - from bot.api import telegram, google, weather, reddit +import datetime + import requests import time import json import datetime import emoji -class ChatBot(): +import bot.framework as FW + +class ChatBot(FW.BotFramework): """""" - def __init__(self, name, version, prst): + def __init__(self, name, version, prst, hw_commands): """Inits the Bot with a few conf. vars Args: -> name:str - Name of the bot -> version:str - Version number -> prst:shelveObj - persistence """ - - self.version = version - self.name = name - - # Persistent variable - self.persistence = prst - # Uptime counter - self.start_time = datetime.datetime.now() - self.persistence["bot"]["reboots"] += 1 - + super().__init__(name, version, prst) + # Available commands. Must be manually updated! - self.commands = { + self.commands = dict({ "help" : self.bot_show_help, "status" : self.bot_print_status, "log" : self.bot_print_log, @@ -43,81 +37,10 @@ class ChatBot(): "meme" : self.bot_send_meme, "news" : self.bot_send_news, "list" : self.bot_list, + "alias" : self.bot_save_alias, + }, **hw_commands) + # concat bot_commands + hw-commands - } - - - self.emoji_dict = { - "a" : ":regional_indicator_symbol_letter_a:", - "b" : ":regional_indicator_symbol_letter_b:", - "c" : ":regional_indicator_symbol_letter_c:", - "d" : ":regional_indicator_symbol_letter_d:", - "e" : ":regional_indicator_symbol_letter_e:", - "f" : ":regional_indicator_symbol_letter_f:", - "g" : ":regional_indicator_symbol_letter_g:", - "h" : ":regional_indicator_symbol_letter_h:", - "i" : ":regional_indicator_symbol_letter_i:", - "j" : ":regional_indicator_symbol_letter_j:", - "k" : ":regional_indicator_symbol_letter_k:", - "l" : ":regional_indicator_symbol_letter_l:", - "m" : ":regional_indicator_symbol_letter_m:", - "n" : ":regional_indicator_symbol_letter_n:", - "o" : ":regional_indicator_symbol_letter_o:", - "p" : ":regional_indicator_symbol_letter_p:", - "q" : ":regional_indicator_symbol_letter_q:", - "r" : ":regional_indicator_symbol_letter_r:", - "s" : ":regional_indicator_symbol_letter_s:", - "t" : ":regional_indicator_symbol_letter_t:", - "u" : ":regional_indicator_symbol_letter_u:", - "v" : ":regional_indicator_symbol_letter_v:", - "w" : ":regional_indicator_symbol_letter_w:", - "x" : ":regional_indicator_symbol_letter_x:", - "y" : ":regional_indicator_symbol_letter_y:", - "z" : ":regional_indicator_symbol_letter_z:", - "0" : ":keycap_digit_zero:", - "1" : ":keycap_digit_one:", - "2" : ":keycap_digit_two:", - "3" : ":keycap_digit_three:", - "4" : ":keycap_digit_four:", - "5" : ":keycap_digit_five:", - "6" : ":keycap_digit_six:", - "7" : ":keycap_digit_seven:", - "8" : ":keycap_digit_eight:", - "9" : ":keycap_digit_nine:", - } - - self.telegram = telegram.TelegramIO(self.persistence, self.commands) - - def add_commands(self, commands): - """adds new commands to an existing list""" - self.commands = {**self.commands, **commands} - self.telegram.update_commands(self.commands) - - - def react_command(self, command, params): - """""" - result = self.commands[command](*params) - #*params means the list is unpacked and handed over as separate arguments. - self.telegram.send_message(result) - - - def emojify_word(self,word): - """""" - string_emoji = "" - for letter in word: - if letter in self.emoji_dict: - string_emoji += self.emoji_dict[letter.lower()] - else: - string_emoji += letter - return string_emoji - - - def write_bot_log(self, function_name, error_message): - """""" - out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M") - out += " @ " + function_name - out += " --> " + error_message - self.persistence["bot"]["log"] += [out] ############################################################################ @@ -137,13 +60,14 @@ class ChatBot(): def bot_print_status(self, *args): """Prints the bots current status and relevant information""" delta = str(datetime.datetime.now() - self.start_time) + message = "BeebBop, this is " + self.name + " (V." + self.version + ")\n" try: ip = requests.get('https://api.ipify.org').text except: ip = "not fetchable" - message = "<pre>Status: Running :green_circle:\n" + message += "<pre>Status: Running :green_circle:\n" message += "Uptime: " + delta[:delta.rfind(".")] + "\n" - message += "Reboots: " + str(self.persistence["bot"]["reboots"]) + "\n" + message += "Reboots: " + str(self.persistence["global"]["reboots"]) + "\n" message += "IP-Adress: " + ip + "\n" message += "Messages read: " + str(self.persistence["bot"]["messages_read"]) + "\n" message += "Messages sent: " + str(self.persistence["bot"]["messages_sent"]) + "\n" @@ -217,10 +141,22 @@ class ChatBot(): def bot_show_help(self, *args): - """Shows a list of all commands and their description""" + """Show a help message. + + Usage: help {keyword} + Keywords: + * no kw - list of all commands + * full - all commands and their docstring + * command-name - specific command and its docstring + """ description = False - if "full" in args: - description = True + if len(args) > 0: + if args[0] == "full": + description = True + elif args[0] in self.commands: + send_text = "<b>" + args[0] + "</b>\n" + send_text += "<code>" + self.commands[args[0]].__doc__ + "</code>" + return send_text send_text = "BeebBop, this is " + self.name + " (V." + self.version + ")\n" send_text += "Here is what I can do up to now: \n" @@ -236,12 +172,16 @@ class ChatBot(): def bot_print_log(self, *args): - """Shows an error-log, mostly of bad api-requests. Usage - log clear - clears log - log system - shows python output""" + """Show an error-log, mostly of bad api-requests. + + Usage: log {keyword} + Keywords: + * clear - clears log + * system - shows python output + """ if "clear" in args: - self.persistence.write("log",[]) + self.persistence["bot"]["log"] = [] return "Log cleared" elif "system" in args: path="persistence/log.txt" @@ -254,7 +194,7 @@ class ChatBot(): return "could not read File" send_text = "" - for event in self.persistence.read("log"): + for event in self.persistence["bot"]["log"]: send_text += event + "\n" if send_text == "": send_text += "No errors up to now" @@ -262,7 +202,13 @@ class ChatBot(): def bot_show_wikipedia(self, *args): - """Shows the wikipedia entry for a given term""" + """Shows the wikipedia entry for a given term + + Usage: wikipedia <language> <term> + Keywords: + * language - de, fr, en ... + * term - search term, can consist of multiple words + """ if len(args) == 0: return "Please provide the first argument for language (de or fr or en or ...) and then your query" args = list(args) @@ -283,7 +229,12 @@ class ChatBot(): def bot_zvv(self, *args): """Uses the swiss travel api to return the best route between a start- and endpoint. - usage: 'start' to 'finish'""" + + Usage: zvv <start> 'to' <finish> + Keywords: + * start - start point (can be more than 1 word9 + * end - end point + """ if len(args) < 3: return "Please specify a start- and endpoint as well as a separator (the 'to')" @@ -360,7 +311,12 @@ class ChatBot(): def bot_tell_joke(self, *args): - """Tells you the top joke on r/jokes""" + """Tells you the top joke on r/jokes + + Usage: joke {number} + Keywords: + * number - number of jokes + """ params_sorted = self.match_reddit_params(*args) @@ -427,20 +383,33 @@ class ChatBot(): def bot_list(self, *args): - """Shows and interacts with a list. Usage - list <name> <action> {object} - actions are: create, delete, print, clear, add, remove - example: - list new shopping : creates list name shopping + """Interacts with a list (like a shopping list eg.) + + Usage list <name> <action> {object} + Keyword: + * name - name of list + * action - create, delete, all, print, clear, add, remove + * object - might not be needed: index to delete, or item to add + + Example usage: + list create shopping : creates list name shopping list shopping add bread : adds bread to the list list shopping print list shopping clear + list all """ output = "" # args = list(args) - if len(args) < 2: + if len(args) == 0: return "Missing parameters" try: + if args[0] == "all": + try: + return "Existing lists are: " + list(self.persistence["global"]["lists"].keys()).join(" ") + except: + return "No lists created." + if len(args) < 2: + return "Missing parameters" if args[0] == "create": lname = " ".join(args[1:]) self.persistence["global"]["lists"][lname] = [] @@ -454,6 +423,7 @@ class ChatBot(): act = args[1] if act == "print": sl = self.persistence["global"]["lists"][lname] + output += "Content of " + lname + ":\n" for ind,thing in enumerate(sl): output += str(ind+1) + ". " + thing + "\n" elif act == "clear": @@ -474,7 +444,48 @@ class ChatBot(): def bot_save_alias(self, *args): """Save a shortcut for special commands (+params) - usage: /alias sa shopping add - Means: /sa will now be treated as input /shopping add""" - return "Does this look finished to you?" \ No newline at end of file + Usage: alias <alias-name> {<alias-name> <command>} + Keywords: + * action - all, add, delete or clear (deleta all) + * alias-name - short name + * command - command to be executed, can contain arguments for the command + Example usage: + * alias sa list shopping add + * alias sp list shopping print + Means that '/sa ...' will now be treated as if typed '/list shopping add ...' + """ + # args = list(args) + if len(args) == 0: + return "Missing parameters" + try: + if args[0] == "clear": + self.persistence["bot"]["aliases"] = {} + return "All aliases cleared" + elif args[0] == "all": + try: + output = "Existing aliases are:\n" + for j, k in self.persistence["bot"]["aliases"].items(): + output += j + " -> " + k + "\n" + return output + except: + return "No aliases created." + + if len(args) < 2: + return "Missing parameters" + if args[0] == "delete": + ak = args[1] + self.persistence["bot"]["aliases"].pop(ak, None) # no error if key doesnt exist + return "Deleted alias " + ak + + if len(args) < 3: + return "Missing parameters" + if args[0] == "add": + ak = args[1] + cmd = " ".join(args[2:]) + self.persistence["bot"]["aliases"][ak] = cmd + return "Created alias for " + ak + + except: + return "Could not handle your request. Maybe check the keys?" + return "Bad input..." diff --git a/clock/main.py b/clock/main.py index 96f2f91..bae504e 100644 --- a/clock/main.py +++ b/clock/main.py @@ -13,6 +13,8 @@ class ClockFace(object): """Actual functions one might need for a clock""" def __init__(self, text_speed=18, prst=""): + """""" + self.persistence = prst self.IO = led.OutputHandler(32,16) self.tspeed = text_speed @@ -21,6 +23,12 @@ class ClockFace(object): self.output_queue = [] # Threads to execute next + self.commands = { + "blink" : self.alarm_blink, + "wakeup" : self.wake_light, + "showmessage" : self.show_message, + } + self.weather = "" self.brightness_overwrite = {"value" : 1, "duration" : 0} @@ -82,6 +90,11 @@ class ClockFace(object): ############################################################################ ### Higher level commands, accessible from the chat-bot + def external_action(self, command, params): + """""" + self.commands[command](*params) + + def wake_light(self, duration=600): """Simulates a sunris, takes one optional parameter: the duration""" def output(duration): @@ -99,11 +112,10 @@ class ClockFace(object): self.IO.set_matrix(ones,colors=[col]) time.sleep(int(duration) / 20) - self.run(output,(duration,)) - def alarm_blink(self, duration, frequency): + def alarm_blink(self, duration=0, frequency=0): """Blinks the whole screen (red-black). Duration in seconds, frequency in Hertz""" def output(duration, frequency): self.set_brightness(value=1) @@ -118,8 +130,8 @@ class ClockFace(object): time.sleep(1/frequency) self.IO.set_matrix(empty) time.sleep(1/frequency) - - self.run(output,(duration, frequency)) + if not(duration == 0 or frequency == 0): + self.run(output,(duration, frequency)) def image_show(self, image, duration): diff --git a/dashboard_wrapper.py b/dashboard_wrapper.py deleted file mode 100644 index 42a38c7..0000000 --- a/dashboard_wrapper.py +++ /dev/null @@ -1,24 +0,0 @@ -import wrapper - -from threading import Thread -import time - -class DashBoardWrapper(wrapper.Wrapper): - def __init__(self, own_module, *other_modules): - """""" - super().__init__(own_module, other_modules) - print("Initializing DASHBOARD-functionality") - # mainloop - - def mainloop(self): - super(DashBoardWrapper, self).mainloop(sleep_delta = 3600*3) #3hours refresh-cycle - self.set_weather() - self.set_shopping_list() - self.set_bot_logs() - self.set_joke() - self.bot.refresh() - - def set_weather(self): - weather = self.bot.bot_show_weather("zurich") - ... - self.own.set_weather(weather) diff --git a/launcher.py b/launcher.py index fc30143..d6ec187 100644 --- a/launcher.py +++ b/launcher.py @@ -2,7 +2,6 @@ import bot.main import clock.main import dashboard.main - # wrapper import wrapper @@ -10,18 +9,18 @@ import wrapper from threading import Thread import shelve - class Launcher(): """Launches all other submodules""" def __init__(self): """""" - self.persistence = shelve.open('persistence/prst.db', writeback=True) - self.init_persistence() - # TODO populate the persistence - self.bot_module = bot.main.ChatBot(name="ChatterBot", version="2.1", prst=self.persistence) + self.persistence = shelve.DbfilenameShelf("persistence/prst.db", writeback = True) + if len(self.persistence) == 0: + self.init_persistence() + self.persistence["global"]["reboots"] += 1 self.clock_module = clock.main.ClockFace(prst=self.persistence) - + self.bot_module = bot.main.ChatBot(name="ChatterBot", version="2.1", prst=self.persistence, hw_commands=self.clock_module.commands) + self.threads = [] self.threads.append(Thread(target=self.chatbot)) self.threads.append(Thread(target=self.clock)) @@ -42,6 +41,7 @@ class Launcher(): self.dashboard = wrapper.DashBoardWrapper(self.dashboard_module, self.bot_module) def init_persistence(self): + print("New Persistence created") self.persistence["bot"] = { "messages_read": 0, "messages_sent": 0, @@ -49,15 +49,16 @@ class Launcher(): "photos_sent": 0, "log": [], "chat_members": {}, - "reboots": 0 + "aliases" : {} } self.persistence["clock"] = {} self.persistence["dashboard"] = {} self.persistence["global"] = { - "lists" : {} + "lists" : {}, + "reboots": 0 } ######################################################################## ## Aand liftoff! -Launcher() +Launcher() \ No newline at end of file diff --git a/persistence/__init__.py b/persistence/__init__.py new file mode 100644 index 0000000..fc6bb0e --- /dev/null +++ b/persistence/__init__.py @@ -0,0 +1 @@ +#placeholder \ No newline at end of file diff --git a/wrapper.py b/wrapper.py index 1cda615..fcdc268 100644 --- a/wrapper.py +++ b/wrapper.py @@ -19,6 +19,8 @@ class Wrapper(): while True: action() time.sleep(sleep_delta) + self.own.persistence.sync() + @@ -86,16 +88,6 @@ class BotWrapper(Wrapper): self.bot = own_module self.clock = other_modules[0] - - - # available hw-commands. Must be updated manually! - self.hw_commands = { - "blink" : self.clock.alarm_blink, - "wakeup" : self.clock.wake_light, - "showmessage" : self.clock.show_message, - - } - self.bot.add_commands(self.hw_commands) self.mainloop(10) @@ -103,18 +95,38 @@ class BotWrapper(Wrapper): def mainloop(self, sleep_delta): """Calls the telegram entity regularly to check for activity""" def perform_loop(): - result = self.bot.telegram.fetch_updates() - if len(result) != 0: - command, params = self.bot.telegram.handle_result(result) - if command != "nothing": - if command in self.hw_commands: - self.react_hw_command(command,params) # hw-level - else: - self.bot.react_command(command,params) # sw-level + self.bot.react_chats() + # num = self.bot.telegram.fetch_updates() + # for message in range(num): + # command, params = self.bot.react_command() # returns None if handled internally + # if command != None: + # self.clock.external_action(command, params) + super().mainloop(sleep_delta, perform_loop) + + + + +from threading import Thread + +class DashBoardWrapper(Wrapper): + def __init__(self, own_module, *other_modules): + """Wrapper for the dashboard functionality""" + super().__init__(own_module, other_modules) + # self.mainloop(2 * 3600) # 2 hours refresh-cycle + + + def mainloop(self, sleep_delta): + def perform_loop(): + self.set_weather() + self.set_shopping_list() + self.set_bot_logs() + self.set_joke() + self.bot.refresh() super().mainloop(sleep_delta, perform_loop) - def react_hw_command(self, command, params): - """""" - # so params is a list, and so, to pass the commands, we need to unpack it: - self.hw_commands[command](*params) + + def set_weather(self): + weather = self.bot.bot_show_weather("zurich") + ... + self.own.set_weather(weather)