333c356a6e96891a26ddf8c36f743636c785b155
[kiosk.git] / myq_renderer.py
1 #!/usr/local/bin/python3.7
2
3 import pymyq
4 from aiohttp import ClientSession
5 import asyncio
6 import constants
7 import datetime
8 from dateutil.parser import parse
9 import file_writer
10 import renderer
11 import secrets
12
13 class garage_door_renderer(renderer.debuggable_abstaining_renderer):
14     def __init__(self, name_to_timeout_dict):
15         super(garage_door_renderer, self).__init__(name_to_timeout_dict, False)
16         self.doors = None
17
18     def debug_prefix(self):
19         return "myq"
20
21     def periodic_render(self, key):
22         if key == "Poll MyQ":
23             asyncio.get_event_loop().run_until_complete(self.poll_myq())
24         elif key == "Update Page":
25             return self.update_page()
26         else:
27             raise error("Unknown operaiton")
28
29     async def poll_myq(self):
30         async with ClientSession() as websession:
31             myq = await pymyq.login(secrets.myq_username,
32                                     secrets.myq_password,
33                                     websession)
34             self.doors = myq.devices
35
36     def update_page(self):
37         f = file_writer.file_writer(constants.myq_pagename)
38         now = datetime.datetime.now()
39         f.write("""
40 <H1>Garage Door Status</H1>
41 <!-- Last updated at %s -->
42 <HR>
43 <TABLE BORDER=0 WIDTH=99%%>
44   <TR>
45 """ % now)
46         html = self.do_door("Near House")
47         if html == None:
48             return False
49         f.write(html)
50
51         html = self.do_door("Middle Door")
52         if html == None:
53             return False
54         f.write(html)
55         f.write("""
56   </TR>
57 </TABLE>""")
58         f.close()
59         return True
60
61     def get_state_icon(self, state):
62         if state == "open":
63             return "/icons/garage_open.png"
64         elif state == "closed":
65             return "/icons/garage_closed.png"
66         elif state == "opening":
67             return "/icons/garage_opening.png"
68         elif state == "closing":
69             return "/icons/garage_closing.png"
70         else:
71             return str(state) + ", an unknown state for the door."
72
73     def do_door(self, name):
74         for key in self.doors:
75             door = self.doors[key]
76             if door.name == name:
77                 j = self.doors[key].json
78                 state = j["state"]["door_state"]
79
80                 # "last_update": "2020-07-04T18:11:34.2981419Z"
81                 raw = j["state"]["last_update"]
82                 ts = parse(raw)
83                 tz_info = ts.tzinfo
84                 now = datetime.datetime.now(tz_info)
85                 delta = (now - ts).total_seconds()
86                 now = datetime.datetime.now()
87                 is_night = now.hour <= 7 or now.hour >= 21
88                 days = divmod(delta, constants.seconds_per_day)
89                 hours = divmod(days[1], constants.seconds_per_hour)
90                 minutes = divmod(hours[1], constants.seconds_per_minute)
91                 width = 0
92                 if is_night and door.get_status() == "open":
93                     color = "border-color: #ff0000;"
94                     width = 15
95                 else:
96                     color = ""
97                     width = 0
98                 return """
99 <TD WIDTH=49%%>
100   <CENTER>
101   <FONT STYLE="font-size:26pt">%s<BR>
102   <IMG SRC="%s"
103        HEIGHT=250
104        STYLE="border-style: solid; border-width: %dpx; %s">
105   <BR>
106   <B>%s</B></FONT><BR>
107   for %d day(s), %02d:%02d.
108   </CENTER>
109 </TD>""" % (name,
110             self.get_state_icon(state),
111             width,
112             color,
113             state,
114             days[0], hours[0], minutes[0])
115         return None
116
117 # Test
118 #x = garage_door_renderer({"Test" : 1})
119 #x.periodic_render("Poll MyQ")
120 #x.periodic_render("Update Page")