Remove myq
[kiosk.git] / ratago_renderer.py
diff --git a/ratago_renderer.py b/ratago_renderer.py
new file mode 100644 (file)
index 0000000..4e33ed6
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+
+import datetime
+import logging
+import json
+from dateutil.parser import parse
+from typing import Dict, Optional
+
+import requests
+from pyutils.datetimes import datetime_utils
+
+import file_writer
+import globals
+import kiosk_constants
+import kiosk_secrets as secrets
+import renderer
+
+
+logger = logging.getLogger(__name__)
+
+
+class garage_door_renderer(renderer.abstaining_renderer):
+    def __init__(self, name_to_timeout_dict: Dict[str, int]) -> None:
+        super().__init__(name_to_timeout_dict)
+        self.last_update: Optional[datetime.datetime] = None
+        self.doors = {
+            "cover.ratgdo_middle_door_door": {"state": "unknown"},
+            "cover.ratgdo_near_house_door": {"state": "unknown"},
+            "cover.ratgdo_shop_door": {"state": "unknown"},
+        }
+
+    def debug_prefix(self) -> str:
+        return "ratago"
+
+    def periodic_render(self, key: str) -> bool:
+        if key == "Poll Home Assistant":
+            return self.poll_home_assistant()
+        elif key == "Update Page":
+            return self.update_page()
+        else:
+            raise Exception("Unknown operaiton")
+
+    def poll_home_assistant(self) -> bool:
+        key = secrets.HOMEASSISTANT_API_KEY
+        headers = {
+            "Authorization": f"Bearer {key}",
+            "Content-Type": "application/json",
+        }
+        for door in self.doors.keys():
+            try:
+                r = requests.get(
+                    f"https://home.acknak.org/api/states/{door}",
+                    headers=headers,
+                    timeout=3.0,
+                )
+                if r.ok:
+                    j = json.loads(r.content.decode())
+                    logger.debug(j)
+                    self.doors[door] = j
+                else:
+                    logger.warning("Unable to get state of garage door {door}, using 'unknown'")
+            except Exception:
+                logger.exception("Unable to get state of garage door {door}, using 'unknown'")
+        self.last_update = datetime_utils.now_pacific()
+        return True
+
+    def update_page(self) -> bool:
+        with file_writer.file_writer(kiosk_constants.ratago_pagename) as f:
+            f.write(
+                f"""
+<H1>Garage Door Status</H1>
+<!-- Last updated at {self.last_update} -->
+<HR>
+<TABLE BORDER=0 WIDTH=99%>
+    <TR>
+"""
+            )
+
+            html = self.do_door("cover.ratago_near_house_door")
+            if html is None:
+                return False
+            f.write(html)
+
+            html = self.do_door("cover.ratago_middle_door_door")
+            if html is None:
+                return False
+            f.write(html)
+
+            html = self.do_door("cover.ratago_shop_door")
+            if html is None:
+                return False
+            f.write(html)
+            f.write(
+                """
+    </TR>
+</TABLE>"""
+            )
+        return True
+
+    def get_state_icon(self, state: str) -> str:
+        if state == "open":
+            return "/kiosk/images/garage_open.png"
+        elif state == "closed":
+            return "/kiosk/images/garage_closed.png"
+        elif state == "opening":
+            return "/kiosk/images/garage_opening.png"
+        elif state == "closing":
+            return "/kiosk/images/garage_closing.png"
+        else:
+            return str(state) + ", an unknown state for the door."
+
+    def do_door(self, name: str) -> Optional[str]:
+        friendly_door_names = {
+            "cover.ratgdo_middle_door_door": "Middle Door",
+            "cover.ratgdo_near_house_door": "Near House Door",
+            "cover.ratgdo_shop_door": "Workshop Door",
+        }
+        if self.doors is None:
+            return None
+
+        friendly_name = friendly_door_names.get(name, "unknown")
+        attributes = self.doors.get(name, {"state": "unknown"})
+        state = attributes.get("state", "unknown").lower()
+        since = attributes.get("last_changed", "unknown").lower()
+
+        # "last_update": "2020-07-04T18:11:34.2981419Z"
+        ts = parse(since)
+        tz_info = ts.tzinfo
+        now = datetime.datetime.now(tz_info)
+        delta = (now - ts).total_seconds()
+        duration = datetime_utils.describe_duration_briefly(int(delta))
+
+        now = datetime.datetime.now()
+        is_night = now.hour <= 7 or now.hour >= 21
+        width = 0
+        if is_night and state == "open":
+            color = "border-color: #ff0000;"
+            width = 15
+            globals.put("ratago_triggered", True)
+        else:
+            color = ""
+            width = 0
+            globals.put("ratago_triggered", False)
+        return f"""
+<TD WIDTH=32%>
+  <CENTER>
+  <FONT STYLE="font-size:26pt">{friendly_name}<BR>
+  <IMG SRC="{self.get_state_icon(state)}"
+       HEIGHT=250
+       STYLE="border-style: solid; border-width: {width}px; {color}">
+  <BR>
+  <B>{state}</B></FONT><BR>
+  for {duration}
+  </CENTER>
+</TD>"""
+
+
+# Test
+#x = garage_door_renderer({"Test": 1})
+#x.periodic_render("Poll MyQ")
+#x.periodic_render("Update Page")