aioairzone-cloud 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ """Airzone Cloud API library."""
@@ -0,0 +1,372 @@
1
+ """Airzone Cloud API."""
2
+ from __future__ import annotations
3
+
4
+ import logging
5
+ import urllib.parse
6
+ from typing import Any, cast
7
+
8
+ from aiohttp import ClientConnectorError, ClientSession
9
+ from aiohttp.client_reqrep import ClientResponse
10
+
11
+ from .common import ConnectionOptions
12
+ from .const import (
13
+ API_AUTH_LOGIN,
14
+ API_AUTH_REFRESH_TOKEN,
15
+ API_AZ_SYSTEM,
16
+ API_AZ_ZONE,
17
+ API_CONFIG,
18
+ API_DEVICE_ID,
19
+ API_DEVICE_TYPE,
20
+ API_DEVICES,
21
+ API_EMAIL,
22
+ API_INSTALLATION_ID,
23
+ API_INSTALLATIONS,
24
+ API_PASSWORD,
25
+ API_REFRESH_TOKEN,
26
+ API_STATUS,
27
+ API_TOKEN,
28
+ API_URL,
29
+ API_USER,
30
+ API_USER_LOGOUT,
31
+ API_V1,
32
+ API_WS,
33
+ AZD_INSTALLATIONS,
34
+ AZD_SYSTEMS,
35
+ AZD_WEBSERVERS,
36
+ AZD_ZONES,
37
+ HEADER_AUTHORIZATION,
38
+ HEADER_BEARER,
39
+ HTTP_CALL_TIMEOUT,
40
+ )
41
+ from .device import Device
42
+ from .exceptions import LoginError, TokenRefreshError
43
+ from .installation import Installation
44
+ from .system import System
45
+ from .webserver import WebServer
46
+ from .zone import Zone
47
+
48
+ _LOGGER = logging.getLogger(__name__)
49
+
50
+
51
+ class AirzoneCloudApi:
52
+ """Airzone Cloud API."""
53
+
54
+ def __init__(
55
+ self,
56
+ aiohttp_session: ClientSession,
57
+ options: ConnectionOptions,
58
+ ):
59
+ """Airzone Cloud API init."""
60
+ self.aiohttp_session = aiohttp_session
61
+ self.installations: list[Installation] = []
62
+ self.options = options
63
+ self.refresh_token: str | None = None
64
+ self.systems: list[System] = []
65
+ self.token: str | None = None
66
+ self.webservers: list[WebServer] = []
67
+ self.zones: list[Zone] = []
68
+
69
+ async def api_request(
70
+ self, method: str, path: str, json: Any | None = None
71
+ ) -> dict[str, Any]:
72
+ """Airzone Cloud API request."""
73
+ _LOGGER.debug("aiohttp request: /%s (params=%s)", path, json)
74
+ headers: dict[str, str] = {}
75
+ if self.token:
76
+ headers[HEADER_AUTHORIZATION] = f"{HEADER_BEARER} {self.token}"
77
+ resp: ClientResponse = await self.aiohttp_session.request(
78
+ method,
79
+ f"{API_URL}/{path}",
80
+ headers=headers,
81
+ json=json,
82
+ raise_for_status=True,
83
+ timeout=HTTP_CALL_TIMEOUT,
84
+ )
85
+ resp_json = await resp.json(content_type=None)
86
+ _LOGGER.debug("aiohttp response: %s", resp_json)
87
+ return cast(dict, resp_json)
88
+
89
+ async def api_get_device_config(self, device: Device) -> dict[str, Any]:
90
+ """Request API device config data."""
91
+ dev_id = urllib.parse.quote(device.get_id())
92
+
93
+ params = {
94
+ API_INSTALLATION_ID: device.get_installation(),
95
+ }
96
+ dev_params = urllib.parse.urlencode(params)
97
+
98
+ return await self.api_request(
99
+ "GET",
100
+ f"{API_V1}/{API_DEVICES}/{dev_id}/{API_CONFIG}?{dev_params}",
101
+ )
102
+
103
+ async def api_get_device_status(self, device: Device) -> dict[str, Any]:
104
+ """Request API device status data."""
105
+ dev_id = urllib.parse.quote(device.get_id())
106
+
107
+ params = {
108
+ API_INSTALLATION_ID: device.get_installation(),
109
+ }
110
+ dev_params = urllib.parse.urlencode(params)
111
+
112
+ return await self.api_request(
113
+ "GET",
114
+ f"{API_V1}/{API_DEVICES}/{dev_id}/{API_STATUS}?{dev_params}",
115
+ )
116
+
117
+ async def api_get_installation(self, installation: Installation) -> dict[str, Any]:
118
+ """Request API installation data."""
119
+ inst_id = urllib.parse.quote(installation.get_id())
120
+ return await self.api_request(
121
+ "GET",
122
+ f"{API_V1}/{API_INSTALLATIONS}/{inst_id}",
123
+ )
124
+
125
+ async def api_get_installations(self) -> dict[str, Any]:
126
+ """Request API installations data."""
127
+ return await self.api_request(
128
+ "GET",
129
+ f"{API_V1}/{API_INSTALLATIONS}",
130
+ )
131
+
132
+ async def api_get_user(self) -> dict[str, Any]:
133
+ """Request API user data."""
134
+ return await self.api_request(
135
+ "GET",
136
+ f"{API_V1}/{API_USER}",
137
+ )
138
+
139
+ async def api_get_webserver(
140
+ self, webserver: WebServer, devices: bool
141
+ ) -> dict[str, Any]:
142
+ """Request API webserver data."""
143
+ ws_id = urllib.parse.quote(webserver.get_id())
144
+
145
+ params: dict[str, Any] = {
146
+ API_INSTALLATION_ID: webserver.get_installation(),
147
+ }
148
+ if devices:
149
+ params[API_DEVICES] = 1
150
+ ws_params = urllib.parse.urlencode(params)
151
+
152
+ return await self.api_request(
153
+ "GET",
154
+ f"{API_V1}/{API_DEVICES}/{API_WS}/{ws_id}/{API_STATUS}?{ws_params}",
155
+ )
156
+
157
+ async def login(self) -> None:
158
+ """Perform Airzone Cloud API login."""
159
+ if self.token:
160
+ await self.logout()
161
+ resp = await self.api_request(
162
+ "POST",
163
+ f"{API_V1}/{API_AUTH_LOGIN}",
164
+ {
165
+ API_EMAIL: self.options.username,
166
+ API_PASSWORD: self.options.password,
167
+ },
168
+ )
169
+ _LOGGER.debug("login resp: %s", resp)
170
+ if resp.keys() < {API_TOKEN, API_REFRESH_TOKEN}:
171
+ raise LoginError
172
+ self.token = resp[API_TOKEN]
173
+ self.refresh_token = resp[API_REFRESH_TOKEN]
174
+
175
+ async def logout(self) -> None:
176
+ """Perform Airzone Cloud API logout."""
177
+ try:
178
+ if self.token:
179
+ await self.api_request(
180
+ "GET",
181
+ f"{API_V1}/{API_USER_LOGOUT}",
182
+ )
183
+ except ClientConnectorError:
184
+ pass
185
+ finally:
186
+ self.refresh_token = None
187
+ self.token = None
188
+
189
+ async def token_refresh(self) -> None:
190
+ """Perform Airzone Cloud API token refresh."""
191
+ if self.token and self.refresh_token:
192
+ resp = await self.api_request(
193
+ "POST",
194
+ f"{API_V1}/{API_AUTH_REFRESH_TOKEN}",
195
+ {
196
+ API_REFRESH_TOKEN: self.refresh_token,
197
+ },
198
+ )
199
+ _LOGGER.debug("refresh resp: %s", resp)
200
+ if resp.keys() < {API_TOKEN, API_REFRESH_TOKEN}:
201
+ raise TokenRefreshError
202
+ self.token = resp[API_TOKEN]
203
+ self.refresh_token = resp[API_REFRESH_TOKEN]
204
+
205
+ def data(self) -> dict[str, Any]:
206
+ """Return Airzone Cloud data."""
207
+ data: dict[str, Any] = {}
208
+
209
+ if self.installations:
210
+ installations: dict[str, Any] = {}
211
+ for installation in self.installations:
212
+ installations[installation.get_id()] = installation.data()
213
+ data[AZD_INSTALLATIONS] = installations
214
+
215
+ if self.systems:
216
+ systems: dict[str, Any] = {}
217
+ for system in self.systems:
218
+ systems[system.get_id()] = system.data()
219
+ data[AZD_SYSTEMS] = systems
220
+
221
+ if self.webservers:
222
+ webservers: dict[str, Any] = {}
223
+ for webserver in self.webservers:
224
+ webservers[webserver.get_id()] = webserver.data()
225
+ data[AZD_WEBSERVERS] = webservers
226
+
227
+ if self.zones:
228
+ zones: dict[str, Any] = {}
229
+ for zone in self.zones:
230
+ zones[zone.get_id()] = zone.data()
231
+ data[AZD_ZONES] = zones
232
+
233
+ return data
234
+
235
+ def get_installation_id(self, inst_id: str) -> Installation | None:
236
+ """Return Airzone Cloud Installation by ID."""
237
+ for inst in self.installations:
238
+ if inst_id == inst.get_id():
239
+ return inst
240
+ return None
241
+
242
+ def get_system_id(self, sys_id: str) -> System | None:
243
+ """Return Airzone Cloud System by ID."""
244
+ for system in self.systems:
245
+ if sys_id == system.get_id():
246
+ return system
247
+ return None
248
+
249
+ def get_webserver_id(self, ws_id: str) -> WebServer | None:
250
+ """Return Airzone Cloud WebServer by ID."""
251
+ for ws in self.webservers:
252
+ if ws_id == ws.get_id():
253
+ return ws
254
+ return None
255
+
256
+ def get_zone_id(self, zone_id: str) -> Zone | None:
257
+ """Return Airzone Cloud Zone by ID."""
258
+ for zone in self.zones:
259
+ if zone_id == zone.get_id():
260
+ return zone
261
+ return None
262
+
263
+ async def list_installations(self) -> list[Installation]:
264
+ """Return Airzone Cloud installations list."""
265
+ inst_list: list[Installation] = []
266
+
267
+ inst_data = await self.api_get_installations()
268
+ for inst in inst_data[API_INSTALLATIONS]:
269
+ inst_list.append(Installation(inst))
270
+
271
+ return inst_list
272
+
273
+ def select_installation(self, inst: Installation) -> None:
274
+ """Select single Airzone Cloud installation."""
275
+ self.installations = [inst]
276
+ for ws_id in inst.get_webservers():
277
+ if not self.get_webserver_id(ws_id):
278
+ ws = WebServer(inst.get_id(), ws_id)
279
+ self.webservers.append(ws)
280
+
281
+ def set_system_zones_data(self, system: System):
282
+ """Set slave zones modes from master zone."""
283
+ modes = system.get_modes()
284
+ installation_id = system.get_installation()
285
+ system_id = system.get_id()
286
+ system_num = system.get_system()
287
+ for zone in self.zones:
288
+ zone.set_system_id(system_id)
289
+ is_slave = zone.get_master() is False
290
+ if (
291
+ is_slave
292
+ and modes
293
+ and zone.get_installation() == installation_id
294
+ and zone.get_system() == system_num
295
+ ):
296
+ zone.set_modes(modes)
297
+
298
+ async def update_installations(self) -> None:
299
+ """Update Airzone Cloud installations from API."""
300
+ installations_data = await self.api_get_installations()
301
+ for installation_data in installations_data[API_INSTALLATIONS]:
302
+ if not self.get_installation_id(installation_data[API_INSTALLATION_ID]):
303
+ installation = Installation(installation_data)
304
+ if installation:
305
+ self.installations.append(installation)
306
+ for ws_id in installation.get_webservers():
307
+ if not self.get_webserver_id(ws_id):
308
+ ws = WebServer(installation.get_id(), ws_id)
309
+ self.webservers.append(ws)
310
+
311
+ async def update_system(self, system: System) -> None:
312
+ """Update Airzone Cloud System from API."""
313
+ device_data = await self.api_get_device_status(system)
314
+ system.update(device_data)
315
+
316
+ async def update_system_id(self, sys_id: str) -> None:
317
+ """Update Airzone Cloud System by ID."""
318
+ system = self.get_system_id(sys_id)
319
+ if system:
320
+ await self.update_system(system)
321
+
322
+ async def update_systems(self) -> None:
323
+ """Update all Airzone Cloud Systems."""
324
+ for system in self.systems:
325
+ await self.update_system(system)
326
+
327
+ async def update_webserver(self, ws: WebServer, devices: bool) -> None:
328
+ """Update Airzone Cloud WebServer from API."""
329
+ ws_data = await self.api_get_webserver(ws, devices)
330
+ ws.update(ws_data)
331
+ if devices:
332
+ for device_data in ws_data[API_DEVICES]:
333
+ if API_AZ_ZONE == device_data[API_DEVICE_TYPE]:
334
+ if not self.get_zone_id(device_data[API_DEVICE_ID]):
335
+ zone = Zone(ws.get_installation(), ws.get_id(), device_data)
336
+ if zone:
337
+ self.zones.append(zone)
338
+ elif API_AZ_SYSTEM == device_data[API_DEVICE_TYPE]:
339
+ if not self.get_zone_id(device_data[API_DEVICE_ID]):
340
+ system = System(ws.get_installation(), ws.get_id(), device_data)
341
+ if system:
342
+ self.systems.append(system)
343
+
344
+ async def update_webserver_id(self, ws_id: str, devices: bool = False) -> None:
345
+ """Update Airzone Cloud WebServer by ID."""
346
+ ws = self.get_webserver_id(ws_id)
347
+ if ws:
348
+ await self.update_webserver(ws, devices)
349
+
350
+ async def update_webservers(self, devices: bool = True) -> None:
351
+ """Update all Airzone Cloud WebServers."""
352
+ for ws in self.webservers:
353
+ await self.update_webserver(ws, devices)
354
+
355
+ async def update_zone(self, zone: Zone) -> None:
356
+ """Update Airzone Cloud Zone from API."""
357
+ device_data = await self.api_get_device_status(zone)
358
+ zone.update(device_data)
359
+
360
+ async def update_zone_id(self, zone_id: str) -> None:
361
+ """Update Airzone Cloud Zone by ID."""
362
+ zone = self.get_zone_id(zone_id)
363
+ if zone:
364
+ await self.update_zone(zone)
365
+
366
+ async def update_zones(self) -> None:
367
+ """Update all Airzone Cloud Zones."""
368
+ for zone in self.zones:
369
+ await self.update_zone(zone)
370
+
371
+ for system in self.systems:
372
+ self.set_system_zones_data(system)
@@ -0,0 +1,69 @@
1
+ """Airzone Cloud API common code."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from enum import Enum
6
+
7
+
8
+ @dataclass
9
+ class ConnectionOptions:
10
+ """Airzone Cloud options for connection."""
11
+
12
+ username: str
13
+ password: str
14
+
15
+
16
+ class OperationMode(int, Enum):
17
+ """Airzone Cloud operation modes."""
18
+
19
+ STOP = 0
20
+ AUTO = 1
21
+ COOLING = 2
22
+ HEATING = 3
23
+ VENTILATION = 4
24
+ DRY = 5
25
+ EMERGENCY_HEAT = 6
26
+ HEAT_AIR = 7
27
+ HEAT_RADIANT = 8
28
+ HEAT_COMBINED = 9
29
+ COOLING_AIR = 10
30
+ COOLING_RADIANT = 11
31
+ COOLING_COMBINED = 12
32
+
33
+ def is_cool(self) -> bool:
34
+ """Return if mode is Cool."""
35
+ return self.value in [
36
+ self.COOLING,
37
+ self.COOLING_AIR,
38
+ self.COOLING_COMBINED,
39
+ self.COOLING_RADIANT,
40
+ ]
41
+
42
+ def is_dry(self) -> bool:
43
+ """Return if mode is Dry."""
44
+ return self.value in [self.DRY]
45
+
46
+ def is_heat(self) -> bool:
47
+ """Return if mode is Heat."""
48
+ return self.value in [
49
+ self.EMERGENCY_HEAT,
50
+ self.HEATING,
51
+ self.HEAT_AIR,
52
+ self.HEAT_COMBINED,
53
+ self.HEAT_RADIANT,
54
+ ]
55
+
56
+ def is_stop(self) -> bool:
57
+ """Return if mode is Stop."""
58
+ return self.value in [self.STOP]
59
+
60
+ def is_vent(self) -> bool:
61
+ """Return if mode is Ventilation."""
62
+ return self.value in [self.VENTILATION]
63
+
64
+
65
+ class TemperatureUnit(int, Enum):
66
+ """Airzone Cloud temperature units."""
67
+
68
+ CELSIUS = 0
69
+ FAHRENHEIT = 1
@@ -0,0 +1,125 @@
1
+ """Airzone Cloud API constants."""
2
+
3
+ API_AUTH_LOGIN = "auth/login"
4
+ API_AUTH_REFRESH_TOKEN = "auth/refreshToken"
5
+ API_CELSIUS = "celsius"
6
+ API_CONFIG = "config"
7
+ API_CONNECTION_DATE = "connection_date"
8
+ API_DEVICE_ID = "device_id"
9
+ API_DEVICE_TYPE = "device_type"
10
+ API_DEVICES = "devices"
11
+ API_DISCONNECTION_DATE = "disconnection_date"
12
+ API_ECO_CONF = "eco_conf"
13
+ API_EMAIL = "email"
14
+ API_FAH = "fah"
15
+ API_HUMIDITY = "humidity"
16
+ API_INSTALLATION_ID = "installation_id"
17
+ API_INSTALLATIONS = "installations"
18
+ API_IS_CONNECTED = "isConnected"
19
+ API_LOCAL_TEMP = "local_temp"
20
+ API_MODE = "mode"
21
+ API_MODE_AVAIL = "mode_available"
22
+ API_NAME = "name"
23
+ API_OPTS = "opts"
24
+ API_PARAMS = "params"
25
+ API_PASSWORD = "password"
26
+ API_POWER = "power"
27
+ API_RANGE_SP_MAX_COOL_AIR = "range_sp_cool_air_max"
28
+ API_RANGE_SP_MAX_DRY_AIR = "range_sp_dry_air_max"
29
+ API_RANGE_SP_MAX_EMERHEAT_AIR = "range_sp_emerheat_air_max"
30
+ API_RANGE_SP_MAX_HOT_AIR = "range_sp_hot_air_max"
31
+ API_RANGE_SP_MAX_STOP_AIR = "range_sp_stop_air_max"
32
+ API_RANGE_SP_MAX_VENT_AIR = "range_sp_vent_air_max"
33
+ API_RANGE_SP_MIN_COOL_AIR = "range_sp_cool_air_min"
34
+ API_RANGE_SP_MIN_DRY_AIR = "range_sp_dry_air_min"
35
+ API_RANGE_SP_MIN_EMERHEAT_AIR = "range_sp_emerheat_air_min"
36
+ API_RANGE_SP_MIN_HOT_AIR = "range_sp_hot_air_min"
37
+ API_RANGE_SP_MIN_STOP_AIR = "range_sp_stop_air_min"
38
+ API_RANGE_SP_MIN_VENT_AIR = "range_sp_vent_air_min"
39
+ API_REFRESH_TOKEN = "refreshToken"
40
+ API_SETPOINT = "setpoint"
41
+ API_SLEEP = "sleep"
42
+ API_SP_AIR_COOL = "setpoint_air_cool"
43
+ API_SP_AIR_DRY = "setpoint_air_dry"
44
+ API_SP_AIR_HEAT = "setpoint_air_heat"
45
+ API_SP_AIR_STOP = "setpoint_air_stop"
46
+ API_SP_AIR_VENT = "setpoint_air_vent"
47
+ API_SPEED = "speed"
48
+ API_STAT_AP_MAC = "stat_ap_mac"
49
+ API_STAT_CHANNEL = "stat_channel"
50
+ API_STAT_QUALITY = "stat_quality"
51
+ API_STAT_SSID = "stat_ssid"
52
+ API_STATUS = "status"
53
+ API_STEP = "step"
54
+ API_SYSTEM_NUMBER = "system_number"
55
+ API_TIMER = "timer"
56
+ API_TOKEN = "token"
57
+ API_UNITS = "units"
58
+ API_URL = "https://m.airzonecloud.com"
59
+ API_USER = "user"
60
+ API_USER_LOGOUT = "user/logout"
61
+ API_USER_MODE_CONF = "usermode_conf"
62
+ API_V1 = "api/v1"
63
+ API_WS = "ws"
64
+ API_WS_FW = "ws_fw"
65
+ API_WS_IDS = "ws_ids"
66
+ API_WS_TYPE = "ws_type"
67
+ API_ZONE_NUMBER = "zone_number"
68
+
69
+ API_AZ_SYSTEM = "az_system"
70
+ API_AZ_ZONE = "az_zone"
71
+
72
+ API_DEFAULT_TEMP_STEP = 0.5
73
+
74
+ AZD_CONNECTED = "connected"
75
+ AZD_CONNECTION_DATE = "connection-date"
76
+ AZD_DISCONNECTION_DATE = "disconnection-date"
77
+ AZD_FIRMWARE = "firmware"
78
+ AZD_HUMIDITY = "humidity"
79
+ AZD_ID = "id"
80
+ AZD_INSTALLATION = "installation"
81
+ AZD_INSTALLATIONS = "installations"
82
+ AZD_MASTER = "master"
83
+ AZD_MODE = "mode"
84
+ AZD_MODES = "modes"
85
+ AZD_NAME = "name"
86
+ AZD_POWER = "power"
87
+ AZD_SYSTEM = "system"
88
+ AZD_SYSTEM_ID = "system-id"
89
+ AZD_SYSTEMS = "systems"
90
+ AZD_TEMP = "temperature"
91
+ AZD_TEMP_STEP = "temperature-step"
92
+ AZD_TEMP_SET = "temperature-setpoint"
93
+ AZD_TEMP_SET_COOL_AIR = "temperature-setpoint-cool-air"
94
+ AZD_TEMP_SET_DRY_AIR = "temperature-setpoint-dry-air"
95
+ AZD_TEMP_SET_HOT_AIR = "temperature-setpoint-hot-air"
96
+ AZD_TEMP_SET_STOP_AIR = "temperature-setpoint-stop-air"
97
+ AZD_TEMP_SET_VENT_AIR = "temperature-setpoint-vent-air"
98
+ AZD_TEMP_SET_MAX = "temperature-setpoint-max"
99
+ AZD_TEMP_SET_MAX_COOL_AIR = "temperature-setpoint-max-cool-air"
100
+ AZD_TEMP_SET_MAX_DRY_AIR = "temperature-setpoint-max-dry-air"
101
+ AZD_TEMP_SET_MAX_EMERHEAT_AIR = "temperature-setpoint-max-emerheat-air"
102
+ AZD_TEMP_SET_MAX_HOT_AIR = "temperature-setpoint-max-hot-air"
103
+ AZD_TEMP_SET_MAX_STOP_AIR = "temperature-setpoint-max-stop-air"
104
+ AZD_TEMP_SET_MAX_VENT_AIR = "temperature-setpoint-max-vent-air"
105
+ AZD_TEMP_SET_MIN_COOL_AIR = "temperature-setpoint-min-cool-air"
106
+ AZD_TEMP_SET_MIN_DRY_AIR = "temperature-setpoint-min-dry-air"
107
+ AZD_TEMP_SET_MIN_EMERHEAT_AIR = "temperature-setpoint-min-emerheat-air"
108
+ AZD_TEMP_SET_MIN_HOT_AIR = "temperature-setpoint-min-hot-air"
109
+ AZD_TEMP_SET_MIN_STOP_AIR = "temperature-setpoint-min-stop-air"
110
+ AZD_TEMP_SET_MIN_VENT_AIR = "temperature-setpoint-min-vent-air"
111
+ AZD_TEMP_SET_MIN = "temperature-setpoint-min"
112
+ AZD_TYPE = "type"
113
+ AZD_WEBSERVER = "web-server"
114
+ AZD_WEBSERVERS = "web-servers"
115
+ AZD_WIFI_CHANNEL = "wifi-channel"
116
+ AZD_WIFI_MAC = "wifi-mac"
117
+ AZD_WIFI_QUALITY = "wifi-quality"
118
+ AZD_WIFI_SSID = "wifi-ssid"
119
+ AZD_ZONE = "zone"
120
+ AZD_ZONES = "zones"
121
+
122
+ HEADER_AUTHORIZATION = "Authorization"
123
+ HEADER_BEARER = "Bearer"
124
+
125
+ HTTP_CALL_TIMEOUT = 10
@@ -0,0 +1,106 @@
1
+ """Airzone Cloud API Device."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from .common import OperationMode
7
+ from .const import (
8
+ API_CONFIG,
9
+ API_DEVICE_ID,
10
+ API_IS_CONNECTED,
11
+ API_MODE,
12
+ API_MODE_AVAIL,
13
+ API_SYSTEM_NUMBER,
14
+ AZD_CONNECTED,
15
+ AZD_ID,
16
+ AZD_INSTALLATION,
17
+ AZD_MODE,
18
+ AZD_MODES,
19
+ AZD_NAME,
20
+ AZD_SYSTEM,
21
+ AZD_WEBSERVER,
22
+ )
23
+
24
+
25
+ class Device:
26
+ """Airzone Cloud Device."""
27
+
28
+ connected: bool
29
+ name: str
30
+
31
+ def __init__(self, inst_id: str, ws_id: str, device_data: dict[str, Any]):
32
+ """Airzone Cloud Device init."""
33
+ self.id = str(device_data[API_DEVICE_ID])
34
+ self.installation_id = inst_id
35
+ self.mode: OperationMode | None = None
36
+ self.modes: list[OperationMode] = []
37
+ self.system_number = int(device_data[API_CONFIG][API_SYSTEM_NUMBER])
38
+ self.webserver_id = ws_id
39
+
40
+ if API_IS_CONNECTED in device_data:
41
+ self.connected = bool(device_data[API_IS_CONNECTED])
42
+
43
+ def data(self) -> dict[str, Any]:
44
+ """Return Device data."""
45
+ data = {
46
+ AZD_CONNECTED: self.get_connected(),
47
+ AZD_ID: self.get_id(),
48
+ AZD_INSTALLATION: self.get_installation(),
49
+ AZD_MODE: self.get_mode(),
50
+ AZD_NAME: self.get_name(),
51
+ AZD_SYSTEM: self.get_system(),
52
+ AZD_WEBSERVER: self.get_webserver(),
53
+ }
54
+
55
+ modes = self.get_modes()
56
+ if modes:
57
+ data[AZD_MODES] = modes
58
+
59
+ return data
60
+
61
+ def get_connected(self) -> bool:
62
+ """Return connected status."""
63
+ return self.connected
64
+
65
+ def get_id(self) -> str:
66
+ """Return Device ID."""
67
+ return self.id
68
+
69
+ def get_installation(self) -> str:
70
+ """Return Installation ID."""
71
+ return self.installation_id
72
+
73
+ def get_mode(self) -> OperationMode | None:
74
+ """Return Device mode."""
75
+ return self.mode
76
+
77
+ def get_modes(self) -> list[OperationMode] | None:
78
+ """Return Device modes."""
79
+ if len(self.modes) > 0:
80
+ return self.modes
81
+ return None
82
+
83
+ def get_name(self) -> str:
84
+ """Return Device name."""
85
+ return self.name
86
+
87
+ def get_system(self) -> int:
88
+ """Return System number."""
89
+ return self.system_number
90
+
91
+ def get_webserver(self) -> str:
92
+ """Return WebServer ID."""
93
+ return self.webserver_id
94
+
95
+ def update(self, data: dict[str, Any]) -> None:
96
+ """Update Device data."""
97
+ if API_IS_CONNECTED in data:
98
+ self.connected = bool(data[API_IS_CONNECTED])
99
+
100
+ if API_MODE in data:
101
+ self.mode = OperationMode(data[API_MODE])
102
+ if API_MODE_AVAIL in data and len(data[API_MODE_AVAIL]) > 0:
103
+ modes = []
104
+ for mode in data[API_MODE_AVAIL]:
105
+ modes.append(OperationMode(mode))
106
+ self.modes = modes
@@ -0,0 +1,26 @@
1
+ """Airzone Cloud API exceptions."""
2
+ from __future__ import annotations
3
+
4
+
5
+ class AirzoneCloudError(Exception):
6
+ """Base class for Airzone Cloud errors."""
7
+
8
+
9
+ class APIError(AirzoneCloudError):
10
+ """Exception raised when API fails."""
11
+
12
+
13
+ class LoginError(AirzoneCloudError):
14
+ """Exception raised when login fails."""
15
+
16
+
17
+ class TokenRefreshError(AirzoneCloudError):
18
+ """Exception raised when token refresh fails."""
19
+
20
+
21
+ class InvalidParam(AirzoneCloudError):
22
+ """Exception raised when invalid param is requested."""
23
+
24
+
25
+ class ParamUpdateFailure(AirzoneCloudError):
26
+ """Exception raised when parameter isn't updated."""