def main(): if len(sys.argv) != 2: return fileName = sys.argv[1] file = None try: # ファイルから問題の条件などを取得 file = open(fileName, "r") limits = __getMoveLimit(file.readline()) numBoard = __getNumBoard(file.readline()) Logging.debug('Start solving ' + str(numBoard) + ' problems') # 問題を解くループ noProblem = 1 numSolved = 0 for row in file: Logging.debug('Start solving No.%d problem' % noProblem) solve = solve_exercises(row, limits) if limits.isOver(): break # 問題の回答を出力 if str(solve) == '': Logging.debug('Failed!') else: Logging.debug('Success!') numSolved += 1 Logging.output(solve) noProblem += 1 Logging.debug('Solving ' + str(numBoard) + ' problems finished -- ' + str(numSolved)) finally: if file != None: file.close()
def receive_forever(self): """ Puts the receiver in receiving mode forever. In this mode the receiver blocks until new data is received from the sender. Every time a new chunk of data is received it calls the registered handlers' on_new_data() method. """ while True: # allow reconnecting on error try: Logging.debug("Trying to connect to %s:%s..." % (self._sender_address[0], self._sender_address[1])) with sock.create_connection(self._sender_address, timeout=30) as connection: for handler in self._connection_handlers: handler.on_new_connection(self, connection, self._sender_address) Logging.debug("Connected successfully") while True: try: Logging.info("Waiting for data...") data = self.receive(connection) Logging.info("Received data") for handler in self._data_handlers: handler.on_new_data(data) except InvalidFormatException as error: # data was not correct Logging.warning("Received data with invalid format:" " %s" % str(error)) except ConnectionAbortedError: Logging.warning("connection aborted by the sender") except sock.timeout: Logging.warning("connection timed out") except (sock.herror, sock.gaierror): Logging.error("the address of the sender is not valid") break # leave the function except ConnectionRefusedError: Logging.warning("can not reach the sender") # retry in connecting in 10 seconds Logging.debug( "connection failed: will try to connect in 10 seconds") sleep(10)
class pf_openhab(Singleton): def __init__(self): try: if self.loadingdone: pass except: self.loadingdone = True self.logging = Logging() settings_c = Settings() self.openhab_server = settings_c.get_setting("main", "openhab_ip") self.openhab_port = settings_c.get_setting("main", "openhab_port") self.host = settings_c.get_setting("main", "hostname") self.port = settings_c.get_setting("main", "port") self.sitemap_name = settings_c.get_setting("main", "sitemap") self.sitemap_name = "main" if self.sitemap_name == None else self.sitemap_name self.resize_icons = settings_c.get_setting("main", "resize_icons") self.iconh = 64 self.iconw = 64 self.name = "pf_openhab" self.http = urllib3.PoolManager() def get_pages(self, filter): if type(filter) != list: filter = [filter] self.load_sitemap() data = [] n = 0 for i in range(len(self.sitemap["homepage"]["widgets"][0]["widgets"])): key = self.sitemap["homepage"]["widgets"][0]["widgets"][i] found = False for filt in filter: if key["label"][0:len(filt)] == filt and not found: icon_url = "/item/icon/" + key["icon"] + ".png" data.append({ "label": key["label"], "icon": icon_url, "id": n }) found = True n += 1 return data def get_page(self, name): for i in range(len(self.sitemap["homepage"]["widgets"][0]["widgets"])): key = self.sitemap["homepage"]["widgets"][0]["widgets"][i] if key["label"] == name: return key def get_items(self, pagename, subpage="none", subsubpage=0): self.load_sitemap() page = self.get_page(pagename) data = [] n_subp = 1 n = 0 page_type = [page["label"], page["icon"]] for key in page["linkedPage"]["widgets"]: n += 1 item = self.convert_item_data(key) item["id"] = item["name"] + "__" + pagename + "__" + str( subpage) + "__" + str(n) if subpage == "none" or str(subpage) == "0": if item["type"] == "Frame": item["page"] = pagename item["subpage"] = item["label"] data.append(item) elif item["type"] == "Frame" and item["label"] == subpage: page_type[0] = page_type[0] + " / " + key["label"] sub_n = 0 for k in key["widgets"]: sub_n += 1 item = self.convert_item_data(k) item["id"] = item["name"] + "__" + pagename + "__" + str( subpage) + "__" + str(sub_n) if item["type"] == "Frame": item["type"] = "Text" data.append(item) return [data, page_type] def load_sitemap(self): if self.host == None or self.openhab_server == None: #if self.openhab_server == None: data = self.load_error_sitemap(False) else: try: url = "http://" + self.openhab_server + ":" + self.openhab_port + "/rest/sitemaps/" + self.sitemap_name #print(url) content = self.http.request('GET', url) data = content.data.decode("utf-8") except: self.logging.error( "Error connecting to openHAB server, please check settings", location=self.name) data = self.load_error_sitemap(True) data = data.replace("true", "True").replace("false", "False") data = eval(data) self.sitemap = data def load_error_sitemap(self, exception): PATH = os.path.dirname(os.path.abspath(__file__)) errorfile = PATH + "/files/error_sitemap.txt" with open(errorfile, 'r') as f: data = f.read() if exception: data = data.replace("{{HOST_CONFIG_ERROR}}", "No error detected") data = data.replace("{{OPENHAB_CONFIG_ERROR}}", "Error connecting to server, check settings") else: data = data.replace("{{HOST_CONFIG_ERROR}}", "Check settings") data = data.replace("{{OPENHAB_CONFIG_ERROR}}", "Check settings") data = data.replace("{{IP}}", str(self.openhab_server)) data = data.replace("{{PORT}}", str(self.openhab_port)) data = data.replace("{{SITEMAP}}", str(self.sitemap_name)) data = data.replace("{{RESIZE}}", str(self.resize_icons)) data = data.replace("{{HOST_IP}}", str(self.host)) data = data.replace("{{HOST_PORT}}", str(self.port)) return data def get_item(self, item_name): name, pagename, subpage, n = self.split_item_name(item_name) #print(name, pagename, subpage, n) item = self.get_item_data(name, pagename, subpage, n) self.logging.debug("Item from get_item: " + str(item), location=self.name) return item def get_item_data(self, item_name, pagename, subpage, n): #search for the item self.load_sitemap() #print("Name: " + item_name) o = 1 subpage_o = 1 for i in range(len(self.sitemap["homepage"]["widgets"][0]["widgets"])): if self.sitemap["homepage"]["widgets"][0]["widgets"][i][ "label"] == pagename: for key in self.sitemap["homepage"]["widgets"][0]["widgets"][ i]["linkedPage"]["widgets"]: if key["label"].find("[") != -1: comp_label = key["label"][0:key["label"].find("[")] while comp_label[-1:] == " ": comp_label = comp_label[0:-1] else: comp_label = key["label"] try: if key["type"] == "Frame" and ( str(subpage_o) == subpage or comp_label == subpage): #print(subpage) sub_o = 0 for k in key["widgets"]: sub_o += 1 try: if k["item"][ "name"] == item_name and sub_o == n: item = self.convert_item_data(k) item["id"] = item[ "name"] + "__" + pagename + "__" + str( subpage) + "__" + str(n) item["page"] = pagename item["subpage"] = str(subpage) self.logging.debug("Item found, id: " + item["id"], location=self.name) return item except Exception as e: self.logging.warn( "Invalid item found in sitemap 2 %s" % (str(e)), location=self.name) elif "item" in key and key["item"][ "name"] == item_name and o == n: item = self.convert_item_data(key) item["id"] = item[ "name"] + "__" + pagename + "__" + str( subpage) + "__" + str(n) item["page"] = pagename item["subpage"] = str(subpage) self.logging.debug("Item found, id: " + item["id"], location=self.name) return item elif str(subpage) == "0" or subpage == "none": o += 1 elif key["type"] == "Frame": subpage_o += 1 o += 1 except Exception as e: self.logging.warn( "Invalid item found in sitemap 1: %s, %s" % (str(key), str(e)), location=self.name) def convert_item_data(self, key): #print(key) item_data = { "icon": key["icon"], "type": key["type"], "name": key["label"], "state": "" } if "item" in key: item_data.update({ "state": key["item"]["state"], "link": key["item"]["link"], "name": key["item"]["name"] }) if key["item"]["state"] != "" and key["item"]["state"].find( " ") == -1: item_data["icon"] = key["icon"] + "-" + key["item"]["state"] if "transformedState" in key["item"]: transformedState = key["item"]["transformedState"] if len(str(transformedState)) < 15: item_data.update( {"icon": key["icon"] + "-" + transformedState}) if "mappings" in key: item_data.update({"mappings": key["mappings"]}) if "label" in key: item_data.update({"label": key["label"]}) #### correct icon for state try: state = float(item_data["state"]) if state < 0.0: item_data["icon"] = key["icon"] + "-" + str(-1 * state + 100) except: if item_data["state"] == "NULL": item_data["state"] = "OFF" item_data["icon"] = key["icon"] + "-off" elif len(str(item_data["state"])) > 15: item_data["icon"] = key["icon"] #### transform state name if item_data["label"].find("[") != -1: label = item_data["label"][0:item_data["label"].find("[")] while label[-1:] == " ": label = label[0:-1] state = item_data["label"][item_data["label"].find("[") + 1:item_data["label"].find("]")] item_data.update({"state": state, "label": label}) if key["type"] == "Colorpicker": if item_data["state"].lower() != "off": item_data["state"] = self.convert_color_to_rgb( item_data["state"]) item_data["icon"] = key["icon"] + "-on" if len(item_data["state"].split(",")) > 2: if item_data["state"].split(",")[2] == "0" or item_data[ "state"].split(",")[2] == "0.0": item_data.update({ "state": "off", "icon": key["icon"] + "-off" }) elif key["type"] == "Selection": item_state = "" if len(key["mappings"]) == 1: item_data["type"] = "Switch_single" item_state = key["mappings"][0]["label"] for mapp in key["mappings"]: if mapp["command"].lower() == item_data["state"].lower(): ## mappings are like [ displayed state, actual state ] item_state = mapp["label"] elif mapp["label"].lower() == item_data["state"].lower(): item_state = mapp[ 'label'] ##sometimes a state is 0 ==> OFF, which is not mapped correctly with Off or 0 try: ##why is this????? #print(item_state) int(item_state) item_data.update({"item_state": item_data["label"]}) item_data.update({"label": "_"}) except: item_data.update({"state": item_state}) elif key["type"] == "Setpoint": try: step = round(float(key["step"]), 1) if int(step) == step: step = int(step) item_data.update({ "setpoint": [int(key["minValue"]), int(key["maxValue"]), step] }) except: pass elif key["type"] == "Slider": item_data.update({"setpoint": [0, 100, 10]}) ##update the icon to the right url: if self.resize_icons == "1": item_data["icon"] = "/item/icon/" + item_data["icon"] + ".png" else: item_data[ "icon"] = "http://" + self.openhab_server + ":" + self.openhab_port + "/icon/" + item_data[ "icon"] + ".png" return item_data def set_state(self, item_name, state): item, pagename, subpage, n = self.split_item_name(item_name) if state[0:5] == "Color": state = self.convert_color_to_hsv(state[5:]) #cmd = "curl --header \"Content-Type: text/plain\" --request POST --data \"" + state+ "\" " + self.openhab_server + ":" + self.openhab_port + "/rest/items/" + item url = "http://" + self.openhab_server + ":" + self.openhab_port + "/rest/items/" + item headers = {'Content-Type': 'text/plain'} requests.post(url, data=state, headers=headers) self.logging.info("Put state openhab: " + url + " " + str(state), location="openhab") #os.system(cmd) #print(cmd) self.load_sitemap() return self.get_item(item_name) def get_mappings(self, item_name, occurrence=1): ##self.load_sitemap() item = self.get_item(item_name) mappings = [] for mapping in item["mappings"]: mappings.append([mapping["label"], mapping["command"]]) return mappings def convert_color_to_rgb(self, color): if color == "": color = "0.0,0.0,0" color = color.split(",") color = colorsys.hsv_to_rgb( float(color[0]) / 360, float(color[1]) / 100, float(color[2]) / 100) red = hex(int(color[0] * 255))[2:] if len(red) < 2: red = "0" + red blue = hex(int(color[1] * 255))[2:] if len(blue) < 2: blue = "0" + blue green = hex(int(color[2] * 255))[2:] if len(green) < 2: green = "0" + green return "#" + red + blue + green def convert_color_to_hsv(self, color): color = colorsys.rgb_to_hsv( float(int("0x" + color[0:2], 0)) / 255.0, float(int("0x" + color[2:4], 0)) / 255.0, float(int("0x" + color[4:6], 0)) / 255.0) return str(color[0] * 360) + "," + str(color[1] * 100) + "," + str( color[2] * 100) def get_icon(self, name): URL = "http://" + self.openhab_server + ":" + self.openhab_port + "/icon/" + name response = requests.get(URL) with Image.open(BytesIO(response.content)) as image: imgByteArr = BytesIO() cover = Image.Image.resize(image, [self.iconh, self.iconw]) cover.save(imgByteArr, image.format) return imgByteArr.getvalue() def get_chart_data(self, item, period): try: p = int(period[0:len(period) - 1]) except: p = 1 if period[-1:] == "D": dt = datetime.datetime.now() - datetime.timedelta(days=p) elif period[-1:] == "H": p += 1 dt = datetime.datetime.now() - datetime.timedelta(hours=p) elif period[-1:] == "W": dt = datetime.datetime.now() - datetime.timedelta(weeks=p) elif period[-1:] == "M": dt = datetime.datetime.now() - relativedelta(months=p) start = dt.strftime("%Y-%m-%dT%H:%M:%S.000+01:00") self.logging.info("Starting date for data: " + start, location="openhab") start = start.replace("+", "%2B").replace(":", "%3A") name, pagename, subpage, n = self.split_item_name(item) URL = "http://" + self.openhab_server + ":" + self.openhab_port + "/rest/persistence/items/" + name + "?serviceId=rrd4j&starttime=" + start response = requests.get(URL) ## get item info i = self.get_item(item) if i == None: return None else: if i["icon"].lower().find("temp") != -1: typ = "temp" elif i["icon"].lower().find("humi") != -1: typ = "humi" elif i["icon"].lower().find("press") != -1: typ = "pres" elif i["icon"].lower().find("energy") != -1: typ = "watt" else: typ = "value" return {"data": response.content, "type": typ} def split_item_name(self, item_name): a = item_name.split("__") if len(a) > 1: name = a[0] pagename = a[1] subpage = a[2] n = int(a[3]) else: return item_name return name, pagename, subpage, n
class widgets_handler: def __init__(self): self.openhab = pf_openhab() self.logging = Logging() self.name = "widget_handler" PATH = os.path.dirname(os.path.abspath(__file__)) self.template_dir = PATH + "/../templates/" self.imported_widget_classes = {} def render_widget(self, page, lowerpage): w_info = self.get_widget_info(lowerpage, main_page=page) data = self.openhab.get_items(page, lowerpage) item_data = self.render_item_data_for_widget(data[0]) try: item_data = self.get_widget_data(w_info, item_data) if "error" in item_data: return render_template("error.html", data=item_data) except Exception as e: self.logging.error("Error creating widget %s" % str(e), location=self.name) er = self.render_widget_error(e, lowerpage) return render_template("error.html", data={"error": str(er)}) item_data["gen_name"] = w_info["name"] item_data["pagename"] = page try: self.logging.debug("Rendering widget: %s" % w_info["template"], location=self.name) return render_template("widgets/%s.html" % w_info["template"].lower(), data=item_data) except Exception as e: self.logging.error("Error creating widget %s" % str(e), location=self.name) er = self.render_widget_error(e, lowerpage) return render_template("error.html", data={"error": str(er)}) def create_mainpage_popup(self, page, subpage, menuwidget=False): if page == "none": ##in case the widget is on the main page data = self.openhab.get_items(subpage, page) else: data = self.openhab.get_items(page, subpage) item_data = self.render_item_data_for_widget(data[0]) if len(item_data) == 0: #return "widget not in sitemap" self.logging.error("Widget is not in sitemap", location=self.name) er = self.render_widget_error("widget not in sitemap", subpage) return render_template("popups/error.html", data={"error": str(er)}) info = self.get_widget_info(subpage, main_page=page) try: item_data = self.get_widget_data(info, item_data) if "error" in item_data: return render_template("popups/error.html", data=item_data) except Exception as e: self.logging.error("Error creating widget %s" % str(e), location=self.name) er = self.render_widget_error(e, subpage) if menuwidget: return render_template("popups/error.html", data={"error": str(er)}), "Error" else: return render_template("popups/error.html", data={"error": str(er)}) item_data["page_name"] = page item_data["widget_name"] = subpage item_data["menuwidget"] = menuwidget if info == None: return render_template( "popups/error.html", data={ "error": "Popup widget template for %s does not exist" % subpage.lower() }) elif info["template"] == "generic_button_page": return info["template"] else: try: self.logging.debug("Rendering popup widget: %s" % info["template"], location=self.name) data = render_template("popup_widgets/" + info["template"] + ".html", data=item_data) if menuwidget: title = self.find_var(data, "Title") if title == None: title = "" return data, title else: return data except Exception as e: self.logging.error("Error creating popup widget %s" % str(e), location=self.name) er = self.render_widget_error(e, subpage) if menuwidget: return render_template("popups/error.html", data={"error": str(er)}), "Error" else: return render_template("popups/error.html", data={"error": str(er)}) def get_widget_data(self, w_info, item_data): if w_info["name"] not in self.imported_widget_classes: try: a = __import__(w_info["name"] + "_widget") self.imported_widget_classes[w_info["name"]] = getattr( a, w_info["name"] + "_widget")() except Exception as e: self.logging.warn("Could not create widget %s" % str(e), location=self.name) self.logging.warn("Could not create widget %s" % str(w_info["name"]), location=self.name) self.logging.warn("Importing normal widget", location=self.name) a = __import__("widget") self.imported_widget_classes[w_info["name"]] = a.widget() cl = self.imported_widget_classes[w_info["name"]] item_data = cl.get_data(item_data) return item_data def check_widget_type(self, name): if name[0:2] == "m_": return "menu_button" if name[0:2] in ["a_"]: return "menu_popup" if name[0:2] in ["b_"]: return "widget_popup" if name[0:2] in ["c_"]: return "widget_subpage" if name[0:2] == "s_": info = self.get_widget_info(name) return "widget_" + str(info["rows"]) else: return name def get_widget_label(self, name): for n in ["b_"]: if name.find(n) != -1: return name[name.find(n) + 2:] if name.find("[") != -1 and name.find("]") != -1: name = name[name.find("[") + 1:name.find("]")] return name for n in ["m_", "a_", "b_", "c_", "d_"]: if name.find("/ " + n) != -1: return name[name.find("/ " + n) + 4:] if name.find(n) != -1: return name[name.find(n) + 2:] i = self.get_widget_info(name) if i == None: return name else: return i["name"] def get_widget_info(self, name, main_page="none"): ## s_ frontpage widget with possible popup widget ## a_ generic button page (with large button on frontpage ## b_ bottom page ## c_ popup widget with button ## d_ popup widget with button ## m_ generic button linking to a page instead of popup widget_data = {} widget_data["a_"] = { "type": "popup_widget", "name": name[2:], "template": "generic_button_page" } if name[0:2] in widget_data: return widget_data[name[0:2]] else: ##try to find the info from the widget template data = "_" name_lower = name[2:].lower() if name[0:2] == "s_": ##widget f_name = self.template_dir + "widgets/" + name_lower + ".html" if Path(f_name).is_file(): with open(f_name, 'r') as myfile: data = myfile.read().replace('\n', '') n = self.find_var(data, "Name") rows = self.find_var(data, "Rows") title = self.find_var(data, "Title") if rows != None and n != None: return { "title": title, "name": n, "rows": int(rows), "template": name_lower, "type": "frontpage_widget", "pagename": main_page } else: ##popup f_name = self.template_dir + "popup_widgets/" + name_lower + ".html" if Path(f_name).is_file(): with open(f_name, 'r') as myfile: data = myfile.read().replace('\n', '') n = self.find_var(data, "Name") if n != None: return { "name": n, "template": name_lower, "type": "popup_widget", "pagename": main_page } return None def find_var(self, data, var): if data.find(var + "=") != -1: pos = data.find(var + "=") pos2 = data[pos + len(var) + 1:].find("/") return data[pos + len(var) + 1:pos + len(var) + 1 + pos2] else: return None def render_item_data_for_widget(self, data): d = {} for dat in data: dat["state_length"] = len(dat["state"]) d[dat["label"].lower()] = dat return d def render_widget_error(self, e, w): e = str(e) if e.find("attribute") != -1: pos = e.find("attribute") n = e[pos + 10:] return "Please add an item labeled %s to the widget named %s" % ( n, str(w)) else: return "Widget: " + str(w) + " " + str(e)
class mqtt(Singleton): def __init__(self): try: if self.loadingdone: pass except: self.loadingdone = True self.started = True self.logging = Logging() self.name = "mqtt" self.settings_c = Settings() try: self.server = self.settings_c.get_setting("mqtt", "server") self.port = int(self.settings_c.get_setting("mqtt", "port")) self.timeout = int( self.settings_c.get_setting("mqtt", "timeout")) except Exception as e: self.logging.error("Configuration not correct, check settings", location=self.name) self.listeners = [] self.client = mqtt_cl.Client() self.client.on_connect = self.on_connect self.client.on_message = self.on_message self.client.connect(self.server, self.port, self.timeout) self.client.loop_start() self.logging.info("Connected to mqtt broker at: " + self.server, location=self.name) def on_connect(self, client, userdata, flags, rc): self.logging.info("Resubscribing for all listeners at " + self.server, location=self.name) for listen in self.listeners: self.client.subscribe(listen[0]) def on_message(self, client, userdata, msg): self.logging.info("Received message: " + msg.topic + " " + str(msg.payload), location=self.name) if self.started: for listen in self.listeners: topic = listen[0][0:-1] if msg.topic.find(topic) != -1: self.logging.debug("Topic match for %s at %s" % (listen[1].get_name(), listen[0]), location=self.name) try: data = ast.literal_eval(msg.payload.decode("utf-8")) except: data = msg.payload.decode("utf-8") try: p = getattr(listen[1], listen[2]) p(msg.topic, data) except Exception as e: self.logging.error("Error executing: " + str(e), location=self.name) def add_listener(self, topic, class_item, functionname): self.listeners.append([topic, class_item, functionname]) self.client.subscribe(topic) try: name = class_item.get_name() except: name = "unknown" self.logging.info("Added listener for %s at %s" % (name, topic), location=self.name) def publish(self, topic, payload): self.logging.info("Publish %s, %s " % (topic, str(payload)), location=self.name) self.client.publish(topic, payload)
class message_handler(Singleton): def __init__(self): try: if self.loadingdone: pass except: self.loadingdone = True self.database = main_database() self.popupflag = False self.popupactive = False self.logging = Logging() self.setting_handler = setting_handler() self.setting_popup_timeout = self.setting_handler.get_setting( "message_timeout") self.page_handler = page_handler.page_handler() self.toast_flag = False self.toast_db = [] self.toast_message = "none" self.toast_sender = "none" self.toast_received = 0 self.mqtt = mqtt() settings_c = Settings() self.mqtt_topics = settings_c.get_setting("messaging", "mqtt_topics").split(",") for topic in self.mqtt_topics: self.mqtt.add_listener(topic, self, "received_mqtt_message") ##send information messages on first run if not self.database.data["settings"]["first_run_messages_flag"]: self.database.data["settings"][ "first_run_messages_flag"] = True message = "On a black screen, clock or photoframe, click on the bottom left corner to return to the main screen. " self.database.data["messages"].append([ time.time(), "HABframe", "Return from screensaver", message, False ]) message = "Thank you for using HABframe!" self.database.data["messages"].append([ time.time(), "HABframe", "welcome message", message, False ]) self.database.save_datafile() self.del_popup_flag() def get_name(self): return "message_handler" def message_request(self, request, data_get): if request[0] == "new": try: if "message" in data_get: message = data_get["message"].replace("@20", "/").replace( "%3B", ":") else: message = request[2].replace("@20", "/").replace("%3B", ":") if "sender" in data_get: sender = data_get["sender"] else: sender = request[1] if "subject" in data_get: subject = data_get["subject"] else: subject = "-" self.new_message(sender, subject, message) return ["Message received"] except Exception as e: self.logging.error("Error in message: " + str(e), location="messages") return ["Invalid new message"] elif request[0] == "message_popup": i = 0 found = False while i < len(self.database.data["messages"]) and not found: message = self.database.data["messages"][i] if not message[-1]: show_message = [i] + message #we want the last unread message #found = True i += 1 n_unread = self.check_amount_unread() times = datetime.datetime.fromtimestamp(float( show_message[1])).strftime('%a %d-%m, %H:%M') return self.page_handler.create_popup("message", { "id": show_message[0], "from": show_message[2], "time": times, "message": show_message[4], "subject": show_message[3], "n_unread": n_unread }, renew_screensaver=False) elif request[0] == "markread_popup": message_id = int(request[1]) self.logging.info("Marking message as read " + str(message_id), location="messages") self.database.data["messages"][message_id][-1] = True self.database.save_datafile() self.popupactive = False self.del_popup_flag() return ["Marked as read"] elif request[0] == "markallread_popup": message_id = int(request[1]) self.logging.info("Marking all messages as read ", location="messages") for i in range(len(self.database.data["messages"])): self.database.data["messages"][i][-1] = True self.database.save_datafile() self.popupactive = False self.del_popup_flag() return ["Marked as read"] elif request[0] == "message_timeout": timeout = self.setting_handler.get_setting("message_timeout") return [str(timeout)] elif request[0] == "toast_timeout": timeout = self.setting_handler.get_setting("toast_timeout") return [str(timeout)] elif request[0] == "delete_popup": message_id = int(request[1]) del (self.database.data["messages"][message_id]) self.logging.info("Deleting message: " + str(message_id), location="messages") if len(self.database.data["messages"]) == 0: self.database.data["messages"] = [] #self.database.data["messages"].append([time.time(), "none", "message database is empty", True]) self.database.save_datafile() self.popupactive = False self.del_popup_flag() return ["Message deleted"] elif request[0] == "deactivate_popup": self.popupactive = False return ["popup deactive"] elif request[0] == "showmessage": message_id = int(request[1]) return self.format_message(message_id=message_id) elif request[0] == "deletemessage": if request[1] == "all": self.database.data["messages"] = [] #self.database.data["messages"].append([time.time(), "none", "message database is empty", True]) else: message_id = int(request[1]) del (self.database.data["messages"][message_id]) self.logging.info("Deleting message: " + str(message_id), location="messages") if len(self.database.data["messages"]) == 0: self.database.data["messages"] = [] #self.database.data["messages"].append([time.time(), "none", "message database is empty", True]) self.database.save_datafile() return self.format_message_list(start=0) elif request[0] == "showmessagepage": message_id = int(request[1]) return self.format_message_list(start=message_id) elif request[0] == "toast": if "message" in data_get: self.toast_message = data_get["message"].replace( "@20", "/").replace("%3B", ":") else: self.toast_message = request[2].replace("@20", "/").replace( "%3B", ":") if "sender" in data_get: self.toast_sender = data_get["sender"].replace("@20", "/").replace( "%3B", ":") else: self.toast_sender = request[1].replace("@20", "/").replace( "%3B", ":") self.logging.debug("Received new toast message from http", location="messages") self.new_toast() return ["Toast received"] elif request[0] == "get_toast": return self.create_toast(len_max=31) def new_message(self, sender, subject, message): self.database.data["messages"].append( [time.time(), sender, subject, message, False]) self.database.save_datafile() self.del_popup_flag() ##popup flag when a popup was activated self.logging.write("Received new message from " + sender + ": " + message, level="info", location="messages") def new_toast(self): self.toast_received = time.time() self.toast_db.append( [self.toast_sender, self.toast_message, time.time(), False, 0]) self.logging.info("Received new toast message: " + self.toast_message, location="messages") def create_toast(self, len_max): toast = self.get_toast_message() data = { "text": toast[0], "from": toast[1], "len": len(toast[0]), "max": len_max } return self.page_handler.create_popup("toast", data=data, renew_screensaver=False) def get_messages(self): messages = [] for i in reversed(range(len(self.database.data["messages"]))): m = self.database.data["messages"][i] messages.append({ "id": i, "date": m[0], "from": m[1], "subject": m[2], "message": m[3] }) return messages def check_amount_unread(self): unread = 0 for message in self.database.data["messages"]: if not message[-1]: unread += 1 return unread def check_unread(self): unread = False for message in self.database.data["messages"]: if not message[-1]: unread = True return unread def get_popup_flag( self ): ##The popup flag is set when a new message has generated a popup return self.popupflag def set_popup_flag(self): self.logging.write("Setting popup flag", level="warn", location="messages") self.popupflag = True def del_popup_flag(self): ##Only a new message can delete a popup if self.popupflag: self.logging.write("Removing popup flag", level="warn", location="messages") self.popupflag = False def get_popup_active(self): if time.time( ) > self.popup_time_activated + self.setting_popup_timeout + 1: ##seconds return False else: return True def set_popup_active(self, state): self.popup_time_activated = time.time() def check_toast(self): #print("=========================, checking toast") timeout = self.setting_handler.get_setting("toast_timeout") new_toast = False last_toast_send = 0 for i in range(len(self.toast_db)): if self.toast_db[i][3]: last_toast_send = self.toast_db[i][4] if self.toast_db[i][2] < time.time() - 600: self.toast_db[i][3] = True if not self.toast_db[i][3]: new_toast = True if len(self.toast_db) > 50: del self.toast_db[0:25] if self.toast_received > time.time( ) - 600 and new_toast and last_toast_send < time.time() - timeout - 3: return True else: return False def get_toast_message(self): ##return the first unread toast message for i in range(len(self.toast_db)): if not self.toast_db[i][3]: ##toast is unread self.toast_db[i][3] = True self.toast_db[i][4] = time.time() self.logging.write("Sending toast message: " + self.toast_db[i][0] + " / " + self.toast_db[i][1], level=2, location="messages") return [self.toast_db[i][1], self.toast_db[i][0]] self.logging.write("No unread toast message, sending last one: " + self.toast_message + " / " + self.toast_sender, level="warning", location="messages") return [self.toast_message, self.toast_sender] def format_message_list(self, start=0): messages = self.get_messages() page_data = {"next_page": False, "prev_page": False, "messages": []} try: start_page = int(start) except: start_page = 0 if start_page == 0: start_message = 0 stop_message = 6 else: page_data["prev_page"] = start_page start_message = start_page * 5 + 1 stop_message = start_page * 5 + 6 n_messages = len(messages) if stop_message >= n_messages: stop_message = n_messages else: page_data["next_page"] = start_page + 1 for i in range(start_message, stop_message): messages[i]["date"] = datetime.datetime.fromtimestamp( messages[i]["date"]).strftime('%a %d-%m, %H:%M') page_data["messages"].append(messages[i]) return render_template("message_list.html", data=page_data) def format_message(self, message_id=0): messages = self.get_messages() if message_id == -1: message_id = len(messages) - 1 if len(messages) > 0: for m in messages: if m["id"] == message_id: message = m message["date"] = datetime.datetime.fromtimestamp( message["date"]).strftime('%a %d-%m, %H:%M') else: message = {"date": "", "message": "No messages", "from": ""} if len(messages) > 0 and message["subject"] == "-": message["subject"] = message["date"] return render_template("message.html", data=message) def received_mqtt_message(self, topic, payload): try: message = payload['message'] if "message" in topic.lower(): t = "message" elif "toast" in topic.lower(): t = "toast" else: try: t = payload['type'] except: t = 'message' try: sender = payload['sender'] except: sender = "unknown" if t == "message": subject = payload['subject'] self.new_message(sender, subject, message) else: self.toast_sender = sender self.toast_message = message self.new_toast() except Exception as e: raise Exception(e)
class item_handler(): def __init__(self): self.openhab = pf_openhab() self.name = "item_handler" self.database = main_database() self.setting_handler = setting_handler() self.page_handler = page_handler() self.message_handler = message_handler() self.logging = Logging() settings_c = Settings() self.host = settings_c.get_setting("main", "hostname") self.port = settings_c.get_setting("main", "port") self.enable_clock = settings_c.get_setting("main", "enable_clock") self.enable_album = settings_c.get_setting("main", "enable_album") self.openhab_server = settings_c.get_setting("main", "openhab_ip") self.openhab_port = settings_c.get_setting("main", "openhab_port") self.http = urllib3.PoolManager() self.timeout_message_popup = 0 self.saved_chart_periods = {} self.screentrigger = 0 def item_request(self, request): action = request[0] if len(request) > 1: item = request[1] if action != "photoframe" and action != "popup_chart" and action != "icon": item_info = self.openhab.get_item(item) self.logging.debug("Item info for request: " + str(item_info), location=self.name) ##handle a button press per type of item: #print(item) if action == "set": if item_info == None: return "none_none" elif item_info["type"] == "Switch_single": item_info = self.openhab.set_state( item, item_info["mappings"][0]["command"]) elif item_info["type"] == "Switch": if item_info["state"] == "ON": item_info = self.openhab.set_state(item, "OFF") else: item_info = self.openhab.set_state(item, "ON") return self.page_handler.create_item_button(item_info, header=False) elif action == "cmd": command = request[2] item_info = self.openhab.set_state(item, command) if item_info == None: return "reload_widget_popup" elif item_info["subpage"][0:2] in ["a_", "c_", "d_", "s_"]: return "reload_widget_popup" else: return self.page_handler.create_item_button(item_info, header=False) elif action == "popup": if item_info == None: return "none_none" #return self.page_handler.create_popup("error", data = { "error": "Invalid Item" }) self.setting_handler.screen_timeout_start = time.time() if item_info["state"][-1:] == "%": s = item_info["state"][0:-1] elif item_info["state"][-1:] == "C": s = item_info["state"][0:-2] else: s = item_info["state"] if item_info["type"] == "Selection": mappings = self.openhab.get_mappings(item) return self.page_handler.create_popup("selection", data={ "id": item, "mappings": mappings, "n": len(mappings) }) elif item_info["type"] == "Colorpicker": return self.page_handler.create_popup("colorpicker", data=item_info) elif item_info["type"] == "Setpoint": item_info["state"] = s return self.page_handler.create_popup("setpoint", data=item_info) elif item_info["type"] == "Slider": item_info["state"] = s return self.page_handler.create_popup("slider", data=item_info) elif item_info["type"] == "Chart": ##item_info.update( { "chart_period": request[2] } ) return self.page_handler.create_popup("chart", data=item_info) else: return "none_none" elif action == "popup_chart": data = { "id": item, "periods": [["4 Hours", "4h"], ["Day", "D"], ["3 Days", "3D"], ["Week", "W"], ["2 Weeks", "2W"]] } return self.page_handler.create_popup("chart_period", data) elif action == "chart_data": data = self.get_chart_data(item, request[2].upper()) return data elif action == "icon": icon = self.openhab.get_icon(item) return ["jpg", icon] def get_chart_data(self, item, period): default_period = self.setting_handler.get_setting("chart_period") #print(default_period, period) if default_period == "auto" and period.lower() == "default": if item in self.saved_chart_periods: period = self.saved_chart_periods[item] else: period = "D" elif period.lower() == "default": period = default_period self.saved_chart_periods[item] = period data = self.openhab.get_chart_data(item, period) if data == None: self.logging.warn("No Chart data returned for %s" % item, location=self.name) return "None" d = eval(data["data"]) try: p = int(period[0:len(period) - 1]) e = "s" except: p = 1 e = "" formats = { "H": ["%H:%M", "Hour" + e], "D": ["%a %Hh", "Day" + e], "W": ["%d-%m", "Week" + e], "M": ["%d-%m", "Month" + e] } f = formats[period[-1:]] db = { "name": d["name"], "data": [], "labels": [], "fill": False, "grid": True, "color": "red", "xlabel": str(p) + " " + f[1], "ylabel": "Value", "points": 4 } if data["type"] == "temp": db.update({"ylabel": "Temperature (°C)"}) elif data["type"] == "humi": db.update({"ylabel": "Humidity (%)", "color": "blue"}) elif data["type"] == "pres": db.update({"ylabel": "Pressure (mb)", "color": "green"}) elif data["type"] == "watt": db.update({"ylabel": "Power (W)", "fill": True, "color": "yellow"}) for i in range(len(d["data"])): t = str(d["data"][i]["time"]) t = datetime.datetime.fromtimestamp(float(t[0:-3])).strftime(f[0]) val = "%.4f" % (float(d["data"][i]["state"])) if i == 0 or val != db["data"][-1]: db["data"].append(val) db["labels"].append(t) ##do not show point when there are a lot of datapoints if len(db["data"]) > 25: db["points"] = 0 return json.dumps(db)
class state_handler(Singleton): def __init__(self): try: if self.loadingdone: pass except: self.loadingdone = True self.openhab = pf_openhab() self.name = "state_handler" self.database = main_database() self.setting_handler = setting_handler() self.message_handler = message_handler() self.logging = Logging() settings_c = Settings() self.host = settings_c.get_setting("main", "hostname") self.port = settings_c.get_setting("main", "port") self.http = urllib3.PoolManager() self.timeouts = {} self.update_timeout("screensaver", 60) self.update_timeout("message", -1) self.screentrigger = 0 self.screen_state = True try: self.im_size = settings_c.get_setting("album", "image_size") self.album_url = settings_c.get_setting("album", "random_picture_url") except Exception as e: self.logging.error("Invalid album settings: " + str(e), location=self.name) self.album_url = "none" try: self.album_info_url = settings_c.get_setting("album", "picture_info_url") if self.album_info_url == None: raise Exception("No data") except: self.logging.warn("No album info url", location=self.name) self.album_info_url = "none" def state_request(self, request): action = request[0] if len(request) > 1: item = request[1] ##handle a button press per type of item: #print(item) if action == "photoframe": if item == "frame": ans = self.setting_handler.set_setting("frame", request[2]) if ans != None: return ans[0] return "Setting saved" elif item == "screen": ans = self.setting_handler.set_setting("screen", request[2]) if ans != None: return ans[0] return "Setting saved" elif item == "trigger": self.screentrigger = time.time() self.refresh_screensaver() self.logging.info("Triggered frame on externally", location=self.name) return "Screen triggered" else: return "none_none" elif action == "icon": icon = self.openhab.get_icon(item) return ["jpg", icon] elif action == "picture": try: if item == "new" and self.album_url != "none": response = requests.get(self.album_url) with Image.open(BytesIO(response.content)) as image: imgByteArr = BytesIO() cover = Image.Image.resize(image, [int(self.im_size.split("x")[0]), int(self.im_size.split("x")[1])]) cover.save(imgByteArr, image.format) return ["jpg", imgByteArr.getvalue()] elif item == "info" and self.album_info_url != "none" and self.album_info_url != "": content = self.http.request('GET', self.album_info_url) return content.data.decode("utf-8") elif item == "info": return "no album info" except Exception as e: self.logging.error("Error occured in processing picture for album %s" %e, location=self.name) return "error" def state_check(self, request): page = [] main_page = request[0] subpage = "none" if len(request) > 1: subpage = request[1] ## get used settings setting_album_timeout = self.setting_handler.get_setting("album_timeout") ##not used setting_popup_timeout = self.setting_handler.get_setting("message_timeout") setting_screen_user = self.setting_handler.get_setting("screen") ##screen on or off main_setting_screen_control = self.setting_handler.get_setting("main_screen_control") current_screen_state = self.get_screen_state() screensaver_page = self.get_screensaver_page() desired_screen_state = "off" desired_page = "unchanged" ##reset old screen trigger if self.screentrigger != 0 and time.time() > self.screentrigger + 5*60: self.screentrigger = 0 ##calculate desired screen state (on / off) ##switching is done depending on configuration if main_page in ["main", "settings", "messages"]: if self.check_timeout("screensaver") and setting_screen_user == "off": desired_screen_state = "off" else: desired_screen_state = "on" elif main_page in ["photoframe", "clock", "black"]: desired_screen_state = setting_screen_user ## check desired screen state for messages self.logging.debug("Unread messages: %s" %(str(self.message_handler.check_unread())), location=self.name) self.logging.debug("Popup flag: %s" %(str(self.message_handler.get_popup_flag())), location=self.name) if self.message_handler.check_unread() and not self.message_handler.get_popup_flag(): self.message_handler.set_popup_active(True) self.message_handler.set_popup_flag() self.logging.info("responding new message", location=self.name) desired_screen_state = "on" new_message = True ###turn on screen and make popup elif not self.check_timeout("message"): desired_screen_state = "on" ##keep screen on for message new_message = False else: new_message = False ##calculate desired page (main, black, album or clock) ##switching is done depending on configuration if main_page in ["main", "settings", "messages"]: if self.check_timeout("screensaver") and setting_screen_user == "on" and screensaver_page != "main": desired_page = screensaver_page elif main_page == "photoframe" and screensaver_page != "album": desired_page = screensaver_page elif main_page == "clock" and screensaver_page != "clock": desired_page = screensaver_page elif main_page == "black" and setting_screen_user == "on": desired_page = screensaver_page self.logging.debug("Show new messages: %s" %(str(new_message)), location=self.name) self.logging.debug("Screensaver page: %s" %(screensaver_page), location=self.name) self.logging.debug("Desired page: %s, desired_screen_state: %s" %(desired_page, desired_screen_state), location=self.name) self.logging.debug("Message timeout: %s, Subpage timeout: %s" %(self.check_timeout("message"), self.check_timeout("screensaver_subpage")), location=self.name) ## switch screen off is desired state is off if desired_screen_state == "off" and main_setting_screen_control != "off" and current_screen_state: ##=="on" return self.switch_off_screen(main_setting_screen_control) elif desired_screen_state == "off" and current_screen_state: ##=="on" link = self.get_desired_page_link("clock") return [link] elif self.screentrigger != 0: self.toggle_screen(state = True) self.screentrigger = 0 self.refresh_screensaver() self.logging.info("turn on screen for trigger", location=self.name) return ["close_return_main"] ##actions when we want the screen on elif new_message: if not current_screen_state: self.toggle_screen(state = "on") ##no need for a page change self.update_timeout("message", self.setting_handler.get_setting("message_timeout") + 2) ##in seconds return ["new_message"] elif self.message_handler.check_toast(): ##even if the screen is off self.logging.write("responding new toast message", level=2, location="item_handle") return ["new_toast"] elif desired_screen_state == "on" and desired_page != "unchanged" and self.check_timeout("message"): ##except when there is a message popup self.toggle_screen(state = setting_screen_user) link = self.get_desired_page_link(desired_page) return [link] elif self.check_timeout("screensaver_subpage") and self.check_timeout("message") and main_page not in ["photoframe", "clock"]: ##except when there is a message popup self.delete_timeout("screensaver_subpage") return ["close_return_main"] elif self.check_timeout("screensaver_subpage") and self.check_timeout("message"): self.delete_timeout("screensaver_subpage") ##if for some reason it end here; return ["no_actionHERE"] def switch_off_screen(self, main_setting_screen_control): self.toggle_screen(state = "off") if main_setting_screen_control == "black": link = self.get_desired_page_link("black") return [link] else: link = self.get_desired_page_link("main") return [link] def get_screensaver_page(self): enable_clock = self.setting_handler.get_setting("main_enable_clock") enable_album = self.setting_handler.get_setting("main_enable_album") setting_album_clock = self.setting_handler.get_setting("frame") ##photoframe or clock when screen is on if enable_album == "1" and setting_album_clock == "photoframe": return "album" elif enable_clock == "1" and setting_album_clock == "clock": return "clock" else: return "main" def get_desired_page_link(self, page): if page == "album": self.logging.info("http://"+self.host+":"+self.port+"/page/photoframe", location=self.name) return "http://"+self.host+":"+self.port+"/page/photoframe" elif page == "clock": type_clock = self.setting_handler.get_setting("clock_type") self.logging.info("http://"+self.host+":"+self.port+"/page/clock/"+type_clock, location=self.name) return "http://"+self.host+":"+self.port+"/page/clock/"+type_clock elif page == "main": main_setting_screen_control = self.setting_handler.enable_screen_control self.logging.info("External screen control: %s, no action, stay on main page" %main_setting_screen_control, location=self.name) return "http://"+self.host+":"+self.port+"/page/maindiv/screensaver" elif page == "black": self.logging.write("http://"+self.host+":"+self.port+"/black", level=2) return "http://"+self.host+":"+self.port+"/page/black" def update_timeout(self, name, delta): ##delta in seconds self.timeouts[name] = time.time() + delta def check_timeout(self, name): if name in self.timeouts: self.logging.debug(("Timeout %s: "%name).ljust(30) + str(time.ctime(int(self.timeouts[name]))), location=self.name) if self.timeouts[name] < time.time(): return True else: return False else: return False def delete_timeout(self, name): if name in self.timeouts: del self.timeouts[name] else: self.logging.debug("Timeout %s not deleted, not existing" %name, location=self.name) def refresh_screensaver(self): to = self.setting_handler.get_setting("screen_timeout") if to == "off": to = 24*60*300 self.logging.info("refreshing screensaver", location=self.name) self.update_timeout("screensaver", int(to)*60) self.delete_timeout("screensaver_subpage") def refresh_screensaver_subpage(self): self.refresh_screensaver() self.logging.info("refreshing screensaver for popup", location=self.name) self.update_timeout("screensaver_subpage", 25) def toggle_screen(self, state = True): screen_control = self.setting_handler.get_setting("main_screen_control") switch = False if str(self.screen_state) != str(state): self.logging.info("Switching screen state: %s, %s" %(str(self.screen_state), str(state)), location=self.name) else: self.logging.debug("Switching screen state: %s, %s" %(str(self.screen_state), str(state)), location=self.name) if (state == "off" or state == "0" or state == False) and self.get_screen_state() == True: state = False self.screen_state = False switch = True elif (state == "on" or state == "1" or state == True) and self.get_screen_state() == False: state = True self.screen_state = True switch = True if screen_control == "pi": if not state: self.logging.write("Turn off screen", level=2) cmd = "echo 1 > /sys/class/backlight/rpi_backlight/bl_power" os.system(cmd) else: self.logging.write("Turn on screen", level=2) cmd = "echo 0 > /sys/class/backlight/rpi_backlight/bl_power" os.system(cmd) elif screen_control == "url" and switch: if not state: self.logging.info("Turn off screen via url", location=self.name) url = self.setting_handler.get_setting("screen_control_off_url") else: self.logging.info("Turn on screen via url", location=self.name) url = self.setting_handler.get_setting("screen_control_on_url") self.logging.debug("Screensaver url: %s" %url, location=self.name) self.http.request('GET', url) elif screen_control == "cmd" and switch: if not state: self.logging.info("Turn off screen via cmd", location=self.name) cmd = self.setting_handler.get_setting("screen_control_off_cmd") else: self.logging.info("Turn on screen via cmd", location=self.name) cmd = self.setting_handler.get_setting("screen_control_on_cmd") self.logging.debug("Screensaver cmd: %s" %cmd, location=self.name) os.system(cmd) def get_screen_state(self): return self.screen_state