Merge branch 'master' of ssh://git.house:/usr/local/git/base/kiosk
[kiosk.git] / myq_renderer.py
index 1e666489e66cf0366532e3658a6f9a6bc2763a01..ebfac233927a8038cda3daca83a2fe23fb984d78 100644 (file)
@@ -1,86 +1,93 @@
-import pymyq
+#!/usr/bin/env python3
+
 from aiohttp import ClientSession
 import asyncio
-import constants
 import datetime
 from dateutil.parser import parse
+import pymyq  # type: ignore
+from typing import Dict, Optional
+
+from pyutils.datetimes import datetime_utils
+
+import kiosk_constants
 import file_writer
 import renderer
-import secrets
+import kiosk_secrets as secrets
 
 
-class garage_door_renderer(renderer.debuggable_abstaining_renderer):
-    def __init__(self, name_to_timeout_dict):
-        super(garage_door_renderer, self).__init__(name_to_timeout_dict, False)
-        self.doors = None
-        self.last_update = None
+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.doors: Optional[Dict] = None
+        self.last_update: Optional[datetime.datetime] = None
 
-    def debug_prefix(self):
+    def debug_prefix(self) -> str:
         return "myq"
 
-    def periodic_render(self, key):
+    def periodic_render(self, key: str) -> bool:
         if key == "Poll MyQ":
             self.last_update = datetime.datetime.now()
             return asyncio.run(self.poll_myq())
         elif key == "Update Page":
             return self.update_page()
         else:
-            raise error("Unknown operaiton")
+            raise Exception("Unknown operaiton")
 
-    async def poll_myq(self):
+    async def poll_myq(self) -> bool:
         async with ClientSession() as websession:
             myq = await pymyq.login(
                 secrets.myq_username, secrets.myq_password, websession
             )
             self.doors = myq.devices
+            assert(self.doors is not None)
             return len(self.doors) > 0
 
-    def update_page(self):
-        f = file_writer.file_writer(constants.myq_pagename)
-        f.write(
-            """
+    def update_page(self) -> bool:
+        with file_writer.file_writer(kiosk_constants.myq_pagename) as f:
+            f.write(
+                f"""
 <H1>Garage Door Status</H1>
-<!-- Last updated at %s -->
+<!-- Last updated at {self.last_update} -->
 <HR>
-<TABLE BORDER=0 WIDTH=99%%>
-  <TR>
+<TABLE BORDER=0 WIDTH=99%>
+    <TR>
 """
-            % self.last_update
-        )
-        html = self.do_door("Near House")
-        if html == None:
-            return False
-        f.write(html)
+            )
+            html = self.do_door("Near House")
+            if html is None:
+                return False
+            f.write(html)
 
-        html = self.do_door("Middle Door")
-        if html == None:
-            return False
-        f.write(html)
-        f.write(
-            """
-  </TR>
+            html = self.do_door("Middle Door")
+            if html is None:
+                return False
+            f.write(html)
+            f.write(
+                """
+    </TR>
 </TABLE>"""
-        )
-        f.close()
+            )
         return True
 
-    def get_state_icon(self, state):
+    def get_state_icon(self, state: str) -> str:
         if state == "open":
-            return "/icons/garage_open.png"
+            return "/kiosk/images/garage_open.png"
         elif state == "closed":
-            return "/icons/garage_closed.png"
+            return "/kiosk/images/garage_closed.png"
         elif state == "opening":
-            return "/icons/garage_opening.png"
+            return "/kiosk/images/garage_opening.png"
         elif state == "closing":
-            return "/icons/garage_closing.png"
+            return "/kiosk/images/garage_closing.png"
         else:
             return str(state) + ", an unknown state for the door."
 
-    def do_door(self, name):
+    def do_door(self, name: str) -> Optional[str]:
+        if self.doors is None:
+            return None
         for key in self.doors:
             door = self.doors[key]
             if door.name == name:
-                j = self.doors[key].json
+                j = self.doors[key].device_json
                 state = j["state"]["door_state"]
 
                 # "last_update": "2020-07-04T18:11:34.2981419Z"
@@ -91,9 +98,7 @@ class garage_door_renderer(renderer.debuggable_abstaining_renderer):
                 delta = (now - ts).total_seconds()
                 now = datetime.datetime.now()
                 is_night = now.hour <= 7 or now.hour >= 21
-                days = divmod(delta, constants.seconds_per_day)
-                hours = divmod(days[1], constants.seconds_per_hour)
-                minutes = divmod(hours[1], constants.seconds_per_minute)
+                duration = datetime_utils.describe_duration_briefly(int(delta))
                 width = 0
                 if is_night and door.state == "open":
                     color = "border-color: #ff0000;"
@@ -101,31 +106,22 @@ class garage_door_renderer(renderer.debuggable_abstaining_renderer):
                 else:
                     color = ""
                     width = 0
-                return """
-<TD WIDTH=49%%>
+                return f"""
+<TD WIDTH=49%>
   <CENTER>
-  <FONT STYLE="font-size:26pt">%s<BR>
-  <IMG SRC="%s"
+  <FONT STYLE="font-size:26pt">{name}<BR>
+  <IMG SRC="{self.get_state_icon(state)}"
        HEIGHT=250
-       STYLE="border-style: solid; border-width: %dpx; %s">
+       STYLE="border-style: solid; border-width: {width}px; {color}">
   <BR>
-  <B>%s</B></FONT><BR>
-  for %d day(s), %02d:%02d.
+  <B>{state}</B></FONT><BR>
+  for {duration}
   </CENTER>
-</TD>""" % (
-                    name,
-                    self.get_state_icon(state),
-                    width,
-                    color,
-                    state,
-                    days[0],
-                    hours[0],
-                    minutes[0],
-                )
+</TD>"""
         return None
 
 
 # Test
-x = garage_door_renderer({"Test": 1})
-x.periodic_render("Poll MyQ")
-x.periodic_render("Update Page")
+#x = garage_door_renderer({"Test": 1})
+#x.periodic_render("Poll MyQ")
+#x.periodic_render("Update Page")