Better persistence
This commit is contained in:
parent
cd13cea967
commit
6f80f26de1
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
# Persistence
|
# Persistence
|
||||||
persistent_vars.json
|
prst.db.*
|
||||||
|
|
||||||
# API-Key (keep secret at all times)
|
# API-Key (keep secret at all times)
|
||||||
keys.py
|
keys.py
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import emoji
|
import emoji
|
||||||
import requests
|
import requests
|
||||||
import Levenshtein as lev
|
import Levenshtein as lev
|
||||||
|
import datetime
|
||||||
|
|
||||||
import bot.api.keys
|
import bot.api.keys
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ class TelegramIO():
|
|||||||
"""Inspects the message and reacts accordingly. Can easily be extended"""
|
"""Inspects the message and reacts accordingly. Can easily be extended"""
|
||||||
message_data = result[0]
|
message_data = result[0]
|
||||||
|
|
||||||
self.persistence.increment("messages_read")
|
self.persistence["bot"]["messages_read"] += 1
|
||||||
self.offset = message_data["update_id"] + 1
|
self.offset = message_data["update_id"] + 1
|
||||||
|
|
||||||
if "edited_message" in message_data:
|
if "edited_message" in message_data:
|
||||||
@ -55,7 +56,7 @@ class TelegramIO():
|
|||||||
self.chat_id = message["chat"]["id"]
|
self.chat_id = message["chat"]["id"]
|
||||||
author = message["from"]
|
author = message["from"]
|
||||||
|
|
||||||
chat_members = self.persistence.read("chat_members")
|
chat_members = self.persistence["bot"]["chat_members"]
|
||||||
if str(author["id"]) not in chat_members:
|
if str(author["id"]) not in chat_members:
|
||||||
name = ""
|
name = ""
|
||||||
if "first_name" in author:
|
if "first_name" in author:
|
||||||
@ -65,7 +66,7 @@ class TelegramIO():
|
|||||||
if len(name) == 0:
|
if len(name) == 0:
|
||||||
name += "anonymous"
|
name += "anonymous"
|
||||||
chat_members[author["id"]] = name
|
chat_members[author["id"]] = name
|
||||||
self.persistence.write("chat_members", chat_members)
|
self.persistence["bot"]["chat_members"] = chat_members
|
||||||
self.send_message("Welcome to this chat " + name + "!")
|
self.send_message("Welcome to this chat " + name + "!")
|
||||||
|
|
||||||
if "text" in message:
|
if "text" in message:
|
||||||
@ -90,7 +91,7 @@ class TelegramIO():
|
|||||||
command = self.fuzzy_match_command(full[0])
|
command = self.fuzzy_match_command(full[0])
|
||||||
if len(command) != 1:
|
if len(command) != 1:
|
||||||
if command[0] == "EXACT":
|
if command[0] == "EXACT":
|
||||||
self.persistence.increment("commands_executed")
|
self.persistence["bot"]["commands_executed"] += 1
|
||||||
return command[1], full[1:]
|
return command[1], full[1:]
|
||||||
else:
|
else:
|
||||||
send = "Did you mean <code>" + command[1] + "</code>"
|
send = "Did you mean <code>" + command[1] + "</code>"
|
||||||
@ -129,11 +130,12 @@ class TelegramIO():
|
|||||||
|
|
||||||
def send_message(self, message):
|
def send_message(self, message):
|
||||||
|
|
||||||
if message == "":
|
if message == "" or message == None:
|
||||||
return
|
return
|
||||||
|
|
||||||
print("SENDING: " + emoji.demojize(message))
|
print("SENDING: " + message)
|
||||||
|
# message = message.replace("<","<").replace(">", ">")
|
||||||
|
# TODO: sanitize input but keep relevant tags
|
||||||
data = {
|
data = {
|
||||||
'chat_id': self.chat_id,
|
'chat_id': self.chat_id,
|
||||||
'text': emoji.emojize(message),
|
'text': emoji.emojize(message),
|
||||||
@ -144,13 +146,14 @@ class TelegramIO():
|
|||||||
send_url = self.base_url + "sendMessage"
|
send_url = self.base_url + "sendMessage"
|
||||||
try:
|
try:
|
||||||
r = requests.post(send_url, data=data)
|
r = requests.post(send_url, data=data)
|
||||||
print(r.status_code)
|
if (r.status_code != 200):
|
||||||
self.persistence.increment("messages_sent")
|
raise Exception
|
||||||
|
self.persistence["bot"]["messages_sent"]
|
||||||
except:
|
except:
|
||||||
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
||||||
out += " @ " + "telegram.send_message"
|
out += " @ " + "telegram.send_message"
|
||||||
out += " --> " + "did not send:\n" + message
|
out += " --> " + "did not send:\n" + message
|
||||||
self.persistence.append_list("log", out)
|
self.persistence["bot"]["log"] += [out]
|
||||||
|
|
||||||
|
|
||||||
def send_photo(self, url, caption):
|
def send_photo(self, url, caption):
|
||||||
@ -165,9 +168,9 @@ class TelegramIO():
|
|||||||
send_url = self.base_url + "sendPhoto"
|
send_url = self.base_url + "sendPhoto"
|
||||||
try:
|
try:
|
||||||
r = requests.post(send_url, data=data)
|
r = requests.post(send_url, data=data)
|
||||||
self.persistence.increment("photos_sent")
|
self.persistence["bot"]["photos_sent"] += 1
|
||||||
except:
|
except:
|
||||||
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
||||||
out += " @ " + "telegram.send_photo"
|
out += " @ " + "telegram.send_photo"
|
||||||
out += " --> " + "did not send:\n" + url
|
out += " --> " + "did not send:\n" + url
|
||||||
self.persistence.append_list("log", out)
|
self.persistence["bot"]["log"] += [out]
|
||||||
|
93
bot/main.py
93
bot/main.py
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from bot.api import telegram, google, weather, reddit
|
from bot.api import telegram, google, weather, reddit
|
||||||
from persistence import rw as pvars
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
@ -11,21 +10,21 @@ import emoji
|
|||||||
|
|
||||||
class ChatBot():
|
class ChatBot():
|
||||||
""""""
|
""""""
|
||||||
def __init__(self, name, version):
|
def __init__(self, name, version, prst):
|
||||||
"""Inits the Bot with a few conf. vars
|
"""Inits the Bot with a few conf. vars
|
||||||
Args: -> name:str - Name of the bot
|
Args: -> name:str - Name of the bot
|
||||||
-> api_key:str - t.me api-key
|
|
||||||
-> version:str - Version number
|
-> version:str - Version number
|
||||||
|
-> prst:shelveObj - persistence
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.version = version
|
self.version = version
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
# Persistent variable
|
# Persistent variable
|
||||||
self.persistence = pvars.Variables("bot")
|
self.persistence = prst
|
||||||
# Uptime counter
|
# Uptime counter
|
||||||
self.start_time = datetime.datetime.now()
|
self.start_time = datetime.datetime.now()
|
||||||
self.persistence.increment("reboots")
|
self.persistence["bot"]["reboots"] += 1
|
||||||
|
|
||||||
# Available commands. Must be manually updated!
|
# Available commands. Must be manually updated!
|
||||||
self.commands = {
|
self.commands = {
|
||||||
@ -43,7 +42,7 @@ class ChatBot():
|
|||||||
"joke" : self.bot_tell_joke,
|
"joke" : self.bot_tell_joke,
|
||||||
"meme" : self.bot_send_meme,
|
"meme" : self.bot_send_meme,
|
||||||
"news" : self.bot_send_news,
|
"news" : self.bot_send_news,
|
||||||
"shopping" : self.bot_shopping_list,
|
"list" : self.bot_list,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +117,7 @@ class ChatBot():
|
|||||||
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
out = datetime.datetime.now().strftime("%d.%m.%y - %H:%M")
|
||||||
out += " @ " + function_name
|
out += " @ " + function_name
|
||||||
out += " --> " + error_message
|
out += " --> " + error_message
|
||||||
self.persistence.append_list("log", out)
|
self.persistence["bot"]["log"] += [out]
|
||||||
|
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
@ -144,11 +143,11 @@ class ChatBot():
|
|||||||
ip = "not fetchable"
|
ip = "not fetchable"
|
||||||
message = "<pre>Status: Running :green_circle:\n"
|
message = "<pre>Status: Running :green_circle:\n"
|
||||||
message += "Uptime: " + delta[:delta.rfind(".")] + "\n"
|
message += "Uptime: " + delta[:delta.rfind(".")] + "\n"
|
||||||
message += "Reboots: " + str(self.persistence.read("reboots")) + "\n"
|
message += "Reboots: " + str(self.persistence["bot"]["reboots"]) + "\n"
|
||||||
message += "IP-Adress: " + ip + "\n"
|
message += "IP-Adress: " + ip + "\n"
|
||||||
message += "Messages read: " + str(self.persistence.read("messages_read")) + "\n"
|
message += "Messages read: " + str(self.persistence["bot"]["messages_read"]) + "\n"
|
||||||
message += "Messages sent: " + str(self.persistence.read("messages_sent")) + "\n"
|
message += "Messages sent: " + str(self.persistence["bot"]["messages_sent"]) + "\n"
|
||||||
message += "Commands executed " + str(self.persistence.read("commands_executed")) + "</pre>"
|
message += "Commands executed " + str(self.persistence["bot"]["commands_executed"]) + "</pre>"
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
@ -245,8 +244,14 @@ class ChatBot():
|
|||||||
self.persistence.write("log",[])
|
self.persistence.write("log",[])
|
||||||
return "Log cleared"
|
return "Log cleared"
|
||||||
elif "system" in args:
|
elif "system" in args:
|
||||||
send_text = self.persistence.read_ext_file("persistence/log.txt")
|
path="persistence/log.txt"
|
||||||
return send_text
|
try:
|
||||||
|
file = open(path,"r")
|
||||||
|
content = file.read()
|
||||||
|
file.close()
|
||||||
|
return content
|
||||||
|
except:
|
||||||
|
return "could not read File"
|
||||||
|
|
||||||
send_text = ""
|
send_text = ""
|
||||||
for event in self.persistence.read("log"):
|
for event in self.persistence.read("log"):
|
||||||
@ -279,7 +284,7 @@ class ChatBot():
|
|||||||
def bot_zvv(self, *args):
|
def bot_zvv(self, *args):
|
||||||
"""Uses the swiss travel api to return the best route between a start- and endpoint.
|
"""Uses the swiss travel api to return the best route between a start- and endpoint.
|
||||||
usage: 'start' to 'finish'"""
|
usage: 'start' to 'finish'"""
|
||||||
if len(args) <= 3:
|
if len(args) < 3:
|
||||||
return "Please specify a start- and endpoint as well as a separator (the 'to')"
|
return "Please specify a start- and endpoint as well as a separator (the 'to')"
|
||||||
|
|
||||||
url = "http://transport.opendata.ch/v1/connections"
|
url = "http://transport.opendata.ch/v1/connections"
|
||||||
@ -421,33 +426,49 @@ class ChatBot():
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def bot_shopping_list(self, *args):
|
def bot_list(self, *args):
|
||||||
"""Shows a shopping list. Usage
|
"""Shows and interacts with a list. Usage
|
||||||
add <aobject>
|
list <name> <action> {object}
|
||||||
print
|
actions are: create, delete, print, clear, add, remove
|
||||||
clear
|
example:
|
||||||
remove <position>
|
list new shopping : creates list name shopping
|
||||||
|
list shopping add bread : adds bread to the list
|
||||||
|
list shopping print
|
||||||
|
list shopping clear
|
||||||
"""
|
"""
|
||||||
output = ""
|
output = ""
|
||||||
# args = list(args)
|
# args = list(args)
|
||||||
if len(args) == 0:
|
if len(args) < 2:
|
||||||
return "Missing parameter(s)"
|
return "Missing parameters"
|
||||||
|
try:
|
||||||
if args[0] == "print":
|
if args[0] == "create":
|
||||||
sl = self.persistence.global_action("read", "shopping_list")
|
lname = " ".join(args[1:])
|
||||||
|
self.persistence["global"]["lists"][lname] = []
|
||||||
|
output = "Created list " + lname
|
||||||
|
elif args[0] == "delete":
|
||||||
|
lname = " ".join(args[1:])
|
||||||
|
self.persistence["global"]["lists"].pop(lname, None) # no error if key doesnt exist
|
||||||
|
output = "Deleted list " + lname
|
||||||
|
else:
|
||||||
|
lname = args[0]
|
||||||
|
act = args[1]
|
||||||
|
if act == "print":
|
||||||
|
sl = self.persistence["global"]["lists"][lname]
|
||||||
for ind,thing in enumerate(sl):
|
for ind,thing in enumerate(sl):
|
||||||
output += str(ind+1) + ". " + thing + "\n"
|
output += str(ind+1) + ". " + thing + "\n"
|
||||||
elif args[0] == "clear":
|
elif act == "clear":
|
||||||
self.persistence.global_action("write", "shopping_list", value=[])
|
self.persistence["global"]["lists"][lname] = []
|
||||||
output = "Cleared list."
|
output = "Cleared list " + lname
|
||||||
elif args[0] == "add":
|
elif act == "add":
|
||||||
if len(args) == 1:
|
if len(args) < 3:
|
||||||
output = "Missing parameter"
|
return "Missing paramaeter"
|
||||||
add = " ".join(args[1:])
|
add = " ".join(args[2:])
|
||||||
self.persistence.global_action("append_list", "shopping_list", value=add)
|
self.persistence["global"]["lists"][lname] += [add]
|
||||||
output = "Added " + add + "."
|
return "Added " + add + "."
|
||||||
elif args[0] == "remove":
|
elif act == "remove":
|
||||||
output = "Removed test."
|
return "Not working yet"
|
||||||
|
except:
|
||||||
|
output = "Could not handle your request. Maybe check the keys?"
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import time
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleWrapper():
|
|
||||||
"""Wrapper for the BOT-functionality"""
|
|
||||||
def __init__(self, bot_module, clock_module):
|
|
||||||
""""""
|
|
||||||
print("Initializing bot-functionality")
|
|
||||||
#######################################################################
|
|
||||||
|
|
||||||
self.bot = bot_module
|
|
||||||
self.clock = clock_module
|
|
||||||
|
|
||||||
# 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.message_loop()
|
|
||||||
|
|
||||||
|
|
||||||
def message_loop(self):
|
|
||||||
"""Calls the telegram entity regularly to check for activity"""
|
|
||||||
print("Starting bot mainloop")
|
|
||||||
while(True):
|
|
||||||
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
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
@ -6,15 +6,13 @@ import numpy
|
|||||||
|
|
||||||
|
|
||||||
from clock.api import led
|
from clock.api import led
|
||||||
import persistence.rw
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
#start of actual programm.
|
#start of actual programm.
|
||||||
class ClockFace(object):
|
class ClockFace(object):
|
||||||
"""Actual functions one might need for a clock"""
|
"""Actual functions one might need for a clock"""
|
||||||
|
|
||||||
def __init__(self, text_speed=18):
|
def __init__(self, text_speed=18, prst=""):
|
||||||
self.IO = led.OutputHandler(32,16)
|
self.IO = led.OutputHandler(32,16)
|
||||||
self.tspeed = text_speed
|
self.tspeed = text_speed
|
||||||
|
|
||||||
@ -136,5 +134,5 @@ class ClockFace(object):
|
|||||||
"""Runs a text message over the screen. Obviously needs the text"""
|
"""Runs a text message over the screen. Obviously needs the text"""
|
||||||
# keep in mind, in this case args is a tuple of all words
|
# keep in mind, in this case args is a tuple of all words
|
||||||
message_str = " ".join(args)
|
message_str = " ".join(args)
|
||||||
print("SENDING: " + message_str)
|
print("SHOWING (CLOCK): " + message_str)
|
||||||
self.text_scroll(message_str)
|
self.text_scroll(message_str)
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
import wrapper
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
|
|
||||||
class ClockWrapper(wrapper.Wrapper):
|
|
||||||
"""Wrapper for the CLOCK-functionality"""
|
|
||||||
def __init__(self, own_module, *other_modules):
|
|
||||||
""""""
|
|
||||||
super().__init__(own_module, *other_modules)
|
|
||||||
print("Initializing clock-functionality")
|
|
||||||
self.weather = {"weather":"", "high":"", "low":"", "show":"temps"}
|
|
||||||
self.mainloop(15)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def mainloop(self, sleep_delta):
|
|
||||||
"""Runs the showing of the clock-face periodically (better way?)"""
|
|
||||||
print("Starting clock mainloop")
|
|
||||||
self.prev_time = 0
|
|
||||||
self.prev_weather_time = datetime.datetime.fromtimestamp(0)
|
|
||||||
|
|
||||||
def perform_loop():
|
|
||||||
if self.prev_time != datetime.datetime.now().strftime("%H:%M"):
|
|
||||||
d = datetime.datetime.now() - self.prev_weather_time
|
|
||||||
mins_elapsed = int(d.total_seconds()/60)
|
|
||||||
|
|
||||||
if mins_elapsed >= 3*60:
|
|
||||||
# fetch new weather every 3 hours (hard coded)
|
|
||||||
prev_weather_time = datetime.datetime.now()
|
|
||||||
weather = self.others[0].bot_show_weather("zurich")
|
|
||||||
if not (":sad:" in weather):
|
|
||||||
l1 = weather[weather.find("</b>")+5:weather.find("\n")].replace (":","")
|
|
||||||
# current weather situation (icon): we pick the first line, remove the start string, remove :: indicating an emoji
|
|
||||||
|
|
||||||
temps_today = weather.splitlines()[4]
|
|
||||||
low = temps_today[temps_today.find("button")+8:temps_today.find("°")]
|
|
||||||
temps_today = temps_today[temps_today.find("°") + 1:]
|
|
||||||
high = temps_today[temps_today.find("button")+8:temps_today.find("°")]
|
|
||||||
self.weather["weather"] = l1
|
|
||||||
self.weather["high"] = high
|
|
||||||
self.weather["low"] = low
|
|
||||||
else:
|
|
||||||
self.weather["weather"] = "error"
|
|
||||||
self.weather["high"] = "error"
|
|
||||||
self.weather["low"] = "error"
|
|
||||||
|
|
||||||
if mins_elapsed % 5 == 0:
|
|
||||||
if self.weather["show"] == "weather":
|
|
||||||
next = "temps"
|
|
||||||
else:
|
|
||||||
next = "weather"
|
|
||||||
self.weather["show"] = next
|
|
||||||
|
|
||||||
prev_time = datetime.datetime.now().strftime("%H:%M")
|
|
||||||
|
|
||||||
self.own.set_face(self.weather)
|
|
||||||
|
|
||||||
super().mainloop(sleep_delta,perform_loop)
|
|
39
launcher.py
39
launcher.py
@ -4,13 +4,11 @@ import clock.main
|
|||||||
import dashboard.main
|
import dashboard.main
|
||||||
|
|
||||||
# wrapper
|
# wrapper
|
||||||
import clock_wrapper
|
import wrapper
|
||||||
import bot_wrapper
|
|
||||||
import dashboard_wrapper
|
|
||||||
|
|
||||||
# misc.
|
# misc.
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
import shelve
|
||||||
|
|
||||||
|
|
||||||
class Launcher():
|
class Launcher():
|
||||||
@ -18,8 +16,11 @@ class Launcher():
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
""""""
|
""""""
|
||||||
self.bot_module = bot.main.ChatBot("ChatterBot", "2.0")
|
self.persistence = shelve.open('persistence/prst.db', writeback=True)
|
||||||
self.clock_module = clock.main.ClockFace()
|
self.init_persistence()
|
||||||
|
# TODO populate the persistence
|
||||||
|
self.bot_module = bot.main.ChatBot(name="ChatterBot", version="2.1", prst=self.persistence)
|
||||||
|
self.clock_module = clock.main.ClockFace(prst=self.persistence)
|
||||||
|
|
||||||
self.threads = []
|
self.threads = []
|
||||||
self.threads.append(Thread(target=self.chatbot))
|
self.threads.append(Thread(target=self.chatbot))
|
||||||
@ -30,18 +31,32 @@ class Launcher():
|
|||||||
|
|
||||||
|
|
||||||
def clock(self):
|
def clock(self):
|
||||||
print("Launching clock-functionality")
|
self.clock = wrapper.ClockWrapper(self.clock_module, self.bot_module)
|
||||||
self.clock = clock_wrapper.ClockWrapper(self.clock_module, self.bot_module)
|
|
||||||
|
|
||||||
|
|
||||||
def chatbot(self):
|
def chatbot(self):
|
||||||
print("Launching bot-functionality")
|
self.bot = wrapper.BotWrapper(self.bot_module, self.clock_module)
|
||||||
self.bot = bot_wrapper.ModuleWrapper(self.bot_module, self.clock_module)
|
|
||||||
|
|
||||||
|
|
||||||
def dashboard(self):
|
def dashboard(self):
|
||||||
print("Launching dashboard-functionality")
|
self.dashboard = wrapper.DashBoardWrapper(self.dashboard_module, self.bot_module)
|
||||||
self.dashboard = dashboard_wrapper.DashBoardWrapper(self.dashboard_module, self.bot_module)
|
|
||||||
|
def init_persistence(self):
|
||||||
|
self.persistence["bot"] = {
|
||||||
|
"messages_read": 0,
|
||||||
|
"messages_sent": 0,
|
||||||
|
"commands_executed": 0,
|
||||||
|
"photos_sent": 0,
|
||||||
|
"log": [],
|
||||||
|
"chat_members": {},
|
||||||
|
"reboots": 0
|
||||||
|
}
|
||||||
|
self.persistence["clock"] = {}
|
||||||
|
self.persistence["dashboard"] = {}
|
||||||
|
self.persistence["global"] = {
|
||||||
|
"lists" : {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## Aand liftoff!
|
## Aand liftoff!
|
||||||
|
@ -1 +0,0 @@
|
|||||||
# Placeholder
|
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"bot" : {
|
|
||||||
"messages_read": 0,
|
|
||||||
"messages_sent": 0,
|
|
||||||
"commands_executed": 0,
|
|
||||||
"photos_sent": 0,
|
|
||||||
"log": [],
|
|
||||||
"chat_members": {},
|
|
||||||
"reboots": 0
|
|
||||||
},
|
|
||||||
|
|
||||||
"clock" : {
|
|
||||||
"test":""
|
|
||||||
},
|
|
||||||
"dashboard" : {
|
|
||||||
"test":""
|
|
||||||
},
|
|
||||||
"global" : {
|
|
||||||
"shopping_list" : []
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
import json
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
class Variables():
|
|
||||||
""""""
|
|
||||||
|
|
||||||
def __init__(self, module_name, file_name="persistence/persistent_vars.json", init_name="persistence/persistent_init.json", ):
|
|
||||||
self.path = file_name
|
|
||||||
self.init_path = init_name
|
|
||||||
|
|
||||||
self.module = module_name
|
|
||||||
|
|
||||||
self.last_action = ""
|
|
||||||
# last performed action, if only reads are made, then the underlying var has not been changed
|
|
||||||
# and doesn't need to be read again
|
|
||||||
self.savefile = {}
|
|
||||||
|
|
||||||
if not os.path.exists(self.path):
|
|
||||||
shutil.copy(self.init_path, self.path)
|
|
||||||
|
|
||||||
|
|
||||||
def global_action(self, action, name, value=""):
|
|
||||||
old = self.module
|
|
||||||
self.module = "global"
|
|
||||||
action = getattr(self, action)
|
|
||||||
if value != "":
|
|
||||||
ret = action(name,value)
|
|
||||||
else:
|
|
||||||
ret = action(name)
|
|
||||||
self.module = old
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def write(self, name, value):
|
|
||||||
pre = self.read("")
|
|
||||||
pre[self.module][name] = value
|
|
||||||
try:
|
|
||||||
file = open(self.path,"w")
|
|
||||||
json.dump(pre, file)
|
|
||||||
file.close()
|
|
||||||
self.last_action = "write"
|
|
||||||
except:
|
|
||||||
print("Config not written - critical")
|
|
||||||
|
|
||||||
|
|
||||||
def read(self, name):
|
|
||||||
if self.last_action == "read":
|
|
||||||
vars = self.savefile
|
|
||||||
else:
|
|
||||||
file = open(self.path,"r")
|
|
||||||
vars = json.load(file)
|
|
||||||
file.close()
|
|
||||||
self.savefile = vars
|
|
||||||
self.last_action = "read"
|
|
||||||
|
|
||||||
if name != "":
|
|
||||||
vars = vars[self.module][name]
|
|
||||||
return vars
|
|
||||||
|
|
||||||
|
|
||||||
def increment(self, name, inc=1):
|
|
||||||
pre = self.read(name)
|
|
||||||
if pre:
|
|
||||||
self.write(name, pre + inc)
|
|
||||||
else:
|
|
||||||
self.write(name, inc)
|
|
||||||
|
|
||||||
|
|
||||||
def append_list(self, name, value):
|
|
||||||
pre = self.read(name)
|
|
||||||
pre.append(value)
|
|
||||||
self.write(name, pre)
|
|
||||||
|
|
||||||
|
|
||||||
def read_ext_file(self, path):
|
|
||||||
"""returns content of given file"""
|
|
||||||
if not os.path.exists(path):
|
|
||||||
return "File does not exist"
|
|
||||||
file = open(path,"r")
|
|
||||||
content = file.read()
|
|
||||||
file.close()
|
|
||||||
return content
|
|
103
wrapper.py
103
wrapper.py
@ -1,4 +1,6 @@
|
|||||||
import time
|
import time
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
class Wrapper():
|
class Wrapper():
|
||||||
"""Wrapper skeleton for the modules (bot, clock dashboard...)"""
|
"""Wrapper skeleton for the modules (bot, clock dashboard...)"""
|
||||||
@ -6,12 +8,113 @@ class Wrapper():
|
|||||||
def __init__(self, own_module, *other_modules):
|
def __init__(self, own_module, *other_modules):
|
||||||
self.own = own_module
|
self.own = own_module
|
||||||
self.others = other_modules
|
self.others = other_modules
|
||||||
|
print("Starting " + self.__class__.__name__ + " functionality")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def mainloop(self, sleep_delta, action):
|
def mainloop(self, sleep_delta, action):
|
||||||
"""sleep_delta in seconds sets the sleep period of the loop
|
"""sleep_delta in seconds sets the sleep period of the loop
|
||||||
action is a function that is performed every * seconds"""
|
action is a function that is performed every * seconds"""
|
||||||
|
print("Launching " + self.__class__.__name__ + " mainloop")
|
||||||
while True:
|
while True:
|
||||||
action()
|
action()
|
||||||
time.sleep(sleep_delta)
|
time.sleep(sleep_delta)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ClockWrapper(Wrapper):
|
||||||
|
"""Wrapper for the CLOCK-functionality"""
|
||||||
|
def __init__(self, own_module, *other_modules):
|
||||||
|
""""""
|
||||||
|
super().__init__(own_module, *other_modules)
|
||||||
|
self.weather = {"weather":"", "high":"", "low":"", "show":"temps"}
|
||||||
|
self.mainloop(15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def mainloop(self, sleep_delta):
|
||||||
|
"""Runs the showing of the clock-face periodically (better way?)"""
|
||||||
|
|
||||||
|
self.prev_time = 0
|
||||||
|
self.prev_weather_time = datetime.datetime.fromtimestamp(0)
|
||||||
|
|
||||||
|
def perform_loop():
|
||||||
|
if self.prev_time != datetime.datetime.now().strftime("%H:%M"):
|
||||||
|
d = datetime.datetime.now() - self.prev_weather_time
|
||||||
|
mins_elapsed = int(d.total_seconds()/60)
|
||||||
|
|
||||||
|
if mins_elapsed >= 3*60:
|
||||||
|
# fetch new weather every 3 hours (hard coded)
|
||||||
|
self.prev_weather_time = datetime.datetime.now()
|
||||||
|
weather = self.others[0].bot_show_weather("zurich")
|
||||||
|
if not (":sad:" in weather):
|
||||||
|
l1 = weather[weather.find("</b>")+5:weather.find("\n")].replace (":","")
|
||||||
|
# current weather situation (icon): we pick the first line, remove the start string, remove :: indicating an emoji
|
||||||
|
|
||||||
|
temps_today = weather.splitlines()[4]
|
||||||
|
low = temps_today[temps_today.find("button")+8:temps_today.find("°")]
|
||||||
|
temps_today = temps_today[temps_today.find("°") + 1:]
|
||||||
|
high = temps_today[temps_today.find("button")+8:temps_today.find("°")]
|
||||||
|
self.weather["weather"] = l1
|
||||||
|
self.weather["high"] = high
|
||||||
|
self.weather["low"] = low
|
||||||
|
else:
|
||||||
|
self.weather["weather"] = "error"
|
||||||
|
self.weather["high"] = "error"
|
||||||
|
self.weather["low"] = "error"
|
||||||
|
|
||||||
|
if mins_elapsed % 5 == 0:
|
||||||
|
if self.weather["show"] == "weather":
|
||||||
|
next = "temps"
|
||||||
|
else:
|
||||||
|
next = "weather"
|
||||||
|
self.weather["show"] = next
|
||||||
|
|
||||||
|
self.prev_time = datetime.datetime.now().strftime("%H:%M")
|
||||||
|
|
||||||
|
self.own.set_face(self.weather)
|
||||||
|
|
||||||
|
super().mainloop(sleep_delta,perform_loop)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BotWrapper(Wrapper):
|
||||||
|
"""Wrapper for the BOT-functionality"""
|
||||||
|
def __init__(self, own_module, *other_modules):
|
||||||
|
""""""
|
||||||
|
super().__init__(own_module, *other_modules)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user