python-openevse-http 1.4.0__py3-none-any.whl → 1.6.0__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/__init__.py +8 -0
- openevsehttp/commands.py +69 -18
- openevsehttp/exceptions.py +24 -8
- openevsehttp/properties.py +31 -0
- {python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/METADATA +3 -1
- {python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/RECORD +9 -9
- {python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/WHEEL +1 -1
- {python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/top_level.txt +0 -0
openevsehttp/__init__.py
CHANGED
|
@@ -16,11 +16,15 @@ from .const import (
|
|
|
16
16
|
from .exceptions import (
|
|
17
17
|
AlreadyListening,
|
|
18
18
|
AuthenticationError,
|
|
19
|
+
CommandFailedError,
|
|
20
|
+
FirmwareResolutionError,
|
|
19
21
|
InvalidType,
|
|
20
22
|
MissingMethod,
|
|
21
23
|
MissingSerial,
|
|
24
|
+
OpenEVSEError,
|
|
22
25
|
ParseJSONError,
|
|
23
26
|
UnknownError,
|
|
27
|
+
UnknownStateError,
|
|
24
28
|
UnsupportedFeature,
|
|
25
29
|
)
|
|
26
30
|
from .websocket import (
|
|
@@ -43,15 +47,19 @@ __all__ = [
|
|
|
43
47
|
"UPDATE_TRIGGERS",
|
|
44
48
|
"AlreadyListening",
|
|
45
49
|
"AuthenticationError",
|
|
50
|
+
"CommandFailedError",
|
|
46
51
|
"ContentTypeError",
|
|
52
|
+
"FirmwareResolutionError",
|
|
47
53
|
"InvalidType",
|
|
48
54
|
"MissingMethod",
|
|
49
55
|
"MissingSerial",
|
|
50
56
|
"OpenEVSE",
|
|
57
|
+
"OpenEVSEError",
|
|
51
58
|
"OpenEVSEWebsocket",
|
|
52
59
|
"ParseJSONError",
|
|
53
60
|
"ServerTimeoutError",
|
|
54
61
|
"UnknownError",
|
|
62
|
+
"UnknownStateError",
|
|
55
63
|
"UnsupportedFeature",
|
|
56
64
|
"divert_mode",
|
|
57
65
|
"states",
|
openevsehttp/commands.py
CHANGED
|
@@ -13,7 +13,12 @@ from awesomeversion import AwesomeVersion
|
|
|
13
13
|
from awesomeversion.exceptions import AwesomeVersionCompareException
|
|
14
14
|
|
|
15
15
|
from .const import MAX_AMPS, MIN_AMPS, RAPI_ERRORS, SUCCESS_ANSWERS, divert_mode
|
|
16
|
-
from .exceptions import
|
|
16
|
+
from .exceptions import (
|
|
17
|
+
CommandFailedError,
|
|
18
|
+
FirmwareResolutionError,
|
|
19
|
+
UnknownStateError,
|
|
20
|
+
UnsupportedFeature,
|
|
21
|
+
)
|
|
17
22
|
from .utils import get_awesome_version
|
|
18
23
|
|
|
19
24
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -90,12 +95,12 @@ class CommandsMixin:
|
|
|
90
95
|
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
91
96
|
if msg not in SUCCESS_ANSWERS:
|
|
92
97
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
93
|
-
raise
|
|
98
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
94
99
|
|
|
95
100
|
async def divert_mode(self) -> Mapping[str, Any] | list[Any]:
|
|
96
101
|
"""Set the divert mode to either Normal or Eco modes."""
|
|
97
102
|
if not self._config:
|
|
98
|
-
raise
|
|
103
|
+
raise UnknownStateError("Missing configuration: self._config is required")
|
|
99
104
|
|
|
100
105
|
if not self._version_check("2.9.1"):
|
|
101
106
|
_LOGGER.debug("Feature not supported for older firmware.")
|
|
@@ -213,7 +218,7 @@ class CommandsMixin:
|
|
|
213
218
|
or response.get("msg") not in SUCCESS_ANSWERS
|
|
214
219
|
):
|
|
215
220
|
_LOGGER.error("Problem toggling override: %s", response)
|
|
216
|
-
raise
|
|
221
|
+
raise CommandFailedError(f"Failed to toggle override: {response}")
|
|
217
222
|
else:
|
|
218
223
|
# Older firmware use RAPI commands
|
|
219
224
|
_LOGGER.debug("Toggling manual override via RAPI")
|
|
@@ -222,7 +227,9 @@ class CommandsMixin:
|
|
|
222
227
|
|
|
223
228
|
if "state" not in self._status:
|
|
224
229
|
_LOGGER.error("Cannot toggle override: unknown charger state.")
|
|
225
|
-
raise
|
|
230
|
+
raise UnknownStateError(
|
|
231
|
+
"Cannot toggle override: unknown charger state."
|
|
232
|
+
)
|
|
226
233
|
|
|
227
234
|
command = "$FE" if self._status.get("state") == 254 else "$FS"
|
|
228
235
|
response, msg = await self.send_command(command)
|
|
@@ -231,7 +238,7 @@ class CommandsMixin:
|
|
|
231
238
|
isinstance(msg, str) and (msg.startswith("$NK") or msg in RAPI_ERRORS)
|
|
232
239
|
):
|
|
233
240
|
_LOGGER.error("Problem toggling override via RAPI: %s", msg)
|
|
234
|
-
raise
|
|
241
|
+
raise CommandFailedError(f"Failed to toggle override via RAPI: {msg}")
|
|
235
242
|
|
|
236
243
|
async def clear_override(self) -> None:
|
|
237
244
|
"""Clear the manual override status."""
|
|
@@ -247,7 +254,7 @@ class CommandsMixin:
|
|
|
247
254
|
_LOGGER.debug("Clear override response: %s", msg)
|
|
248
255
|
if msg not in SUCCESS_ANSWERS:
|
|
249
256
|
_LOGGER.error("Problem clearing override: %s", response)
|
|
250
|
-
raise
|
|
257
|
+
raise CommandFailedError(f"Failed to clear override: {response}")
|
|
251
258
|
|
|
252
259
|
async def set_current(self, amps: int = 6) -> None:
|
|
253
260
|
"""Set the soft current limit."""
|
|
@@ -276,7 +283,7 @@ class CommandsMixin:
|
|
|
276
283
|
or response.get("msg") not in SUCCESS_ANSWERS
|
|
277
284
|
):
|
|
278
285
|
_LOGGER.error("Problem setting current limit: %s", response)
|
|
279
|
-
raise
|
|
286
|
+
raise CommandFailedError(f"Problem setting current limit: {response}")
|
|
280
287
|
|
|
281
288
|
else:
|
|
282
289
|
# RAPI commands
|
|
@@ -291,7 +298,7 @@ class CommandsMixin:
|
|
|
291
298
|
isinstance(msg, str) and (msg.startswith("$NK") or msg in RAPI_ERRORS)
|
|
292
299
|
):
|
|
293
300
|
_LOGGER.error("Problem setting current via RAPI: %s", msg)
|
|
294
|
-
raise
|
|
301
|
+
raise CommandFailedError(f"Problem setting current via RAPI: {msg}")
|
|
295
302
|
|
|
296
303
|
async def set_service_level(self, level: int | str = 2) -> None:
|
|
297
304
|
"""Set the service level of the EVSE."""
|
|
@@ -311,7 +318,7 @@ class CommandsMixin:
|
|
|
311
318
|
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
312
319
|
if msg not in SUCCESS_ANSWERS:
|
|
313
320
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
314
|
-
raise
|
|
321
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
315
322
|
|
|
316
323
|
# Restart OpenEVSE WiFi
|
|
317
324
|
async def restart_wifi(self) -> None:
|
|
@@ -346,7 +353,7 @@ class CommandsMixin:
|
|
|
346
353
|
|
|
347
354
|
if not success:
|
|
348
355
|
_LOGGER.error("Problem restarting WiFi: %s", response)
|
|
349
|
-
raise
|
|
356
|
+
raise CommandFailedError(f"Failed to restart WiFi: {msg}")
|
|
350
357
|
|
|
351
358
|
# Restart EVSE module
|
|
352
359
|
async def restart_evse(self) -> None:
|
|
@@ -364,7 +371,9 @@ class CommandsMixin:
|
|
|
364
371
|
or reply.get("error")
|
|
365
372
|
):
|
|
366
373
|
_LOGGER.error("Problem restarting EVSE module via HTTP: %s", reply)
|
|
367
|
-
raise
|
|
374
|
+
raise CommandFailedError(
|
|
375
|
+
f"Failed to restart EVSE module via HTTP: {reply}"
|
|
376
|
+
)
|
|
368
377
|
|
|
369
378
|
response = (
|
|
370
379
|
reply.get("msg", "Unknown error")
|
|
@@ -381,7 +390,7 @@ class CommandsMixin:
|
|
|
381
390
|
and (response.startswith("$NK") or response in RAPI_ERRORS)
|
|
382
391
|
):
|
|
383
392
|
_LOGGER.error("Problem restarting EVSE module via RAPI: %s", response)
|
|
384
|
-
raise
|
|
393
|
+
raise CommandFailedError(
|
|
385
394
|
f"Failed to restart EVSE module via RAPI: {response}"
|
|
386
395
|
)
|
|
387
396
|
|
|
@@ -563,7 +572,7 @@ class CommandsMixin:
|
|
|
563
572
|
_LOGGER.error(
|
|
564
573
|
"Could not resolve latest firmware download URL from GitHub."
|
|
565
574
|
)
|
|
566
|
-
raise
|
|
575
|
+
raise FirmwareResolutionError(
|
|
567
576
|
"Could not resolve latest firmware download URL from GitHub."
|
|
568
577
|
)
|
|
569
578
|
firmware_url = check_result["browser_download_url"]
|
|
@@ -605,7 +614,7 @@ class CommandsMixin:
|
|
|
605
614
|
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
606
615
|
if msg not in SUCCESS_ANSWERS:
|
|
607
616
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
608
|
-
raise
|
|
617
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
609
618
|
|
|
610
619
|
async def set_divert_mode(self, mode: str = "fast") -> None:
|
|
611
620
|
"""Set the divert mode."""
|
|
@@ -630,7 +639,7 @@ class CommandsMixin:
|
|
|
630
639
|
|
|
631
640
|
if not success:
|
|
632
641
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
633
|
-
raise
|
|
642
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
634
643
|
|
|
635
644
|
self._status["divertmode"] = new_mode
|
|
636
645
|
|
|
@@ -650,7 +659,7 @@ class CommandsMixin:
|
|
|
650
659
|
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
651
660
|
if msg not in SUCCESS_ANSWERS and msg != "Current Shaper state changed":
|
|
652
661
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
653
|
-
raise
|
|
662
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
654
663
|
|
|
655
664
|
self._status["shaper"] = mode
|
|
656
665
|
|
|
@@ -663,7 +672,49 @@ class CommandsMixin:
|
|
|
663
672
|
|
|
664
673
|
if shaper_active is None:
|
|
665
674
|
_LOGGER.error("Cannot toggle shaper: unknown shaper state.")
|
|
666
|
-
raise
|
|
675
|
+
raise UnknownStateError("Cannot toggle shaper: unknown shaper state.")
|
|
667
676
|
|
|
668
677
|
new_state = not bool(shaper_active)
|
|
669
678
|
await self.set_shaper(new_state)
|
|
679
|
+
|
|
680
|
+
async def set_mqtt_vehicle_range_miles(self, enable: bool = True) -> None:
|
|
681
|
+
"""Set mqtt_vehicle_range_miles configuration setting.
|
|
682
|
+
|
|
683
|
+
Dynamically changing this setting will affect future evaluations of
|
|
684
|
+
the vehicle_range_with_unit property.
|
|
685
|
+
"""
|
|
686
|
+
if not isinstance(enable, bool):
|
|
687
|
+
raise TypeError("Value must be a boolean.")
|
|
688
|
+
|
|
689
|
+
url = f"{self.url}config"
|
|
690
|
+
data = {"mqtt_vehicle_range_miles": enable}
|
|
691
|
+
|
|
692
|
+
_LOGGER.debug("Setting mqtt_vehicle_range_miles to %s", enable)
|
|
693
|
+
response = await self.process_request(url=url, method="post", data=data)
|
|
694
|
+
response = self._normalize_response(response)
|
|
695
|
+
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
696
|
+
if msg not in SUCCESS_ANSWERS:
|
|
697
|
+
_LOGGER.error("Problem issuing command: %s", response)
|
|
698
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
699
|
+
|
|
700
|
+
async def set_rfid_enabled(self, enable: bool = True) -> None:
|
|
701
|
+
"""Enable or disable RFID access."""
|
|
702
|
+
if not self._version_check("4.1.4"):
|
|
703
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
704
|
+
raise UnsupportedFeature
|
|
705
|
+
|
|
706
|
+
if not isinstance(enable, bool):
|
|
707
|
+
raise TypeError("Value must be a boolean.")
|
|
708
|
+
|
|
709
|
+
url = f"{self.url}config"
|
|
710
|
+
data = {"rfid_enabled": enable}
|
|
711
|
+
|
|
712
|
+
_LOGGER.debug("Setting rfid_enabled to %s", enable)
|
|
713
|
+
response = await self.process_request(url=url, method="post", data=data)
|
|
714
|
+
response = self._normalize_response(response)
|
|
715
|
+
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
716
|
+
if msg not in SUCCESS_ANSWERS:
|
|
717
|
+
_LOGGER.error("Problem issuing command: %s", response)
|
|
718
|
+
raise CommandFailedError(f"Problem issuing command: {response}")
|
|
719
|
+
|
|
720
|
+
self._config["rfid_enabled"] = enable
|
openevsehttp/exceptions.py
CHANGED
|
@@ -1,33 +1,49 @@
|
|
|
1
1
|
"""Exceptions."""
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class OpenEVSEError(Exception):
|
|
5
|
+
"""Base exception for python-openevse-http."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthenticationError(OpenEVSEError):
|
|
5
9
|
"""Exception for authentication errors."""
|
|
6
10
|
|
|
7
11
|
|
|
8
|
-
class ParseJSONError(
|
|
12
|
+
class ParseJSONError(OpenEVSEError):
|
|
9
13
|
"""Exception for JSON parsing errors."""
|
|
10
14
|
|
|
11
15
|
|
|
12
|
-
class UnknownError(
|
|
16
|
+
class UnknownError(OpenEVSEError):
|
|
13
17
|
"""Exception for Unknown errors."""
|
|
14
18
|
|
|
15
19
|
|
|
16
|
-
class MissingMethod(
|
|
20
|
+
class MissingMethod(OpenEVSEError):
|
|
17
21
|
"""Exception for missing method variable."""
|
|
18
22
|
|
|
19
23
|
|
|
20
|
-
class AlreadyListening(
|
|
24
|
+
class AlreadyListening(OpenEVSEError):
|
|
21
25
|
"""Exception for already listening websocket."""
|
|
22
26
|
|
|
23
27
|
|
|
24
|
-
class MissingSerial(
|
|
28
|
+
class MissingSerial(OpenEVSEError):
|
|
25
29
|
"""Exception for missing serial number."""
|
|
26
30
|
|
|
27
31
|
|
|
28
|
-
class UnsupportedFeature(
|
|
32
|
+
class UnsupportedFeature(OpenEVSEError):
|
|
29
33
|
"""Exception for firmware that is too old."""
|
|
30
34
|
|
|
31
35
|
|
|
32
|
-
class InvalidType(
|
|
36
|
+
class InvalidType(OpenEVSEError):
|
|
33
37
|
"""Exception for invalid types."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class CommandFailedError(OpenEVSEError):
|
|
41
|
+
"""Exception for command rejections or failures."""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class UnknownStateError(OpenEVSEError):
|
|
45
|
+
"""Exception when charger state cannot be determined."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FirmwareResolutionError(OpenEVSEError):
|
|
49
|
+
"""Exception when firmware download URL cannot be resolved."""
|
openevsehttp/properties.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
+
import warnings
|
|
6
7
|
from collections.abc import Mapping
|
|
7
8
|
from datetime import datetime, timedelta, timezone
|
|
8
9
|
from typing import Any, cast
|
|
@@ -458,11 +459,33 @@ class PropertiesMixin:
|
|
|
458
459
|
@property
|
|
459
460
|
def vehicle_range(self) -> int | None:
|
|
460
461
|
"""Return battery range."""
|
|
462
|
+
warnings.warn(
|
|
463
|
+
"vehicle_range is deprecated, use vehicle_range_with_unit instead",
|
|
464
|
+
DeprecationWarning,
|
|
465
|
+
stacklevel=2,
|
|
466
|
+
)
|
|
461
467
|
return cast(
|
|
462
468
|
"int | None",
|
|
463
469
|
self._status.get("vehicle_range", self._status.get("battery_range", None)),
|
|
464
470
|
)
|
|
465
471
|
|
|
472
|
+
@property
|
|
473
|
+
def vehicle_range_with_unit(self) -> tuple[int, str] | None:
|
|
474
|
+
"""Return battery range and its unit."""
|
|
475
|
+
value = cast(
|
|
476
|
+
"int | None",
|
|
477
|
+
self._status.get("vehicle_range", self._status.get("battery_range", None)),
|
|
478
|
+
)
|
|
479
|
+
if value is None:
|
|
480
|
+
return None
|
|
481
|
+
unit = "miles" if self.mqtt_vehicle_range_miles else "km"
|
|
482
|
+
return (value, unit)
|
|
483
|
+
|
|
484
|
+
@property
|
|
485
|
+
def mqtt_vehicle_range_miles(self) -> bool:
|
|
486
|
+
"""Return True if mqtt vehicle range is in miles, False if km."""
|
|
487
|
+
return bool(self._config.get("mqtt_vehicle_range_miles", False))
|
|
488
|
+
|
|
466
489
|
@property
|
|
467
490
|
def vehicle_eta(self) -> datetime | None:
|
|
468
491
|
"""Return time to full charge."""
|
|
@@ -545,3 +568,11 @@ class PropertiesMixin:
|
|
|
545
568
|
_LOGGER.debug("Feature not supported for older firmware.")
|
|
546
569
|
raise UnsupportedFeature
|
|
547
570
|
return int(self._status.get("power", 0))
|
|
571
|
+
|
|
572
|
+
@property
|
|
573
|
+
def rfid_enabled(self) -> bool | None:
|
|
574
|
+
"""Return charger RFID enabled state."""
|
|
575
|
+
if not self._version_check("4.1.4"):
|
|
576
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
577
|
+
raise UnsupportedFeature
|
|
578
|
+
return self._config.get("rfid_enabled")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python_openevse_http
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
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
|
|
@@ -65,6 +65,7 @@ import asyncio
|
|
|
65
65
|
import aiohttp
|
|
66
66
|
from openevsehttp import OpenEVSE
|
|
67
67
|
|
|
68
|
+
|
|
68
69
|
async def main():
|
|
69
70
|
async with aiohttp.ClientSession() as session:
|
|
70
71
|
charger = OpenEVSE("192.168.1.30", session=session)
|
|
@@ -81,6 +82,7 @@ async def main():
|
|
|
81
82
|
await charger.toggle_shaper()
|
|
82
83
|
await charger.ws_disconnect()
|
|
83
84
|
|
|
85
|
+
|
|
84
86
|
if __name__ == "__main__":
|
|
85
87
|
asyncio.run(main())
|
|
86
88
|
```
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
openevsehttp/__init__.py,sha256=
|
|
1
|
+
openevsehttp/__init__.py,sha256=QeXl80ozsK6J9PN-jB_83Bde31YXFGgLuUdmArpZAMM,1363
|
|
2
2
|
openevsehttp/__main__.py,sha256=EHmSdT7GjAVvHQxvLBTjZXsj_V5SB6B2_kpgUAT7mPM,146
|
|
3
3
|
openevsehttp/client.py,sha256=bySzhJ9SKU0IN7-QQfW7_ZrKNw-EoPV4RvnRBXtmCQ8,19326
|
|
4
|
-
openevsehttp/commands.py,sha256=
|
|
4
|
+
openevsehttp/commands.py,sha256=LzGGQbFnpLGwZ7mFgJ_xb08g6PV8-r-sqOmiMlqNlwY,29691
|
|
5
5
|
openevsehttp/const.py,sha256=-frkFduu8hxEBab9FnwA3D65XHrsyH0W7P9miYsWh90,1726
|
|
6
|
-
openevsehttp/exceptions.py,sha256=
|
|
6
|
+
openevsehttp/exceptions.py,sha256=FkU2v6LaZodUmZy78bOsF16der3M0T3y6pQXzTXwFg0,1106
|
|
7
7
|
openevsehttp/managers.py,sha256=EtQMQziwhoZeqKe2zWY-0yS7zedhuYjYtL5j9xBBCZ0,5380
|
|
8
|
-
openevsehttp/properties.py,sha256=
|
|
8
|
+
openevsehttp/properties.py,sha256=yFzpZQAzSNwiz2gAcqC3Spe9gQHa_orLyfgs7eZwL14,19093
|
|
9
9
|
openevsehttp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
openevsehttp/sensors.py,sha256=zhQSToY_Zp2rOhPnUXT40xS5ZnUavqNGLm4zAFiUUrY,5717
|
|
11
11
|
openevsehttp/utils.py,sha256=fPUWL64gFTRw4TtV4WITDAFMJ75VjNhPBaU6diwVlv0,2019
|
|
12
12
|
openevsehttp/websocket.py,sha256=yMuLNsB2qYZLtfYRW7-D7NH7rv-qaSTp7F79OajKm_0,10790
|
|
13
|
-
python_openevse_http-1.
|
|
14
|
-
python_openevse_http-1.
|
|
15
|
-
python_openevse_http-1.
|
|
16
|
-
python_openevse_http-1.
|
|
17
|
-
python_openevse_http-1.
|
|
13
|
+
python_openevse_http-1.6.0.dist-info/licenses/LICENSE,sha256=hSB6TOQ7rmwSGb6XzqRjDGMvmUj5_GlacqQin3tegtA,11341
|
|
14
|
+
python_openevse_http-1.6.0.dist-info/METADATA,sha256=t-5bsWNGUFccdXWSE67jI_68jQSoak7CzQXyIH8zhqk,5413
|
|
15
|
+
python_openevse_http-1.6.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
16
|
+
python_openevse_http-1.6.0.dist-info/top_level.txt,sha256=u8RUkoEIE33Cjn6gmqiEoVpZ0VZ59WJ3FXBwwOg0CPE,13
|
|
17
|
+
python_openevse_http-1.6.0.dist-info/RECORD,,
|
{python_openevse_http-1.4.0.dist-info → python_openevse_http-1.6.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|