Example #1
0
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
Example #2
0
class setting_handler(Singleton):
    def __init__(self):
        try:
            if self.loadingdone:
                pass
        except:
            self.loadingdone = True
            self.name = "setting_handler"
            self.database = main_database()
            self.logging = Logging()
            self.http = urllib3.PoolManager()
            self.settings = {}
            #self.settings["main_page"] = ["Front page", ["OpenHAB", "Weather"]]
            self.settings["screen_timeout"] = [
                "Screen timeout (min)", [1, 3, 5, 10, 15, 30, "off"]
            ]
            self.settings["album_timeout"] = [
                "Album timeout (hr)", [1, 3, 5, 10, 15, 30]
            ]
            self.settings["message_timeout"] = [
                "Message timeout (s)", [10, 30, 60, 120, 300]
            ]
            self.settings["toast_timeout"] = [
                "Info timeout (s)", [7, 10, 15, 20, 30]
            ]
            self.settings["mouse"] = ["Mouse button", ["on", "off"]]
            self.settings["items_per_page"] = [
                "Number of items per page", [6, 8, 9, 12]
            ]
            self.settings["sensors_per_page"] = [
                "Number of sensor items per page", [6, 8, 9, 12]
            ]
            self.settings["screen"] = ["Screen", ["on", "off"]]
            self.settings["frame"] = ["Photo / Clock", ["photoframe", "clock"]]
            self.settings["frame_info"] = [
                "Frame Info", ["none", "load", "album", "both"]
            ]
            self.settings["frame_td"] = [
                "Frame Time/Date", ["none", "clock", "date", "both"]
            ]
            self.settings["frame_display_time"] = [
                "Photo display time",
                ["short", "medium", "long", "extra long"]
            ]
            self.settings["clock_type"] = ["Clock type", ["digital", "analog"]]
            self.settings["chart_period"] = [
                "Default chart period",
                ["auto", "4 hours", "12 hours", "1 day", "3 days", "1 week"]
            ]

            for key, item in self.settings.items():
                value = self.database.data["settings"][key]
                self.settings[key].append(int(value))

            settings_c = Settings()
            self.enable_screen_control = settings_c.get_setting(
                "main", "enable_screen_control")

            try:
                topics = settings_c.get_setting(
                    "main", "mqtt_control_topic").split(",")
                self.mqtt = mqtt()
                for topic in topics:
                    self.mqtt.add_listener(topic, self,
                                           "received_mqtt_message")
            except:
                self.logging.warn("Mqtt not configured for handling settings",
                                  location="settings_handler")

            if self.enable_screen_control in ["pi", "black"]:
                pass
            elif self.enable_screen_control == "url":
                try:
                    self.screen_control_on_url = settings_c.get_setting(
                        "main", "screen_on_url")
                    self.screen_control_off_url = settings_c.get_setting(
                        "main", "screen_off_url")
                    self.settings["screen_control_on_url"] = [
                        0, 0, self.screen_control_on_url
                    ]
                    self.settings["screen_control_off_url"] = [
                        0, 0, self.screen_control_off_url
                    ]
                except:
                    self.logging.error(
                        "Add settings 'screen_on_url' and 'screen_off_url' for external url screen control",
                        location="settings_handler")
                    self.enable_screen_control = "black"
            elif self.enable_screen_control == "cmd":
                try:
                    self.screen_control_on_cmd = settings_c.get_setting(
                        "main", "screen_on_cmd")
                    self.screen_control_off_cmd = settings_c.get_setting(
                        "main", "screen_off_cmd")
                    self.settings["screen_control_on_cmd"] = [
                        0, 0, self.screen_control_on_cmd
                    ]
                    self.settings["screen_control_off_cmd"] = [
                        0, 0, self.screen_control_off_cmd
                    ]
                except:
                    self.logging.error(
                        "Add settings 'screen_on_cmd' and 'screen_off_cmd' for external command screen control",
                        location="settings_handler")
                    self.enable_screen_control = "black"
            elif self.enable_screen_control != "off":
                self.logging.error(
                    "Incorrect screen control enable settings, screen control is off",
                    location="settings_handler")
                self.enable_screen_control = "off"

            self.settings["main_enable_clock"] = [
                0, 0, settings_c.get_setting("main", "enable_clock")
            ]
            self.settings["main_enable_album"] = [
                0, 0, settings_c.get_setting("main", "enable_album")
            ]
            if settings_c.get_setting("main", "enable_album") == "0":
                self.logging.warn("Album not enabled, setting frame to clock",
                                  location="settings_handler")
                self.__set_setting("frame", "clock")
            elif settings_c.get_setting("main", "enable_clock") == "0":
                self.logging.warn(
                    "clock not enabled, setting frame to photoframe",
                    location="settings_handler")
                self.__set_setting("frame", "photoframe")
            if settings_c.get_setting(
                    "main", "enable_clock") == "0" and settings_c.get_setting(
                        "main", "enable_album") == "0":
                self.logging.warn(
                    "Album and clock not enabled, turning off screen setting",
                    location="settings_handler")
                self.__set_setting(
                    "screen", "off"
                )  ##in this case only the screensaver determines if the screen is turned on or off
            self.settings["main_screen_control"] = [
                0, 0, self.enable_screen_control
            ]

    def get_name(self):
        return self.name

    def setting_request(self, request):
        if request[0] == "setsetting":
            setting = request[1]
            if setting == "screen" and self.get_setting(
                    "main_enable_album") == "0" and self.get_setting(
                        "main_enable_clock") == "0":
                return [
                    "Enable album or clock to be able to control this setting"
                ]
            if setting == "frame" and (
                    self.get_setting("main_enable_album") == "0"
                    or self.get_setting("main_enable_clock") == "0"):
                return [
                    "Enable album and clock to be able to control this setting"
                ]
            cur_value = self.settings[setting][2]
            if cur_value + 1 < len(self.settings[setting][1]):
                self.settings[setting][2] = cur_value + 1
            else:
                self.settings[setting][2] = 0
            self.save_settings()
            self.logging.write(
                self.settings[setting][0] + ": " +
                str(self.settings[setting][1][self.settings[setting][2]]),
                level=2)
            return [
                self.settings[setting][0] + ": " +
                str(self.settings[setting][1][self.settings[setting][2]])
            ]
        elif request[0] == "getsetting":
            return [str(self.get_setting(request[1]))]

    def set_setting(self, setting, value):
        if setting == "screen" and self.get_setting(
                "main_enable_album") == "0" and self.get_setting(
                    "main_enable_clock") == "0":
            return ["Enable album or clock to be able to control this setting"]
        if setting == "frame" and (self.get_setting("main_enable_album") == "0"
                                   or self.get_setting("main_enable_clock")
                                   == "0"):
            return [
                "Enable album and clock to be able to control this setting"
            ]
        self.__set_setting(setting, value)

    def __set_setting(self, setting, value):
        values = self.settings[setting][1]
        self.screen_timeout_start = time.time()
        for i in range(len(values)):
            if values[i] == value:
                self.settings[setting][2] = i
                self.save_settings()

    def get_settings(self):
        settings = []
        for key, item in self.settings.items():
            if (key == "clock_type"
                ) and self.get_setting("main_enable_clock") == "0":
                pass
            elif (key == "album_timeout" or key == "frame_info"
                  or key == "frame_td" or key == "frame_display_time"
                  ) and self.get_setting("main_enable_album") == "0":
                pass
            elif key == "frame" and (
                    self.get_setting("main_enable_album") == "0"
                    or self.get_setting("main_enable_clock") == "0"):
                pass
            elif key == "screen" and self.get_setting(
                    "main_enable_album") == "0" and self.get_setting(
                        "main_enable_clock") == "0":
                pass
            elif key == "screen" and self.enable_screen_control == "off":
                pass
            elif item[0] != 0:
                settings.append([key, item[0], item[1][item[2]]])
        return settings

    def save_settings(self):
        for key, item in self.settings.items():
            self.database.data["settings"][key] = item[2]
        self.database.save_datafile()

    def get_setting(self, setting):
        value = self.settings[setting][2]
        if self.settings[setting][0] != 0:
            return self.translate_setting(setting,
                                          self.settings[setting][1][value])
        else:
            return value

    def translate_setting(self, setting, value):
        if setting == "frame_display_time":
            timing = {
                "short": 5000,
                "medium": 13000,
                "long": 20000,
                "extra long": 60000
            }
            if value == 0:
                return "short"
            return timing[value]
        elif setting == "chart_period":
            period = {
                "auto": "auto",
                "4 hours": "4H",
                "12 hours": "12H",
                "1 day": "1D",
                "3 days": "3D",
                "1 week": "1W"
            }
            if value == 0:
                return "auto"
            return period[value]
        return value

    def received_mqtt_message(self, topic, payload):
        try:
            payload_setting = payload['setting']
            for setting in self.settings:
                if setting == payload_setting:
                    if "cmd" in topic.lower():
                        self.set_setting(setting, payload[setting])
                        self.logging.info(
                            "Set setting via mqtt message: %s, %s" %
                            (setting, payload[setting]),
                            location="settings_handler")
                    elif "state" in topic.lower():
                        val = self.get_setting(setting)
                        topic = topic[0:topic.rfind("/") + 1] + "status"
                        self.mqtt.publish(
                            topic, str({
                                'setting': setting,
                                'value': val
                            }))
            if payload_setting == "all":
                topic = topic[0:topic.rfind("/") + 1] + "status"
                self.mqtt.publish(topic, str(list(self.settings.keys())))
        except Exception as e:
            raise Exception(e)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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