python-swidget 1.3.2__tar.gz → 1.3.3__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.3.2 → python_swidget-1.3.3}/PKG-INFO +4 -4
- {python_swidget-1.3.2 → python_swidget-1.3.3}/pyproject.toml +4 -4
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/discovery.py +2 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/swidgetdevice.py +7 -1
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/websocket.py +16 -13
- {python_swidget-1.3.2 → python_swidget-1.3.3}/README.md +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/__init__.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/cli.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/exceptions.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/provision.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/py.typed +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/swidgetdimmer.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/swidgetoutlet.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/swidgetswitch.py +0 -0
- {python_swidget-1.3.2 → python_swidget-1.3.3}/swidget/swidgettimerswitch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: python-swidget
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.3
|
|
4
4
|
Summary: Python API for Swidget smart devices
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
6
|
Author: Swidget
|
|
@@ -21,13 +21,13 @@ Requires-Dist: importlib-metadata
|
|
|
21
21
|
Requires-Dist: m2r (>=0,<1) ; extra == "docs"
|
|
22
22
|
Requires-Dist: mistune (<2.0.0) ; extra == "docs"
|
|
23
23
|
Requires-Dist: pydantic (>=2,<3)
|
|
24
|
-
Requires-Dist: requests (==2.32.
|
|
24
|
+
Requires-Dist: requests (==2.32.5)
|
|
25
25
|
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.
|
|
30
|
-
Requires-Dist: urllib3 (==
|
|
29
|
+
Requires-Dist: types-requests (>=2.32.0,<3.0.0)
|
|
30
|
+
Requires-Dist: urllib3 (==2.5.0)
|
|
31
31
|
Project-URL: Repository, https://github.com/swidget/python-swidget
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-swidget"
|
|
3
|
-
version = "1.3.
|
|
3
|
+
version = "1.3.3"
|
|
4
4
|
description = "Python API for Swidget smart devices"
|
|
5
5
|
license = "GPL-3.0-or-later"
|
|
6
6
|
authors = ["Swidget"]
|
|
@@ -22,9 +22,9 @@ importlib-metadata = "*"
|
|
|
22
22
|
asyncclick = ">=8"
|
|
23
23
|
pydantic = "^2"
|
|
24
24
|
ssdp = "1.1.1"
|
|
25
|
-
requests = "2.32.
|
|
26
|
-
types-requests = "^2.
|
|
27
|
-
urllib3 = '
|
|
25
|
+
requests = "2.32.5"
|
|
26
|
+
types-requests = "^2.32.0"
|
|
27
|
+
urllib3 = '2.5.0'
|
|
28
28
|
|
|
29
29
|
# required only for docs
|
|
30
30
|
sphinx = { version = "^4", optional = true }
|
|
@@ -31,12 +31,14 @@ class SwidgetDiscoveredDevice:
|
|
|
31
31
|
host_type: str,
|
|
32
32
|
insert_type: str,
|
|
33
33
|
friendly_name: str = "Swidget Discovered Device",
|
|
34
|
+
host_id: str = "",
|
|
34
35
|
):
|
|
35
36
|
self.mac = mac
|
|
36
37
|
self.host = host
|
|
37
38
|
self.friendly_name = friendly_name
|
|
38
39
|
self.host_type = host_type
|
|
39
40
|
self.insert_type = insert_type
|
|
41
|
+
self.host_id = host_id
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
class SwidgetProtocol(ssdp.SimpleServiceDiscoveryProtocol):
|
|
@@ -37,6 +37,8 @@ class InsertType(Enum):
|
|
|
37
37
|
GL = "GUIDE LIGHT"
|
|
38
38
|
PO = "POWER OUT"
|
|
39
39
|
VIDEO = "video" # This is not a mistake.
|
|
40
|
+
USBC = "USBC"
|
|
41
|
+
WD = "WATER DETECTOR"
|
|
40
42
|
Unknown = -1
|
|
41
43
|
|
|
42
44
|
|
|
@@ -277,7 +279,7 @@ class SwidgetDevice:
|
|
|
277
279
|
try:
|
|
278
280
|
self.rssi = state["connection"]["rssi"]
|
|
279
281
|
except Exception:
|
|
280
|
-
|
|
282
|
+
self.rssi = 0
|
|
281
283
|
for assembly in self.assemblies:
|
|
282
284
|
for id, component in self.assemblies[assembly].components.items():
|
|
283
285
|
try:
|
|
@@ -544,6 +546,10 @@ class SwidgetDevice:
|
|
|
544
546
|
pass
|
|
545
547
|
elif function == "sd":
|
|
546
548
|
return_values[function] = data["state"]
|
|
549
|
+
elif function == "water":
|
|
550
|
+
return_values[function] = data["state"]
|
|
551
|
+
elif function == "buzzer":
|
|
552
|
+
return_values[function] = data["mode"]
|
|
547
553
|
else:
|
|
548
554
|
return_values[function] = data["now"]
|
|
549
555
|
return return_values
|
|
@@ -94,13 +94,13 @@ class SwidgetWebsocket:
|
|
|
94
94
|
self.retry_count = 0
|
|
95
95
|
_LOGGER.debug("Websocket now connected")
|
|
96
96
|
except (ClientConnectionError, WSServerHandshakeError):
|
|
97
|
-
_LOGGER.
|
|
97
|
+
_LOGGER.exception("Error connecting to websocket")
|
|
98
98
|
self._client = None
|
|
99
99
|
except socket.gaierror as e:
|
|
100
100
|
_LOGGER.error(f"Error resolving host: {e}")
|
|
101
101
|
self._client = None
|
|
102
|
-
except Exception
|
|
103
|
-
_LOGGER.
|
|
102
|
+
except Exception:
|
|
103
|
+
_LOGGER.exception("An unexpected error occurred.")
|
|
104
104
|
self._client = None
|
|
105
105
|
|
|
106
106
|
async def send_str(self, message: str) -> None:
|
|
@@ -126,7 +126,7 @@ class SwidgetWebsocket:
|
|
|
126
126
|
f"Failed to send message after {max_send_retries} attempts."
|
|
127
127
|
)
|
|
128
128
|
|
|
129
|
-
async def receive(self):
|
|
129
|
+
async def receive(self) -> Any | None:
|
|
130
130
|
"""Receive a message from the WebSocket server."""
|
|
131
131
|
_LOGGER.debug("websocket.receive() called")
|
|
132
132
|
try:
|
|
@@ -136,16 +136,17 @@ class SwidgetWebsocket:
|
|
|
136
136
|
message_data = message.json()
|
|
137
137
|
_LOGGER.debug(f"[{self.host}] Received message: {message_data}")
|
|
138
138
|
return message_data
|
|
139
|
-
elif message.type
|
|
140
|
-
_LOGGER.error("Websocket
|
|
139
|
+
elif message.type in (WSMsgType.CLOSED, WSMsgType.CLOSING):
|
|
140
|
+
_LOGGER.error("Websocket connection is closed")
|
|
141
141
|
self._client = None
|
|
142
142
|
elif message.type == WSMsgType.ERROR:
|
|
143
143
|
_LOGGER.error("WebSocket error.")
|
|
144
144
|
self._client = None
|
|
145
145
|
except Exception as e:
|
|
146
146
|
_LOGGER.error(f"Error receiving message: {e}")
|
|
147
|
+
return None
|
|
147
148
|
|
|
148
|
-
async def close(self):
|
|
149
|
+
async def close(self) -> None:
|
|
149
150
|
"""Close the WebSocket connection."""
|
|
150
151
|
_LOGGER.debug("websocket.close() called")
|
|
151
152
|
self.is_running = False
|
|
@@ -156,15 +157,17 @@ class SwidgetWebsocket:
|
|
|
156
157
|
if self.session and not self.session.closed:
|
|
157
158
|
await self.session.close()
|
|
158
159
|
|
|
159
|
-
async def reconnect(self):
|
|
160
|
-
"""
|
|
160
|
+
async def reconnect(self) -> None:
|
|
161
|
+
"""Attempt to reconnect to the WebSocket server, raising on failure."""
|
|
161
162
|
_LOGGER.debug("websocket.reconnect() called")
|
|
162
163
|
if self.max_retries is not None and self.retry_count >= self.max_retries:
|
|
163
|
-
_LOGGER.
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
_LOGGER.error("Max retries reached. Stopping reconnect attempts.")
|
|
165
|
+
raise ConnectionError(
|
|
166
|
+
f"Max retries reached. Could not connect to {self.host}"
|
|
167
|
+
)
|
|
166
168
|
|
|
167
169
|
self.retry_count += 1
|
|
170
|
+
# Implement exponential backoff for reconnection delay
|
|
168
171
|
delay = self.retry_interval * (2 ** (self.retry_count - 1))
|
|
169
172
|
_LOGGER.warning(
|
|
170
173
|
f"Reconnecting to Swidget device: {self.host} in {delay} seconds (attempt {self.retry_count})..."
|
|
@@ -172,7 +175,7 @@ class SwidgetWebsocket:
|
|
|
172
175
|
await asyncio.sleep(delay)
|
|
173
176
|
await self.connect()
|
|
174
177
|
|
|
175
|
-
async def run(self):
|
|
178
|
+
async def run(self) -> None:
|
|
176
179
|
"""Run the WebSocket client to handle messages and reconnections."""
|
|
177
180
|
while self.is_running:
|
|
178
181
|
if self._client is None:
|
|
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
|
|
File without changes
|