python-swidget 1.0.2__tar.gz → 1.2.0__tar.gz
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.
- {python_swidget-1.0.2 → python_swidget-1.2.0}/PKG-INFO +3 -2
- {python_swidget-1.0.2 → python_swidget-1.2.0}/pyproject.toml +3 -2
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/cli.py +5 -5
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/swidgetdevice.py +97 -8
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/swidgetdimmer.py +6 -3
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/websocket.py +47 -5
- {python_swidget-1.0.2 → python_swidget-1.2.0}/README.md +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/__init__.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/discovery.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/exceptions.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/provision.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/py.typed +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/swidgetoutlet.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/swidgetswitch.py +0 -0
- {python_swidget-1.0.2 → python_swidget-1.2.0}/swidget/swidgettimerswitch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-swidget
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Python API for Swidget smart devices
|
|
5
5
|
Home-page: https://github.com/swidget/python-swidget
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -26,7 +26,8 @@ Requires-Dist: sphinx (>=4,<5) ; extra == "docs"
|
|
|
26
26
|
Requires-Dist: sphinx_rtd_theme (>=0,<1) ; extra == "docs"
|
|
27
27
|
Requires-Dist: sphinxcontrib-programoutput (>=0,<1) ; extra == "docs"
|
|
28
28
|
Requires-Dist: ssdp (==1.1.1)
|
|
29
|
-
Requires-Dist: types-requests (==2.31.0.
|
|
29
|
+
Requires-Dist: types-requests (==2.31.0.6)
|
|
30
|
+
Requires-Dist: urllib3 (==1.26.5)
|
|
30
31
|
Project-URL: Repository, https://github.com/swidget/python-swidget
|
|
31
32
|
Description-Content-Type: text/markdown
|
|
32
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-swidget"
|
|
3
|
-
version = "1.0
|
|
3
|
+
version = "1.2.0"
|
|
4
4
|
description = "Python API for Swidget smart devices"
|
|
5
5
|
license = "GPL-3.0-or-later"
|
|
6
6
|
authors = ["Swidget"]
|
|
@@ -23,7 +23,8 @@ asyncclick = ">=8"
|
|
|
23
23
|
pydantic = "^1"
|
|
24
24
|
ssdp = "1.1.1"
|
|
25
25
|
requests = "2.31.0"
|
|
26
|
-
types-requests = "2.31.0.
|
|
26
|
+
types-requests = "2.31.0.6"
|
|
27
|
+
urllib3 = '1.26.5'
|
|
27
28
|
|
|
28
29
|
# required only for docs
|
|
29
30
|
sphinx = { version = "^4", optional = true }
|
|
@@ -116,8 +116,8 @@ def join(ssid, network_password, secret_key, friendly_name):
|
|
|
116
116
|
confirmation = click.prompt(f"Are you connected to a wifi network that stars with the name 'Swidget-' (y/n)")
|
|
117
117
|
if confirmation == "y":
|
|
118
118
|
click.echo(f"Asking the device to connect to network {ssid}..")
|
|
119
|
-
# def provision_wifi(ssid, network_password, token_name, secret_key, friendly_name):
|
|
120
119
|
provision_wifi(friendly_name, ssid, network_password, secret_key)
|
|
120
|
+
click.echo(f"Disconnect from the `swidget` network and connect back your main WiFi network")
|
|
121
121
|
return True
|
|
122
122
|
else:
|
|
123
123
|
click.echo("Not provisioning wifi")
|
|
@@ -164,7 +164,7 @@ async def state(dev: SwidgetDevice):
|
|
|
164
164
|
click.echo(f"\tMAC (rssi): {dev.mac_address} ({dev.rssi})")
|
|
165
165
|
|
|
166
166
|
click.echo(click.style("\n\t== Current State ==", bold=True))
|
|
167
|
-
realtime_values =
|
|
167
|
+
realtime_values = dev.realtime_values
|
|
168
168
|
for info_name, info_data in realtime_values.items():
|
|
169
169
|
if isinstance(info_data, list):
|
|
170
170
|
click.echo(f"\t{info_name}:")
|
|
@@ -263,11 +263,11 @@ async def enable_debug_server(dev: SwidgetDevice):
|
|
|
263
263
|
async def check_for_updates(dev: SwidgetDevice):
|
|
264
264
|
click.echo("Contacting Swidget servers to fetch for updates...")
|
|
265
265
|
available_updates = await dev.check_for_updates()
|
|
266
|
-
if len(available_updates
|
|
266
|
+
if len(available_updates) == 0:
|
|
267
267
|
click.echo("No available updates")
|
|
268
268
|
else:
|
|
269
269
|
click.echo("The following versions are available to update to")
|
|
270
|
-
for version in available_updates
|
|
270
|
+
for version in available_updates:
|
|
271
271
|
click.echo(click.style(f"\t+ {version}", fg="green"))
|
|
272
272
|
|
|
273
273
|
|
|
@@ -278,7 +278,7 @@ async def upgrade(dev: SwidgetDevice, version: str):
|
|
|
278
278
|
if version is None:
|
|
279
279
|
click.echo("Contacting Swidget servers to fetch for latest version")
|
|
280
280
|
available_updates = await dev.check_for_updates()
|
|
281
|
-
if len(available_updates
|
|
281
|
+
if len(available_updates) == 0:
|
|
282
282
|
click.echo("No available updates")
|
|
283
283
|
else:
|
|
284
284
|
version = available_updates[-1]
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import time
|
|
4
|
+
from types import TracebackType
|
|
4
5
|
|
|
5
6
|
from aiohttp import ClientSession, TCPConnector
|
|
6
|
-
import
|
|
7
|
+
from collections.abc import Callable
|
|
7
8
|
from enum import Enum
|
|
8
9
|
from typing import Any, Dict, List
|
|
9
10
|
|
|
@@ -23,6 +24,36 @@ class DeviceType(Enum):
|
|
|
23
24
|
Unknown = -1
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
class InsertType(Enum):
|
|
28
|
+
"""Insert type enum."""
|
|
29
|
+
USB = "USB"
|
|
30
|
+
THM = "TEMP HUMI MOTION"
|
|
31
|
+
TH = "TEMP HUMI"
|
|
32
|
+
AQ = "AIR QUALITY"
|
|
33
|
+
GL = "GUIDE LIGHT"
|
|
34
|
+
PO = "POWER OUT"
|
|
35
|
+
Unknown = -1
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SelfDiagnosticErrorCodes(Enum):
|
|
39
|
+
"""Self-Diagnostic error codes"""
|
|
40
|
+
UNUSED = 0
|
|
41
|
+
AQ = 1
|
|
42
|
+
GUIDELIGHT = 2
|
|
43
|
+
LIGHT_SENSOR = 3
|
|
44
|
+
MOTION = 4
|
|
45
|
+
POWER_OUT = 5
|
|
46
|
+
PRESSURE = 6
|
|
47
|
+
TEMP = 7
|
|
48
|
+
USB = 8
|
|
49
|
+
VIBRATION = 9
|
|
50
|
+
VIDEO = 10
|
|
51
|
+
ADVANCED_GL = 11
|
|
52
|
+
HUMI = 12
|
|
53
|
+
CO2 = 13
|
|
54
|
+
PART_MATTER = 14
|
|
55
|
+
|
|
56
|
+
|
|
26
57
|
class SwidgetDevice:
|
|
27
58
|
def __init__(self, host, token_name, secret_key, use_https=True, use_websockets=True) -> None:
|
|
28
59
|
self.token_name = token_name
|
|
@@ -34,6 +65,7 @@ class SwidgetDevice:
|
|
|
34
65
|
self.device_type = DeviceType.Unknown
|
|
35
66
|
self._friendly_name = "Unknown Swidget Device"
|
|
36
67
|
self.assemblies: Dict[Any, Any] = dict()
|
|
68
|
+
self._subscribers: Callable[[Dict[str, Any]], Any] = list()
|
|
37
69
|
headers = {self.token_name: self.secret_key,
|
|
38
70
|
'Connection': 'keep-alive'}
|
|
39
71
|
connector = TCPConnector(verify_ssl=False, force_close=True)
|
|
@@ -47,6 +79,10 @@ class SwidgetDevice:
|
|
|
47
79
|
callback=self.message_callback,
|
|
48
80
|
session=self._session)
|
|
49
81
|
|
|
82
|
+
@property
|
|
83
|
+
def connected(self) -> bool:
|
|
84
|
+
return self._websocket.connected
|
|
85
|
+
|
|
50
86
|
def get_websocket(self) -> SwidgetWebsocket | None:
|
|
51
87
|
if self.use_websockets:
|
|
52
88
|
return self._websocket
|
|
@@ -77,6 +113,20 @@ class SwidgetDevice:
|
|
|
77
113
|
async def close(self) -> None:
|
|
78
114
|
await self.stop()
|
|
79
115
|
|
|
116
|
+
async def add_event_callback(self, callback: Callable[[Dict, Any], None],) -> bool:
|
|
117
|
+
for c in self._subscribers:
|
|
118
|
+
if c == callback:
|
|
119
|
+
_LOGGER.warn(f"Callback has already been added, not adding the same callback function again")
|
|
120
|
+
return False
|
|
121
|
+
self._subscribers.append(callback)
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
async def remove_event_callback(self, callback: Callable[[Dict, Any], None],) -> bool:
|
|
125
|
+
if callback in self._subscribers:
|
|
126
|
+
self._subscribers.remove(callback)
|
|
127
|
+
return True
|
|
128
|
+
return False
|
|
129
|
+
|
|
80
130
|
async def message_callback(self, message) -> None:
|
|
81
131
|
"""Entrypoint for a websocket callback"""
|
|
82
132
|
_LOGGER.debug("SwidgetDevice.message_callback() called")
|
|
@@ -88,6 +138,12 @@ class SwidgetDevice:
|
|
|
88
138
|
await self.process_state(message)
|
|
89
139
|
else:
|
|
90
140
|
_LOGGER.error(f"Unknown message type from websocket. Type given was: {message["request_id"]}")
|
|
141
|
+
await self.signal_callbacks(message)
|
|
142
|
+
|
|
143
|
+
async def signal_callbacks(self, message):
|
|
144
|
+
_LOGGER.debug("SwidgetDevice.signal_callsbacks() called")
|
|
145
|
+
for callback in self._subscribers:
|
|
146
|
+
await callback(message)
|
|
91
147
|
|
|
92
148
|
async def get_summary(self) -> None:
|
|
93
149
|
"""Get a summary of the device over HTTP"""
|
|
@@ -213,7 +269,7 @@ class SwidgetDevice:
|
|
|
213
269
|
function_value = state[assembly]["components"][component][function]
|
|
214
270
|
self.assemblies[assembly].components[component].functions[function] = function_value # fmt: skip
|
|
215
271
|
|
|
216
|
-
async def ping(self) ->
|
|
272
|
+
async def ping(self) -> bool:
|
|
217
273
|
"""Ping the device to ensure it's devices
|
|
218
274
|
|
|
219
275
|
:raises SwidgetException: Raise the exception if there we are unable to connect to the Swidget device
|
|
@@ -224,9 +280,11 @@ class SwidgetDevice:
|
|
|
224
280
|
url=f"{self.uri_scheme}://{self.ip_address}/ping",
|
|
225
281
|
ssl=False
|
|
226
282
|
) as response:
|
|
227
|
-
|
|
283
|
+
if response.status == 200:
|
|
284
|
+
return True
|
|
285
|
+
return False
|
|
228
286
|
except:
|
|
229
|
-
|
|
287
|
+
return False
|
|
230
288
|
|
|
231
289
|
async def blink(self) -> Any:
|
|
232
290
|
"""Make the device LED blink
|
|
@@ -254,7 +312,9 @@ class SwidgetDevice:
|
|
|
254
312
|
url=f"{self.uri_scheme}://{self.ip_address}/debug?x-secret-key={self.secret_key}",
|
|
255
313
|
ssl=False
|
|
256
314
|
) as response:
|
|
257
|
-
|
|
315
|
+
if response.status == 200:
|
|
316
|
+
return True
|
|
317
|
+
return False
|
|
258
318
|
except:
|
|
259
319
|
raise SwidgetException
|
|
260
320
|
|
|
@@ -284,7 +344,8 @@ class SwidgetDevice:
|
|
|
284
344
|
url=f"{self.uri_scheme}://{self.ip_address}/api/v1/update",
|
|
285
345
|
ssl=False
|
|
286
346
|
) as response:
|
|
287
|
-
|
|
347
|
+
newer_versions = await response.json()
|
|
348
|
+
return sorted(newer_versions['updates'])
|
|
288
349
|
except:
|
|
289
350
|
raise SwidgetException
|
|
290
351
|
|
|
@@ -298,11 +359,14 @@ class SwidgetDevice:
|
|
|
298
359
|
"version": version
|
|
299
360
|
}
|
|
300
361
|
async with self._session.post(
|
|
301
|
-
url=f"{self.uri_scheme}://{self.ip_address}/api/v1/update",
|
|
362
|
+
url=f"{self.uri_scheme}://{self.ip_address}/api/v1/update/version",
|
|
302
363
|
ssl=False,
|
|
303
364
|
data=json.dumps(data)
|
|
304
365
|
) as response:
|
|
305
|
-
|
|
366
|
+
result = await response.status
|
|
367
|
+
if result == 200:
|
|
368
|
+
return True
|
|
369
|
+
return False
|
|
306
370
|
except:
|
|
307
371
|
raise SwidgetException
|
|
308
372
|
|
|
@@ -428,6 +492,7 @@ class SwidgetDevice:
|
|
|
428
492
|
@property # type: ignore
|
|
429
493
|
def is_on(self) -> bool:
|
|
430
494
|
"""Return whether device is on."""
|
|
495
|
+
_LOGGER.debug("SwidgetDevice.is_on called")
|
|
431
496
|
dimmer_state = self.assemblies['host'].components["0"].functions['toggle']["state"]
|
|
432
497
|
if dimmer_state == "on":
|
|
433
498
|
return True
|
|
@@ -436,6 +501,7 @@ class SwidgetDevice:
|
|
|
436
501
|
async def turn_on(self) -> None:
|
|
437
502
|
"""Turn the device on."""
|
|
438
503
|
_LOGGER.debug("SwidgetDevice.turn_on() called")
|
|
504
|
+
self.assemblies['host'].components["0"].functions['toggle']["state"] = "on"
|
|
439
505
|
await self.send_command(
|
|
440
506
|
assembly="host", component="0", function="toggle", command={"state": "on"}
|
|
441
507
|
)
|
|
@@ -443,18 +509,23 @@ class SwidgetDevice:
|
|
|
443
509
|
async def turn_off(self) -> None:
|
|
444
510
|
"""Turn the device off."""
|
|
445
511
|
_LOGGER.debug("SwidgetDevice.turn_off() called")
|
|
512
|
+
self.assemblies['host'].components["0"].functions['toggle']["state"] = "off"
|
|
446
513
|
await self.send_command(
|
|
447
514
|
assembly="host", component="0", function="toggle", command={"state": "off"}
|
|
448
515
|
)
|
|
449
516
|
|
|
450
517
|
async def turn_on_usb_insert(self) -> None:
|
|
451
518
|
"""Turn the USB insert on."""
|
|
519
|
+
_LOGGER.debug("SwidgetDevice.turn_on_usb_insert() called")
|
|
520
|
+
self.assemblies['insert'].components["usb"].functions['toggle']["state"] = "on"
|
|
452
521
|
await self.send_command(
|
|
453
522
|
assembly="insert", component="usb", function="toggle", command={"state": "on"}
|
|
454
523
|
)
|
|
455
524
|
|
|
456
525
|
async def turn_off_usb_insert(self) -> None:
|
|
457
526
|
"""Turn the USB insert off."""
|
|
527
|
+
_LOGGER.debug("SwidgetDevice.turn_off_usb_insert() called")
|
|
528
|
+
self.assemblies['insert'].components["usb"].functions['toggle']["state"] = "off"
|
|
458
529
|
await self.send_command(
|
|
459
530
|
assembly="insert", component="usb", function="toggle", command={"state": "off"}
|
|
460
531
|
)
|
|
@@ -462,11 +533,29 @@ class SwidgetDevice:
|
|
|
462
533
|
@property # type: ignore
|
|
463
534
|
def usb_is_on(self) -> bool:
|
|
464
535
|
"""Return whether USB is on."""
|
|
536
|
+
_LOGGER.debug("SwidgetDevice.usb_is_on called")
|
|
465
537
|
usb_state = self.assemblies['insert'].components["usb"].functions['toggle']["state"]
|
|
466
538
|
if usb_state == "on":
|
|
467
539
|
return True
|
|
468
540
|
return False
|
|
469
541
|
|
|
542
|
+
async def __aenter__(self) -> "SwidgetDevice":
|
|
543
|
+
"""Initialize and connect the Swidget Websocket client."""
|
|
544
|
+
await self.connect()
|
|
545
|
+
return self
|
|
546
|
+
|
|
547
|
+
async def __aexit__(
|
|
548
|
+
self, exc_type: Exception, exc_value: str, traceback: TracebackType
|
|
549
|
+
) -> None:
|
|
550
|
+
"""Disconnect from the websocket."""
|
|
551
|
+
await self.disconnect()
|
|
552
|
+
|
|
553
|
+
def __repr__(self) -> str:
|
|
554
|
+
"""Return the representation."""
|
|
555
|
+
url = self.connection.ws_server_url
|
|
556
|
+
prefix = "" if self.connection.connected else "not "
|
|
557
|
+
return f"{type(self).__name__}(ws_server_url={url!r}, {prefix}connected)"
|
|
558
|
+
|
|
470
559
|
def __repr__(self) -> str:
|
|
471
560
|
if self._last_update == 0:
|
|
472
561
|
return f"<{self.device_type} at {self.ip_address} - update() needed>"
|
|
@@ -13,7 +13,7 @@ class SwidgetDimmer(SwidgetDevice):
|
|
|
13
13
|
|
|
14
14
|
def __init__(self, host, token_name: str, secret_key: str, use_https: bool, use_websockets: bool) -> None:
|
|
15
15
|
super().__init__(host=host, token_name=token_name, secret_key=secret_key, use_https=use_https, use_websockets=use_websockets)
|
|
16
|
-
self._device_type =
|
|
16
|
+
self._device_type = DeviceType.Dimmer
|
|
17
17
|
|
|
18
18
|
@property # type: ignore
|
|
19
19
|
def brightness(self) -> int:
|
|
@@ -21,6 +21,7 @@ class SwidgetDimmer(SwidgetDevice):
|
|
|
21
21
|
|
|
22
22
|
Will return a range between 0 - 100.
|
|
23
23
|
"""
|
|
24
|
+
_LOGGER.debug("SwidgetDimmer.brightness called")
|
|
24
25
|
if not self.is_dimmable:
|
|
25
26
|
raise SwidgetException("Device is not dimmable.")
|
|
26
27
|
try:
|
|
@@ -30,13 +31,14 @@ class SwidgetDimmer(SwidgetDevice):
|
|
|
30
31
|
|
|
31
32
|
async def set_brightness(self, brightness) -> None:
|
|
32
33
|
"""Set the brightness of the device."""
|
|
33
|
-
_LOGGER.debug("SwidgetDimmer.set_brightness() called")
|
|
34
|
+
_LOGGER.debug("SwidgetDimmer.set_brightness() called with brightness: {brightness}")
|
|
35
|
+
self.assemblies['host'].components["0"].functions["level"]["now"] = brightness
|
|
34
36
|
await self.send_command(
|
|
35
37
|
assembly="host", component="0", function="level", command={"now": brightness}
|
|
36
38
|
)
|
|
37
39
|
|
|
38
40
|
async def set_default_brightness(self, brightness) -> None:
|
|
39
|
-
_LOGGER.debug("SwidgetDimmer.set_default_brightness() called")
|
|
41
|
+
_LOGGER.debug("SwidgetDimmer.set_default_brightness() called with brightness: {brightness}")
|
|
40
42
|
await self.send_command(
|
|
41
43
|
assembly="host", component="0", function="level", command={"default": brightness}
|
|
42
44
|
)
|
|
@@ -44,4 +46,5 @@ class SwidgetDimmer(SwidgetDevice):
|
|
|
44
46
|
@property # type: ignore
|
|
45
47
|
def is_dimmable(self) -> bool:
|
|
46
48
|
"""Whether the switch supports brightness changes."""
|
|
49
|
+
_LOGGER.debug("SwidgetDimmer.is_dimmable() called")
|
|
47
50
|
return True
|
|
@@ -3,6 +3,7 @@ import aiohttp
|
|
|
3
3
|
from aiohttp import ClientWebSocketResponse, WSMsgType
|
|
4
4
|
import logging
|
|
5
5
|
import socket
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
_LOGGER = logging.getLogger(__name__)
|
|
8
9
|
|
|
@@ -69,10 +70,14 @@ class SwidgetWebsocket:
|
|
|
69
70
|
_LOGGER.debug("Websocket already connected")
|
|
70
71
|
return
|
|
71
72
|
|
|
73
|
+
if self._client is not None:
|
|
74
|
+
raise ConnectionError("Already connected")
|
|
75
|
+
|
|
72
76
|
if not self.session:
|
|
73
|
-
raise
|
|
77
|
+
raise ConnectionError("No aiohttp session available")
|
|
74
78
|
|
|
75
79
|
try:
|
|
80
|
+
_LOGGER.debug("Trying to connect")
|
|
76
81
|
self._client = await self.session.ws_connect(url=self.uri, headers=self.headers, verify_ssl=self._verify_ssl, heartbeat=30)
|
|
77
82
|
_LOGGER.debug("Websocket now connected")
|
|
78
83
|
except aiohttp.WSServerHandshakeError as handshake_error:
|
|
@@ -91,13 +96,18 @@ class SwidgetWebsocket:
|
|
|
91
96
|
|
|
92
97
|
async def close(self) -> None:
|
|
93
98
|
_LOGGER.debug("websocket.close() called")
|
|
94
|
-
if
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
if self._client is not None and not self._client.closed:
|
|
100
|
+
await self._client.close()
|
|
101
|
+
self._client = None
|
|
102
|
+
|
|
103
|
+
async def disconnect(self) -> None:
|
|
104
|
+
await self.close()
|
|
97
105
|
|
|
98
106
|
async def send_str(self, message):
|
|
99
107
|
"""Send a message through the websocket."""
|
|
100
108
|
_LOGGER.debug("websocket.send_str() called")
|
|
109
|
+
if not self.connected:
|
|
110
|
+
raise ConnectionError
|
|
101
111
|
message = str(message)
|
|
102
112
|
_LOGGER.debug(f"Sending messsage over websocket: {message}")
|
|
103
113
|
await self._client.send_str(f'{message}')
|
|
@@ -115,6 +125,7 @@ class SwidgetWebsocket:
|
|
|
115
125
|
|
|
116
126
|
if message.type == aiohttp.WSMsgType.TEXT:
|
|
117
127
|
message_data = message.json()
|
|
128
|
+
_LOGGER.debug(f"Received from websocket: {message_data}")
|
|
118
129
|
await self.callback(message_data)
|
|
119
130
|
|
|
120
131
|
if message.type in (
|
|
@@ -122,4 +133,35 @@ class SwidgetWebsocket:
|
|
|
122
133
|
aiohttp.WSMsgType.CLOSED,
|
|
123
134
|
aiohttp.WSMsgType.CLOSING,
|
|
124
135
|
):
|
|
125
|
-
_LOGGER.
|
|
136
|
+
_LOGGER.error("Connection to the Swidget WebSocket on has been closed")
|
|
137
|
+
|
|
138
|
+
async def receive_message_or_raise(self) -> Any:
|
|
139
|
+
"""Receive ONE (raw) message or raise."""
|
|
140
|
+
assert self._ws_client
|
|
141
|
+
ws_msg = await self._ws_client.receive()
|
|
142
|
+
|
|
143
|
+
if ws_msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING):
|
|
144
|
+
raise ConnectionError("Connection was closed.")
|
|
145
|
+
|
|
146
|
+
if ws_msg.type == WSMsgType.ERROR:
|
|
147
|
+
raise ConnectionError
|
|
148
|
+
|
|
149
|
+
if ws_msg.type != WSMsgType.TEXT:
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"Received non-Text message: {ws_msg.type}: {ws_msg.data}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
msg = ws_msg.json()
|
|
156
|
+
except TypeError as err:
|
|
157
|
+
raise TypeError(f"Received unsupported JSON: {err}") from err
|
|
158
|
+
except ValueError as err:
|
|
159
|
+
raise ValueError("Received invalid JSON.") from err
|
|
160
|
+
|
|
161
|
+
_LOGGER.debug(f"Received message:\n{msg}\n")
|
|
162
|
+
return msg
|
|
163
|
+
|
|
164
|
+
def __repr__(self) -> str:
|
|
165
|
+
"""Return the representation."""
|
|
166
|
+
prefix = "" if self.connected else "not "
|
|
167
|
+
return f"{type(self).__name__}(ws_server_url={self.host}, {prefix}connected)"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|