-
Notifications
You must be signed in to change notification settings - Fork 0
/
tahoma.py
265 lines (227 loc) · 11.4 KB
/
tahoma.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
import requests
import logging
#import exceptions
import urllib.parse
import datetime
#import Domoticz
class Tahoma:
def __init__(self):
self.srvaddr = "tahomalink.com"
self.base_url = f"https://gateway-{pin}.local:{port}/enduser-mobile-web/1/enduserAPI"
self.cookie = None
self.listenerId = None
self.__logged_in = False
self.startup = True
#self.heartbeat = False
self.devices = None
self.filtered_devices = None
self.events = None
self.heartbeat_delay = 1
self.con_delay = 0
self.wait_delay = 30
self.json_data = None
self.refresh = True
self.timeout = 10
self.__expiry_date = datetime.datetime.now()
self.logged_in_expiry_days = 6
self.pin = "2017-8871-5701"
self.port = "8443"
self.token = "62ecd0f3cdda9a49c2c1"
self.headers = {
'Accept': 'application/json',
'Authorization': 'Bearer ' + self.token,
'Content-Type': 'application/json'
}
@property
# def logged_in(self):
# logging.debug("checking logged in status: self.__logged_in = "+str(self.__logged_in)+" and self.__expiry_date >= datetime.datetime.now() = " + str(self.__expiry_date >= datetime.datetime.now()))
# if self.__logged_in and (self.__expiry_date >= datetime.datetime.now()):
# return True
# else:
# return False
# def tahoma_login(self, username, password):
# url = self.base_url + '/enduser-mobile-web/enduserAPI/login'
# headers = { 'Host': self.srvaddr,"Connection": "keep-alive","Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded"}
# data = "userId="+urllib.parse.quote(username)+"&userPassword="+urllib.parse.quote(password)+""
# response = requests.post(url, data=data, headers=headers, timeout=self.timeout)
# Status = response.status_code
# Data = response.json()
# logging.debug("Login respone: status_code: '"+str(Status)+"' reponse body: '"+str(Data)+"'")
# if (Status == 200 and not self.__logged_in):
# self.__logged_in = True
# self.__expiry_date = datetime.datetime.now() + datetime.timedelta(days=self.logged_in_expiry_days)
# logging.info("Tahoma authentication succeeded, login valid until " + self.__expiry_date.strftime("%Y-%m-%d %H:%M:%S"))
# #self.cookie = response.cookies
# self.cookie = response.headers["Set-Cookie"]
# logging.debug("login: cookies: '"+ str(response.cookies)+"', headers: '"+str(response.headers)+"'")
# #self.register_listener()
# elif ((Status == 401) or (Status == 400)):
# strData = Data["error"]
# #logging.error("Tahoma error: must reconnect")
# self.__logged_in = False
# self.cookie = None
# self.listenerId = None
# if ("Too many" in strData):
# logging.error("Too many connections, must wait")
# #self.heartbeat = True
# raise exceptions.LoginFailure("Too many connections, must wait")
# elif ("Bad credentials" in strData):
# logging.error("login failed: Bad credentials, please update credentials and restart plugin")
# #self.heartbeat = False
# raise exceptions.LoginFailure("Bad credentials, please update credentials and restart plugin")
# else:
# logging.error("login failed, unhandled reason: "+strData)
# raise exceptions.LoginFailure("login failed, unhandled reason: "+strData)
# if (not self.__logged_in):
# self.tahoma_login(username, password)
# return
# return self.__logged_in
def tahoma_command(self, json_data):
timeout = 4
logging.debug("start command")
Headers = self.headers
url = self.base_url + '/exec/apply'
logging.debug("onCommand: headers: '"+str(Headers)+"', data '"+str(json_data)+"'")
logging.info("Sending command to tahoma api")
try:
response = requests.post(url, headers=Headers, data=json_data, timeout=timeout)
except requests.exceptions.RequestException as exp:
logging.error("Send command returns RequestException: " + str(exp))
logging.debug("command response: status '" + str(response.status_code) + "' response body: '"+str(response.json())+"'")
if response.status_code != 200:
logging.error("error during command, status: " + str(response.status_code) + ", possible cause:" + str(response.json()))
self.__logged_in = False
return ""
self.executionId = response.json()['execId']
event_list = self.get_events()
return event_list
def register_listener(self):
logging.debug("start register")
Headers = self.headers
url = self.base_url + '/events/register'
response = requests.post(url, headers=Headers, timeout=self.timeout)
logging.debug("register response: status '" + str(response.status_code) + "' response body: '"+str(response.json())+"'")
if response.status_code != 200:
logging.error("error during register, status: " + str(response.status_code))
return
Data = response.json()
if "id" in Data:
strData = Data["id"]
else:
logging.error("Data expected in response but not found")
return
self.listenerId = Data['id']
logging.info("Tahoma listener registred")
self.refresh = False
logging.info("Checking setup status at startup")
#self.get_devices()
def get_devices(self, Devices, firstFree):
logging.debug("start get devices")
Headers = self.headersurl = self.base_url + '/setup/devices'
response = requests.get(url, headers=Headers, timeout=self.timeout)
logging.debug("get device response: url '" + str(response.url) + "' response headers: '"+str(response.headers)+"'")
logging.debug("get device response: status '" + str(response.status_code) + "' response body: '"+str(response.json())+"'")
if response.status_code != 200:
logging.error("get_devices: error during get devices, status: " + str(response.status_code))
return
Data = response.json()
if (not "uiClass" in response.text):
logging.error("get_devices: missing uiClass in response")
logging.debug(str(Data))
return
self.devices = Data
self.filtered_devices = list()
for device in self.devices:
logging.debug("get_devices: Device name: "+device["label"]+" Device class: "+device["uiClass"])
if (((device["uiClass"] == "RollerShutter") or (device["uiClass"] == "ExteriorScreen") or (device["uiClass"] == "Screen") or (device["uiClass"] == "Awning") or (device["uiClass"] == "Pergola") or (device["uiClass"] == "GarageDoor") or (device["uiClass"] == "Window") or (device["uiClass"] == "VenetianBlind") or (device["uiClass"] == "ExteriorVenetianBlind")) and ((device["deviceURL"].startswith("io://")) or (device["deviceURL"].startswith("rts://")))):
self.filtered_devices.append(device)
logging.debug("get_devices: devices found: "+str(len(Devices))+" self.startup: "+str(self.startup))
if (len(Devices) == 0 and self.startup):
count = 1
for device in self.filtered_devices:
logging.info("get_devices: Creating device: "+device["label"])
swtype = None
if (device["deviceURL"].startswith("io://")):
if (device["uiClass"] == "Awning"):
swtype = 13
else:
swtype = 16
elif (device["deviceURL"].startswith("rts://")):
swtype = 6
Domoticz.Device(Name=device["label"], Unit=count, Type=244, Subtype=73, Switchtype=swtype, DeviceID=device["deviceURL"]).Create()
if not (count in Devices):
logging.error("Device creation not allowed, please allow device creation")
Domoticz.Error("Device creation not allowed, please allow device creation")
else:
logging.info("Device created: "+device["label"])
count += 1
if ((len(Devices) < len(self.filtered_devices)) and len(Devices) != 0 and self.startup):
logging.info("New device(s) detected")
found = False
for device in self.filtered_devices:
for dev in Devices:
UnitID = Devices[dev].Unit
if Devices[dev].DeviceID == device["deviceURL"]:
found = True
break
if (not found):
idx = firstFree
swtype = None
logging.debug("get_devices: Must create device: "+device["label"])
if (device["deviceURL"].startswith("io://")):
if (device["uiClass"] == "Awning"):
swtype = 13
else:
swtype = 16
elif (device["deviceURL"].startswith("rts://")):
swtype = 6
Domoticz.Device(Name=device["label"], Unit=idx, Type=244, Subtype=73, Switchtype=swtype, DeviceID=device["deviceURL"]).Create()
if not (idx in Devices):
logging.error("Device creation not allowed, please allow device creation")
Domoticz.Error("Device creation not allowed, please allow device creation")
else:
logging.info("New device created: "+device["label"])
else:
found = False
self.startup = False
self.get_events()
def get_events(self):
logging.debug("start get events")
Headers = self.headers
url = self.base_url +self.listenerId+'/fetch'
for i in range(1,4):
try:
response = requests.post(url, headers=Headers, timeout=self.timeout)
logging.debug("get events response: status '" + str(response.status_code) + "' response body: '"+str(response.json())+"'")
#logging.debug("get events: self.__logged_in = '"+str(self.__logged_in)+"' and self.heartbeat = '"+str(self.heartbeat)+"' and self.startup = '"+str(self.startup))
if response.status_code != 200:
logging.error("error during get events, status: " + str(response.status_code) + ", " + str(response.text))
self.__logged_in = False
return
elif (response.status_code == 200 and self.__logged_in and (not self.startup)):
strData = response.json()
if (not "DeviceStateChangedEvent" in response.text):
logging.debug("get_events: no DeviceStateChangedEvent found in response: " + str(strData))
return
self.events = strData
if (self.events):
filtered_events = list()
for event in self.events:
if (event["name"] == "DeviceStateChangedEvent"):
logging.debug("get_events: add event: URL: '"+event["deviceURL"]+"' num states: '"+str(len(event["deviceStates"]))+"'")
filtered_events.append(event)
return filtered_events
#self.update_devices_status(filtered_events)
# elif (response.status_code == 200 and (not self.heartbeat)):
# return
else:
logging.info("Return status"+str(response.status_code))
except requests.exceptions.RequestException as exp:
logging.error("get_events RequestException: " + str(exp))
time.sleep(i ** 3)
else:
raise exceptions.TooManyRetries
def test_print(self):
Headers = self.headers
url = self.base_url
print(Headers)