python-swidget 1.4.4__tar.gz → 1.4.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-swidget
3
- Version: 1.4.4
3
+ Version: 1.4.6
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-swidget"
3
- version = "1.4.4"
3
+ version = "1.4.6"
4
4
  description = "Python API for Swidget smart devices"
5
5
  license = "GPL-3.0-or-later"
6
6
  authors = ["Swidget"]
@@ -249,7 +249,9 @@ class SwidgetDevice:
249
249
  raise ValueError(f"Unsupported HTTP method: {http_method}")
250
250
 
251
251
  url = f"{self.uri_scheme}://{self.ip_address}/api/v1/{endpoint}"
252
- _LOGGER.debug(f"Sending {http_method} request to: {url}")
252
+ _LOGGER.debug(
253
+ f"HTTP {http_method} {url} params={params} body={json_payload}"
254
+ )
253
255
 
254
256
  try:
255
257
  async with self._session.request(
@@ -261,14 +263,22 @@ class SwidgetDevice:
261
263
  ) as response:
262
264
  if response.status == 200:
263
265
  if response.content_length == 0:
266
+ _LOGGER.debug(
267
+ f"HTTP {response.status} {url} (empty body)"
268
+ )
264
269
  return {}
265
- return await response.json()
270
+ body = await response.json()
271
+ _LOGGER.debug(f"HTTP {response.status} {url} body={body}")
272
+ return body
266
273
  elif response.status == 403:
267
274
  _LOGGER.error(
268
275
  f"Authentication failed for {http_method} '{endpoint}'"
269
276
  )
270
277
  raise SwidgetAuthenticationException
271
278
  else:
279
+ _LOGGER.debug(
280
+ f"HTTP {response.status} {url} (non-success)"
281
+ )
272
282
  response.raise_for_status()
273
283
  return {}
274
284
  except ClientConnectorError as e:
@@ -722,8 +732,8 @@ class SwidgetDevice:
722
732
 
723
733
  @property
724
734
  def is_outlet(self) -> bool:
725
- """Return True if the device is an outlet."""
726
- return self.device_type == DeviceType.Outlet
735
+ """Return True if the device is an outlet (any variant)."""
736
+ return self.device_type in (DeviceType.Outlet, DeviceType.Outlet20A)
727
737
 
728
738
  @property
729
739
  def is_switch(self) -> bool:
@@ -107,7 +107,7 @@ class SwidgetWebsocket:
107
107
 
108
108
  async def send_str(self, message: str) -> None:
109
109
  """Send a string message through the websocket with retry attempts."""
110
- _LOGGER.debug("websocket.send_str() called")
110
+ _LOGGER.debug(f"[{self.host}] websocket.send_str: {message}")
111
111
  max_send_retries = 3
112
112
  for attempt in range(max_send_retries):
113
113
  try:
@@ -139,13 +139,24 @@ class SwidgetWebsocket:
139
139
  _LOGGER.debug(f"[{self.host}] Received message: {message_data}")
140
140
  return message_data
141
141
  elif message.type in (WSMsgType.CLOSED, WSMsgType.CLOSING):
142
- _LOGGER.error("Websocket connection is closed")
142
+ # message.data carries the close code (int) when present;
143
+ # message.extra carries the reason string. close_code on
144
+ # the client also reflects the final negotiated code.
145
+ _LOGGER.error(
146
+ f"[{self.host}] Websocket closed "
147
+ f"(type={message.type.name}, "
148
+ f"code={message.data!r}, "
149
+ f"reason={message.extra!r}, "
150
+ f"client.close_code={getattr(self._client, 'close_code', None)!r})"
151
+ )
143
152
  self._client = None
144
153
  elif message.type == WSMsgType.ERROR:
145
- _LOGGER.error("WebSocket error.")
154
+ _LOGGER.error(
155
+ f"[{self.host}] Websocket error: {message.data!r}"
156
+ )
146
157
  self._client = None
147
158
  except Exception as e:
148
- _LOGGER.error(f"Error receiving message: {e}")
159
+ _LOGGER.error(f"Error receiving message: {e}", exc_info=True)
149
160
  return None
150
161
 
151
162
  async def close(self) -> None:
File without changes