python-openevse-http 0.4.0__py3-none-any.whl → 0.4.2__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.
openevsehttp/client.py CHANGED
@@ -183,12 +183,12 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
183
183
  return (False, "")
184
184
  return (value["cmd"], value["ret"])
185
185
 
186
- async def update(self) -> None:
186
+ async def update(self, force_status: bool = False) -> None:
187
187
  """Update the values."""
188
188
  # TODO: add addiontal endpoints to update
189
189
  urls = [f"{self.url}config"]
190
190
 
191
- if not self._ws_listening:
191
+ if not self._ws_listening or force_status or self.ota_update:
192
192
  urls = [f"{self.url}status", f"{self.url}config"]
193
193
 
194
194
  for url in urls:
@@ -196,7 +196,7 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
196
196
  response = await self.process_request(url, method="get")
197
197
  if "/status" in url:
198
198
  if isinstance(response, Mapping) and "error" not in response:
199
- self._status = dict(response)
199
+ self._status.update(dict(response))
200
200
  _LOGGER.debug("Status update: %s", self._status)
201
201
  elif isinstance(response, Mapping):
202
202
  _LOGGER.warning(
@@ -337,6 +337,16 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
337
337
  # TODO: update specific endpoints based on _version prefix
338
338
  if any(key in keys for key in UPDATE_TRIGGERS):
339
339
  await self.update()
340
+
341
+ if "ota" in keys:
342
+ ota_val = data["ota"]
343
+ if ota_val == "started":
344
+ self._status["ota_update"] = 1
345
+ elif ota_val in ("completed", "failed"):
346
+ self._status["ota_update"] = 0
347
+ data.pop("ota_progress", None)
348
+ self._status.pop("ota_progress", None)
349
+
340
350
  self._status.update(data)
341
351
 
342
352
  if self.callback is not None:
openevsehttp/commands.py CHANGED
@@ -39,13 +39,22 @@ class CommandsMixin:
39
39
  async def send_command(self, command: str) -> tuple:
40
40
  raise NotImplementedError
41
41
 
42
- async def update(self) -> None:
42
+ async def update(self, force_status: bool = False) -> None:
43
43
  raise NotImplementedError
44
44
 
45
45
  def _normalize_response(self, response: Any) -> dict[str, Any] | list[Any]:
46
46
  """Normalize response to a dict or list."""
47
47
  raise NotImplementedError
48
48
 
49
+ def _flag_ota_if_started(self, response: Any) -> None:
50
+ """Flag OTA as active if response indicates firmware update has started."""
51
+ normalized = self._normalize_response(response)
52
+ if isinstance(normalized, dict) and (
53
+ normalized.get("msg") == "started"
54
+ or normalized.get("msg") in SUCCESS_ANSWERS
55
+ ):
56
+ self._status["ota_update"] = 1
57
+
49
58
  async def get_schedule(self) -> Mapping[str, Any] | list[Any]:
50
59
  """Return the current schedule."""
51
60
  url = f"{self.url}schedule"
@@ -447,6 +456,10 @@ class CommandsMixin:
447
456
  2. Pass firmware_url to tell the device to download the file directly.
448
457
  3. Pass neither to automatically resolve the latest matching binary URL from GitHub.
449
458
  """
459
+ if not self._version_check("4.1.7"):
460
+ _LOGGER.debug("Feature not supported for older firmware.")
461
+ raise UnsupportedFeature
462
+
450
463
  if firmware_bytes is not None and firmware_url is not None:
451
464
  raise ValueError("Cannot specify both firmware_bytes and firmware_url")
452
465
 
@@ -469,7 +482,11 @@ class CommandsMixin:
469
482
  "Uploading firmware binary to %s (%d bytes)", url, len(firmware_bytes)
470
483
  )
471
484
  # Rapi is mapped to http request's data kwarg in process_request
472
- return await self.process_request(url=url, method="post", rapi=form_data)
485
+ response = await self.process_request(
486
+ url=url, method="post", rapi=form_data
487
+ )
488
+ self._flag_ota_if_started(response)
489
+ return response
473
490
 
474
491
  # 2. Resolve URL from GitHub if not specified
475
492
  if firmware_url is None:
@@ -485,7 +502,9 @@ class CommandsMixin:
485
502
  _LOGGER.debug(
486
503
  "Requesting OpenEVSE to download and update from: %s", firmware_url
487
504
  )
488
- return await self.process_request(url=url, method="post", data=data)
505
+ response = await self.process_request(url=url, method="post", data=data)
506
+ self._flag_ota_if_started(response)
507
+ return response
489
508
 
490
509
  async def set_led_brightness(self, level: int) -> None:
491
510
  """Set LED brightness level."""
@@ -341,7 +341,17 @@ class PropertiesMixin:
341
341
  @property
342
342
  def ota_update(self) -> bool:
343
343
  """Return if an OTA update is active."""
344
- return self._status.get("ota_update", False)
344
+ return bool(self._status.get("ota_update", False))
345
+
346
+ @property
347
+ def ota_progress(self) -> int | None:
348
+ """Return the progress of the current OTA update."""
349
+ return self._status.get("ota_progress")
350
+
351
+ @property
352
+ def ota_state(self) -> str | None:
353
+ """Return the state of the current OTA update."""
354
+ return self._status.get("ota")
345
355
 
346
356
  @property
347
357
  def manual_override(self) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_openevse_http
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Python wrapper for OpenEVSE HTTP API
5
5
  Home-page: https://github.com/firstof9/python-openevse-http
6
6
  Download-URL: https://github.com/firstof9/python-openevse-http
@@ -1,16 +1,16 @@
1
1
  openevsehttp/__init__.py,sha256=I6a1mjOZHYiWb_qfCuDuFLOOncrkkB_7uwybtOIujfY,1165
2
2
  openevsehttp/__main__.py,sha256=EHmSdT7GjAVvHQxvLBTjZXsj_V5SB6B2_kpgUAT7mPM,146
3
- openevsehttp/client.py,sha256=JBAC1jJGdzOabVAqHv8x6EJDVjhaW4t7Iwqn4lDWhwE,17502
4
- openevsehttp/commands.py,sha256=Pv3H0VXWndQica4J4zZlGbxvCz8NjGyJdkppcTnrZcs,23384
3
+ openevsehttp/client.py,sha256=2SGL0RKZp08t_hGXHKIIRGk8wyrNJRcSXQE7nc0P9UU,17951
4
+ openevsehttp/commands.py,sha256=XJO_FPdkzqBW7AU4VvBGktZ84TxRQ3a358mNAkqXQRw,24151
5
5
  openevsehttp/const.py,sha256=y-2hGv_PCal_-VCSGC7IIyzQYtfeVdq3MjOhBWIdZvc,1440
6
6
  openevsehttp/exceptions.py,sha256=bqz-tHTW1AYJMKcm0s5M6z5tA6XZgjnCiBLW1XrZ_70,672
7
7
  openevsehttp/managers.py,sha256=kEX1ZD9u-FY0UEZJsxeFEGBSGzSlkbBc0kmxCiMJtJw,5373
8
- openevsehttp/properties.py,sha256=QVSyn_5a7vI1b4TdnnToRdw6veVCfnp7a19VYit95hg,17107
8
+ openevsehttp/properties.py,sha256=9fmJo6xU8im-Dd2QoH8f2E-0veD8uL1QQYiaERvIRr8,17430
9
9
  openevsehttp/sensors.py,sha256=sJP2FPnU1Lk5S3VUyFT14JM1nKEBQPsjl-DiZI-pZrs,4673
10
10
  openevsehttp/utils.py,sha256=e3HH_jwZgb1iBWJgIoMOM0JPrQNwXyVdOx5vTWOh4T0,858
11
11
  openevsehttp/websocket.py,sha256=Mi_WFmlT3-9i6bbHIN6ua09SD8CpIle2vRXB3HyWzmM,10066
12
- python_openevse_http-0.4.0.dist-info/licenses/LICENSE,sha256=hSB6TOQ7rmwSGb6XzqRjDGMvmUj5_GlacqQin3tegtA,11341
13
- python_openevse_http-0.4.0.dist-info/METADATA,sha256=oSaVonGB3ZuiNKcUHN-X-tqW6p3K5Is8wDY8FLjpg7M,4363
14
- python_openevse_http-0.4.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
15
- python_openevse_http-0.4.0.dist-info/top_level.txt,sha256=u8RUkoEIE33Cjn6gmqiEoVpZ0VZ59WJ3FXBwwOg0CPE,13
16
- python_openevse_http-0.4.0.dist-info/RECORD,,
12
+ python_openevse_http-0.4.2.dist-info/licenses/LICENSE,sha256=hSB6TOQ7rmwSGb6XzqRjDGMvmUj5_GlacqQin3tegtA,11341
13
+ python_openevse_http-0.4.2.dist-info/METADATA,sha256=gK5gBUi_Jy8Zza4bAxOjZ51_GtLY0ILses5rYUEJBT8,4363
14
+ python_openevse_http-0.4.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
15
+ python_openevse_http-0.4.2.dist-info/top_level.txt,sha256=u8RUkoEIE33Cjn6gmqiEoVpZ0VZ59WJ3FXBwwOg0CPE,13
16
+ python_openevse_http-0.4.2.dist-info/RECORD,,