1 #!/usr/local/bin/python
16 APP_ID = "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i"
17 HOST_URI = "myqexternal.myqdevice.com"
18 LOGIN_ENDPOINT = "api/v4/User/Validate"
19 DEVICE_LIST_ENDPOINT = "api/v4/UserDeviceDetails/Get"
20 DEVICE_SET_ENDPOINT = "api/v4/DeviceAttribute/PutDeviceAttribute"
24 myq_lamp_device_id = None
25 myq_device_descr = None
26 myq_device_update_ts = None
27 myq_device_state = None
28 myq_security_token = None
30 def __init__(self, device_id, lamp_id, descr, update_ts, state, token):
31 self.myq_device_id = device_id
32 self.myq_lamp_device_id = lamp_id
33 self.myq_device_descr = descr
34 self.myq_device_update_ts = update_ts
35 self.myq_device_state = state
36 self.myq_security_token = token
38 def update(self, update_ts, state):
39 self.myq_device_update_ts = update_ts
40 self.myq_device_state = state
43 return self.myq_device_descr
45 def get_update_ts(self):
46 return self.myq_device_update_ts
49 self.change_door_state("open")
52 self.change_door_state("close")
55 self.change_lamp_state("on")
58 self.change_lamp_state("off")
61 state = self.myq_device_state
77 return str(state) + ", an unknown state for the door."
79 def get_state_icon(self):
80 state = self.myq_device_state
81 if (state == "1" or state == "9"):
82 return "/icons/garage_open.png"
84 return "/icons/garage_closed.png"
86 return "/icons/garage_opening.png"
87 elif (state == "5" or state == "8"):
88 return "/icons/garage_closing.png"
90 return str(state) + ", an unknown state for the door."
92 def get_lamp_status(self):
93 state = self.check_lamp_state()
101 def change_device_state(self, payload):
102 device_action = requests.put(
103 'https://{host_uri}/{device_set_endpoint}'.format(
105 device_set_endpoint=DEVICE_SET_ENDPOINT),
108 'MyQApplicationId': APP_ID,
109 'SecurityToken': self.myq_security_token
112 return device_action.status_code == 200
114 def change_lamp_state(self, command):
115 newstate = 1 if command.lower() == "on" else 0
117 "attributeName": "desiredlightstate",
118 "myQDeviceId": self.myq_lamp_device_id,
119 "AttributeValue": newstate
121 return self.change_device_state(payload)
123 def change_door_state(self, command):
124 open_close_state = 1 if command.lower() == "open" else 0
126 'attributeName': 'desireddoorstate',
127 'myQDeviceId': self.myq_device_id,
128 'AttributeValue': open_close_state,
130 return self.change_device_state(payload)
132 def check_door_state(self):
133 return self.myq_device_state
135 # def check_lamp_state(self):
136 # return self.check_device_state(self.myq_lamp_device_id, "lightstate")
139 return "MyQ device(%s/%s), last update %s, current state %s" % (
140 self.myq_device_descr,
142 self.myq_device_update_ts,
146 myq_security_token = ""
149 def __init__(self, username, password):
150 self.username = username
151 self.password = password
155 'username': self.username,
156 'password': self.password
158 login = requests.post(
159 'https://{host_uri}/{login_endpoint}'.format(
161 login_endpoint=LOGIN_ENDPOINT),
164 'MyQApplicationId': APP_ID
168 self.myq_security_token = auth.get('SecurityToken')
171 def get_raw_device_list(self):
172 devices = requests.get(
173 'https://{host_uri}/{device_list_endpoint}'.format(
175 device_list_endpoint=DEVICE_LIST_ENDPOINT),
177 'MyQApplicationId': APP_ID,
178 'SecurityToken': self.myq_security_token
180 return devices.json().get('Devices')
182 def get_devices(self):
183 return self.myq_device_list
185 def update_devices(self):
186 devices = self.get_raw_device_list()
191 if dev["MyQDeviceTypeId"] != 7: continue
192 identifier = str(dev["MyQDeviceId"])
196 for attr in dev["Attributes"]:
197 key = attr["AttributeDisplayName"]
198 value = attr["Value"]
199 if (key == "doorstate"):
201 ts = int(attr["UpdatedTime"]) / 1000.0
202 update_ts = datetime.datetime.fromtimestamp(ts)
203 elif (key == "desc"):
205 if (identifier in self.myq_device_list):
206 self.myq_device_list[identifier].update(
209 device = MyQDoor(identifier,
214 self.myq_security_token)
215 self.myq_device_list[identifier] = device
218 class garage_door_renderer(renderer.debuggable_abstaining_renderer):
219 def __init__(self, name_to_timeout_dict):
220 super(garage_door_renderer, self).__init__(name_to_timeout_dict, False)
221 self.myq_service = MyQService(secrets.myq_username,
222 secrets.myq_password)
223 self.myq_service.login()
224 self.myq_service.update_devices()
226 def debug_prefix(self):
229 def periodic_render(self, key):
230 self.debug_print("*** Executing action %s ***" % key)
231 if key == "Poll MyQ":
232 return self.myq_service.update_devices()
233 elif key == "Update Page":
234 return self.update_page()
236 raise error("Unknown operaiton")
238 def do_door(self, name):
239 doors = self.myq_service.get_devices()
240 now = datetime.datetime.now()
241 is_night = now.hour <= 7 or now.hour >= 21
244 if door.get_name() == name:
245 ts = door.get_update_ts()
247 d = int(delta.total_seconds())
248 days = divmod(d, constants.seconds_per_day)
249 hours = divmod(days[1], constants.seconds_per_hour)
250 minutes = divmod(hours[1], constants.seconds_per_minute)
252 if is_night and door.get_status() == "open":
253 color = "border-color: #ff0000;"
261 <FONT STYLE="font-size:26pt">%s<BR>
264 STYLE="border-style: solid; border-width: %dpx; %s">
267 for %d day(s), %02d:%02d.
270 door.get_state_icon(),
274 days[0], hours[0], minutes[0])
277 def update_page(self):
278 f = file_writer.file_writer(constants.myq_pagename)
279 now = datetime.datetime.now()
281 <H1>Garage Door Status</H1>
282 <!-- Last updated at %s -->
284 <TABLE BORDER=0 WIDTH=99%%>
287 html = self.do_door("Near House")
292 html = self.do_door("Middle Door")