python-openevse-http 0.3.0__tar.gz → 0.3.1__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_openevse_http-0.3.1/PKG-INFO +121 -0
- python_openevse_http-0.3.1/README.md +88 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/commands.py +32 -0
- python_openevse_http-0.3.1/python_openevse_http.egg-info/PKG-INFO +121 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/SOURCES.txt +1 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/setup.py +1 -1
- python_openevse_http-0.3.1/tests/test_shaper.py +128 -0
- python_openevse_http-0.3.0/PKG-INFO +0 -48
- python_openevse_http-0.3.0/README.md +0 -15
- python_openevse_http-0.3.0/python_openevse_http.egg-info/PKG-INFO +0 -48
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/LICENSE +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/__init__.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/__main__.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/client.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/const.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/exceptions.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/managers.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/properties.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/sensors.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/websocket.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/pyproject.toml +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/dependency_links.txt +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/not-zip-safe +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/requires.txt +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/top_level.txt +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/setup.cfg +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_client.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_commands.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_external_session.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_main_edge_cases.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_managers.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_mixins.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_properties.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_sensors.py +0 -0
- {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_websocket.py +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python_openevse_http
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Python wrapper for OpenEVSE HTTP API
|
|
5
|
+
Home-page: https://github.com/firstof9/python-openevse-http
|
|
6
|
+
Download-URL: https://github.com/firstof9/python-openevse-http
|
|
7
|
+
Author: firstof9
|
|
8
|
+
Author-email: firstof9@gmail.com
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: aiohttp
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: author-email
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: download-url
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
# python-openevse-http
|
|
40
|
+
|
|
41
|
+
A Python library for communicating with [OpenEVSE](https://www.openevse.com/) chargers via the HTTP API on ESP8266 and ESP32-based WiFi modules.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Asynchronous**: Built on `aiohttp` for non-blocking I/O.
|
|
46
|
+
- **WebSocket Support**: Real-time updates for charger status.
|
|
47
|
+
- **Firmware Support**: Compatible with ESP8266 (2.x) and ESP32 (4.x+) WiFi firmware.
|
|
48
|
+
- **Comprehensive API**:
|
|
49
|
+
- Query status and configuration.
|
|
50
|
+
- Manage manual overrides.
|
|
51
|
+
- Control charging claims and limits.
|
|
52
|
+
- Handle schedules.
|
|
53
|
+
- **Shaper Toggle**: Enable or disable the grid shaper feature (requires firmware 4.0.0+).
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install python_openevse_http
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
from openevsehttp import OpenEVSE
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
# Initialize the charger
|
|
69
|
+
charger = OpenEVSE("192.168.1.30")
|
|
70
|
+
|
|
71
|
+
# Update state
|
|
72
|
+
await charger.update()
|
|
73
|
+
|
|
74
|
+
print(f"Charger State: {charger.status}")
|
|
75
|
+
print(f"Current Charge: {charger.charge_current}A")
|
|
76
|
+
|
|
77
|
+
# Toggle the Shaper feature
|
|
78
|
+
if charger.shaper_active:
|
|
79
|
+
print("Shaper is active, disabling...")
|
|
80
|
+
else:
|
|
81
|
+
print("Shaper is inactive, enabling...")
|
|
82
|
+
|
|
83
|
+
await charger.toggle_shaper()
|
|
84
|
+
|
|
85
|
+
# Clean up
|
|
86
|
+
await charger.close()
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
asyncio.run(main())
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## API Support Matrix
|
|
93
|
+
|
|
94
|
+
| Endpoint | Methods | Supported | Description |
|
|
95
|
+
| :--- | :--- | :---: | :--- |
|
|
96
|
+
| `/status` | GET, POST | ✅ | Real-time status, sensors, and **Vehicle SoC** pushing |
|
|
97
|
+
| `/config` | GET, POST | ✅ | System and WiFi configuration |
|
|
98
|
+
| `/override` | GET, POST, PATCH, DELETE | ✅ | Manual charging overrides & current limits |
|
|
99
|
+
| `/claims` | GET, POST, DELETE | ✅ | Client-based charging claims |
|
|
100
|
+
| `/schedule` | GET, POST | ✅ | Charging schedule management |
|
|
101
|
+
| `/limit` | GET, POST, DELETE | ✅ | Charge limits (Time, Energy, SoC) |
|
|
102
|
+
| `/shaper` | POST | ✅ | Grid shaper control (v4.0.0+) |
|
|
103
|
+
| `/restart` | POST | ✅ | Reboot WiFi gateway or EVSE module |
|
|
104
|
+
| `/divertmode` | POST | ✅ | Solar divert mode control |
|
|
105
|
+
| `/r` (RAPI) | POST | ✅ | Direct RAPI command interface |
|
|
106
|
+
| `/ws` | GET | ✅ | WebSocket real-time updates |
|
|
107
|
+
| `/time` | GET, POST | ❌ | RTC and NTP time settings |
|
|
108
|
+
| `/logs` | GET | ❌ | System and debug event logs |
|
|
109
|
+
| `/emeter` | DELETE | ❌ | Energy meter reset |
|
|
110
|
+
| `/wifi` | GET, POST | ❌ | Network scanning and AP configuration |
|
|
111
|
+
| `/tesla` | GET | ❌ | Tesla vehicle integration |
|
|
112
|
+
| `/certificates`| GET, POST, DELETE | ❌ | SSL/TLS certificate management |
|
|
113
|
+
| `/schedule/plan`| GET | ❌ | Schedule planning and optimization |
|
|
114
|
+
| `/update` | POST | ❌ | Firmware update interface |
|
|
115
|
+
| `/rfid/add` | POST | ❌ | RFID tag management |
|
|
116
|
+
|
|
117
|
+
✅ = Fully Supported \| ⚠️ = Partial Support \| ❌ = Not yet implemented
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
This project is licensed under the Apache-2.0 License.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
# python-openevse-http
|
|
7
|
+
|
|
8
|
+
A Python library for communicating with [OpenEVSE](https://www.openevse.com/) chargers via the HTTP API on ESP8266 and ESP32-based WiFi modules.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Asynchronous**: Built on `aiohttp` for non-blocking I/O.
|
|
13
|
+
- **WebSocket Support**: Real-time updates for charger status.
|
|
14
|
+
- **Firmware Support**: Compatible with ESP8266 (2.x) and ESP32 (4.x+) WiFi firmware.
|
|
15
|
+
- **Comprehensive API**:
|
|
16
|
+
- Query status and configuration.
|
|
17
|
+
- Manage manual overrides.
|
|
18
|
+
- Control charging claims and limits.
|
|
19
|
+
- Handle schedules.
|
|
20
|
+
- **Shaper Toggle**: Enable or disable the grid shaper feature (requires firmware 4.0.0+).
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install python_openevse_http
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import asyncio
|
|
32
|
+
from openevsehttp import OpenEVSE
|
|
33
|
+
|
|
34
|
+
async def main():
|
|
35
|
+
# Initialize the charger
|
|
36
|
+
charger = OpenEVSE("192.168.1.30")
|
|
37
|
+
|
|
38
|
+
# Update state
|
|
39
|
+
await charger.update()
|
|
40
|
+
|
|
41
|
+
print(f"Charger State: {charger.status}")
|
|
42
|
+
print(f"Current Charge: {charger.charge_current}A")
|
|
43
|
+
|
|
44
|
+
# Toggle the Shaper feature
|
|
45
|
+
if charger.shaper_active:
|
|
46
|
+
print("Shaper is active, disabling...")
|
|
47
|
+
else:
|
|
48
|
+
print("Shaper is inactive, enabling...")
|
|
49
|
+
|
|
50
|
+
await charger.toggle_shaper()
|
|
51
|
+
|
|
52
|
+
# Clean up
|
|
53
|
+
await charger.close()
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
asyncio.run(main())
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API Support Matrix
|
|
60
|
+
|
|
61
|
+
| Endpoint | Methods | Supported | Description |
|
|
62
|
+
| :--- | :--- | :---: | :--- |
|
|
63
|
+
| `/status` | GET, POST | ✅ | Real-time status, sensors, and **Vehicle SoC** pushing |
|
|
64
|
+
| `/config` | GET, POST | ✅ | System and WiFi configuration |
|
|
65
|
+
| `/override` | GET, POST, PATCH, DELETE | ✅ | Manual charging overrides & current limits |
|
|
66
|
+
| `/claims` | GET, POST, DELETE | ✅ | Client-based charging claims |
|
|
67
|
+
| `/schedule` | GET, POST | ✅ | Charging schedule management |
|
|
68
|
+
| `/limit` | GET, POST, DELETE | ✅ | Charge limits (Time, Energy, SoC) |
|
|
69
|
+
| `/shaper` | POST | ✅ | Grid shaper control (v4.0.0+) |
|
|
70
|
+
| `/restart` | POST | ✅ | Reboot WiFi gateway or EVSE module |
|
|
71
|
+
| `/divertmode` | POST | ✅ | Solar divert mode control |
|
|
72
|
+
| `/r` (RAPI) | POST | ✅ | Direct RAPI command interface |
|
|
73
|
+
| `/ws` | GET | ✅ | WebSocket real-time updates |
|
|
74
|
+
| `/time` | GET, POST | ❌ | RTC and NTP time settings |
|
|
75
|
+
| `/logs` | GET | ❌ | System and debug event logs |
|
|
76
|
+
| `/emeter` | DELETE | ❌ | Energy meter reset |
|
|
77
|
+
| `/wifi` | GET, POST | ❌ | Network scanning and AP configuration |
|
|
78
|
+
| `/tesla` | GET | ❌ | Tesla vehicle integration |
|
|
79
|
+
| `/certificates`| GET, POST, DELETE | ❌ | SSL/TLS certificate management |
|
|
80
|
+
| `/schedule/plan`| GET | ❌ | Schedule planning and optimization |
|
|
81
|
+
| `/update` | POST | ❌ | Firmware update interface |
|
|
82
|
+
| `/rfid/add` | POST | ❌ | RFID tag management |
|
|
83
|
+
|
|
84
|
+
✅ = Fully Supported \| ⚠️ = Partial Support \| ❌ = Not yet implemented
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
This project is licensed under the Apache-2.0 License.
|
|
@@ -491,3 +491,35 @@ class CommandsMixin:
|
|
|
491
491
|
if not success:
|
|
492
492
|
_LOGGER.error("Problem issuing command: %s", response)
|
|
493
493
|
raise UnknownError
|
|
494
|
+
|
|
495
|
+
async def set_shaper(self, enable: bool = True) -> None:
|
|
496
|
+
"""Set shaper mode."""
|
|
497
|
+
if not self._version_check("4.0.0"):
|
|
498
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
499
|
+
raise UnsupportedFeature
|
|
500
|
+
|
|
501
|
+
url = f"{self.url}shaper"
|
|
502
|
+
mode = 1 if enable else 0
|
|
503
|
+
data = {"mode": mode}
|
|
504
|
+
|
|
505
|
+
_LOGGER.debug("Setting shaper to %s", mode)
|
|
506
|
+
response = await self.process_request(url=url, method="post", data=data)
|
|
507
|
+
response = self._normalize_response(response)
|
|
508
|
+
msg = response.get("msg") if isinstance(response, Mapping) else None
|
|
509
|
+
if msg not in ["OK", "done", "no change"]:
|
|
510
|
+
_LOGGER.error("Problem issuing command: %s", response)
|
|
511
|
+
raise UnknownError
|
|
512
|
+
|
|
513
|
+
async def toggle_shaper(self) -> None:
|
|
514
|
+
"""Toggle shaper mode."""
|
|
515
|
+
shaper_active = self._status.get("shaper")
|
|
516
|
+
if shaper_active is None:
|
|
517
|
+
await self.update()
|
|
518
|
+
shaper_active = self._status.get("shaper")
|
|
519
|
+
|
|
520
|
+
if shaper_active is None:
|
|
521
|
+
_LOGGER.error("Cannot toggle shaper: unknown shaper state.")
|
|
522
|
+
raise RuntimeError("Cannot toggle shaper: unknown shaper state.")
|
|
523
|
+
|
|
524
|
+
new_state = not bool(shaper_active)
|
|
525
|
+
await self.set_shaper(new_state)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python_openevse_http
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Python wrapper for OpenEVSE HTTP API
|
|
5
|
+
Home-page: https://github.com/firstof9/python-openevse-http
|
|
6
|
+
Download-URL: https://github.com/firstof9/python-openevse-http
|
|
7
|
+
Author: firstof9
|
|
8
|
+
Author-email: firstof9@gmail.com
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: aiohttp
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: author-email
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: download-url
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
# python-openevse-http
|
|
40
|
+
|
|
41
|
+
A Python library for communicating with [OpenEVSE](https://www.openevse.com/) chargers via the HTTP API on ESP8266 and ESP32-based WiFi modules.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Asynchronous**: Built on `aiohttp` for non-blocking I/O.
|
|
46
|
+
- **WebSocket Support**: Real-time updates for charger status.
|
|
47
|
+
- **Firmware Support**: Compatible with ESP8266 (2.x) and ESP32 (4.x+) WiFi firmware.
|
|
48
|
+
- **Comprehensive API**:
|
|
49
|
+
- Query status and configuration.
|
|
50
|
+
- Manage manual overrides.
|
|
51
|
+
- Control charging claims and limits.
|
|
52
|
+
- Handle schedules.
|
|
53
|
+
- **Shaper Toggle**: Enable or disable the grid shaper feature (requires firmware 4.0.0+).
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install python_openevse_http
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
from openevsehttp import OpenEVSE
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
# Initialize the charger
|
|
69
|
+
charger = OpenEVSE("192.168.1.30")
|
|
70
|
+
|
|
71
|
+
# Update state
|
|
72
|
+
await charger.update()
|
|
73
|
+
|
|
74
|
+
print(f"Charger State: {charger.status}")
|
|
75
|
+
print(f"Current Charge: {charger.charge_current}A")
|
|
76
|
+
|
|
77
|
+
# Toggle the Shaper feature
|
|
78
|
+
if charger.shaper_active:
|
|
79
|
+
print("Shaper is active, disabling...")
|
|
80
|
+
else:
|
|
81
|
+
print("Shaper is inactive, enabling...")
|
|
82
|
+
|
|
83
|
+
await charger.toggle_shaper()
|
|
84
|
+
|
|
85
|
+
# Clean up
|
|
86
|
+
await charger.close()
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
asyncio.run(main())
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## API Support Matrix
|
|
93
|
+
|
|
94
|
+
| Endpoint | Methods | Supported | Description |
|
|
95
|
+
| :--- | :--- | :---: | :--- |
|
|
96
|
+
| `/status` | GET, POST | ✅ | Real-time status, sensors, and **Vehicle SoC** pushing |
|
|
97
|
+
| `/config` | GET, POST | ✅ | System and WiFi configuration |
|
|
98
|
+
| `/override` | GET, POST, PATCH, DELETE | ✅ | Manual charging overrides & current limits |
|
|
99
|
+
| `/claims` | GET, POST, DELETE | ✅ | Client-based charging claims |
|
|
100
|
+
| `/schedule` | GET, POST | ✅ | Charging schedule management |
|
|
101
|
+
| `/limit` | GET, POST, DELETE | ✅ | Charge limits (Time, Energy, SoC) |
|
|
102
|
+
| `/shaper` | POST | ✅ | Grid shaper control (v4.0.0+) |
|
|
103
|
+
| `/restart` | POST | ✅ | Reboot WiFi gateway or EVSE module |
|
|
104
|
+
| `/divertmode` | POST | ✅ | Solar divert mode control |
|
|
105
|
+
| `/r` (RAPI) | POST | ✅ | Direct RAPI command interface |
|
|
106
|
+
| `/ws` | GET | ✅ | WebSocket real-time updates |
|
|
107
|
+
| `/time` | GET, POST | ❌ | RTC and NTP time settings |
|
|
108
|
+
| `/logs` | GET | ❌ | System and debug event logs |
|
|
109
|
+
| `/emeter` | DELETE | ❌ | Energy meter reset |
|
|
110
|
+
| `/wifi` | GET, POST | ❌ | Network scanning and AP configuration |
|
|
111
|
+
| `/tesla` | GET | ❌ | Tesla vehicle integration |
|
|
112
|
+
| `/certificates`| GET, POST, DELETE | ❌ | SSL/TLS certificate management |
|
|
113
|
+
| `/schedule/plan`| GET | ❌ | Schedule planning and optimization |
|
|
114
|
+
| `/update` | POST | ❌ | Firmware update interface |
|
|
115
|
+
| `/rfid/add` | POST | ❌ | RFID tag management |
|
|
116
|
+
|
|
117
|
+
✅ = Fully Supported \| ⚠️ = Partial Support \| ❌ = Not yet implemented
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
This project is licensed under the Apache-2.0 License.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Tests for shaper command methods."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from openevsehttp.exceptions import UnknownError, UnsupportedFeature
|
|
8
|
+
|
|
9
|
+
pytestmark = pytest.mark.asyncio
|
|
10
|
+
|
|
11
|
+
TEST_URL_SHAPER = "http://openevse.test.tld/shaper"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def test_set_shaper(test_charger, test_charger_v2, mock_aioclient, caplog):
|
|
15
|
+
"""Test set_shaper command."""
|
|
16
|
+
await test_charger.update()
|
|
17
|
+
mock_aioclient.post(
|
|
18
|
+
TEST_URL_SHAPER,
|
|
19
|
+
status=200,
|
|
20
|
+
body='{"msg": "OK"}',
|
|
21
|
+
repeat=True,
|
|
22
|
+
)
|
|
23
|
+
with caplog.at_level(logging.DEBUG):
|
|
24
|
+
await test_charger.set_shaper(True)
|
|
25
|
+
assert "Setting shaper to 1" in caplog.text
|
|
26
|
+
|
|
27
|
+
await test_charger.set_shaper(False)
|
|
28
|
+
assert "Setting shaper to 0" in caplog.text
|
|
29
|
+
|
|
30
|
+
await test_charger_v2.update()
|
|
31
|
+
# Force version lower than 4.0.0
|
|
32
|
+
test_charger_v2._config["version"] = "3.3.1"
|
|
33
|
+
with pytest.raises(UnsupportedFeature):
|
|
34
|
+
await test_charger_v2.set_shaper(True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def test_set_shaper_fail(test_charger, mock_aioclient, caplog):
|
|
38
|
+
"""Test set_shaper failure."""
|
|
39
|
+
await test_charger.update()
|
|
40
|
+
mock_aioclient.post(
|
|
41
|
+
TEST_URL_SHAPER,
|
|
42
|
+
status=200,
|
|
43
|
+
body='{"msg": "failure!"}',
|
|
44
|
+
)
|
|
45
|
+
with pytest.raises(UnknownError):
|
|
46
|
+
await test_charger.set_shaper(True)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async def test_toggle_shaper(test_charger, mock_aioclient, caplog):
|
|
50
|
+
"""Test toggle_shaper command."""
|
|
51
|
+
await test_charger.update()
|
|
52
|
+
# Initial state from status fixture is likely True or False
|
|
53
|
+
# Let's force it to 0 (off)
|
|
54
|
+
test_charger._status["shaper"] = 0
|
|
55
|
+
|
|
56
|
+
mock_aioclient.post(
|
|
57
|
+
TEST_URL_SHAPER,
|
|
58
|
+
status=200,
|
|
59
|
+
body='{"msg": "OK"}',
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
with caplog.at_level(logging.DEBUG):
|
|
63
|
+
await test_charger.toggle_shaper()
|
|
64
|
+
assert "Setting shaper to 1" in caplog.text
|
|
65
|
+
|
|
66
|
+
# Now it's on (1)
|
|
67
|
+
test_charger._status["shaper"] = 1
|
|
68
|
+
mock_aioclient.post(
|
|
69
|
+
TEST_URL_SHAPER,
|
|
70
|
+
status=200,
|
|
71
|
+
body='{"msg": "OK"}',
|
|
72
|
+
)
|
|
73
|
+
with caplog.at_level(logging.DEBUG):
|
|
74
|
+
await test_charger.toggle_shaper()
|
|
75
|
+
assert "Setting shaper to 0" in caplog.text
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def test_toggle_shaper_missing_state(test_charger, mock_aioclient, caplog):
|
|
79
|
+
"""Test toggle_shaper when state is missing."""
|
|
80
|
+
# Clear status to force update()
|
|
81
|
+
test_charger._status = {}
|
|
82
|
+
|
|
83
|
+
# Mock the /status call that update() will make
|
|
84
|
+
from tests.common import load_fixture
|
|
85
|
+
|
|
86
|
+
TEST_URL_STATUS = "http://openevse.test.tld/status"
|
|
87
|
+
mock_aioclient.get(
|
|
88
|
+
TEST_URL_STATUS,
|
|
89
|
+
status=200,
|
|
90
|
+
body=load_fixture("v4_json/status.json"),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
mock_aioclient.post(
|
|
94
|
+
TEST_URL_SHAPER,
|
|
95
|
+
status=200,
|
|
96
|
+
body='{"msg": "OK"}',
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
with caplog.at_level(logging.DEBUG):
|
|
100
|
+
await test_charger.toggle_shaper()
|
|
101
|
+
# status.json has shaper: 1, so it should toggle to 0
|
|
102
|
+
assert "Setting shaper to 0" in caplog.text
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
async def test_toggle_shaper_failed_update(mock_aioclient, caplog):
|
|
106
|
+
"""Test toggle_shaper when state is still missing after update()."""
|
|
107
|
+
from openevsehttp import OpenEVSE
|
|
108
|
+
|
|
109
|
+
charger = OpenEVSE("openevse.test.tld")
|
|
110
|
+
|
|
111
|
+
# Mock the /status call but return status without shaper
|
|
112
|
+
mock_aioclient.get(
|
|
113
|
+
"http://openevse.test.tld/status",
|
|
114
|
+
status=200,
|
|
115
|
+
body='{"mode": 1}', # No shaper key
|
|
116
|
+
)
|
|
117
|
+
mock_aioclient.get(
|
|
118
|
+
"http://openevse.test.tld/config",
|
|
119
|
+
status=200,
|
|
120
|
+
body='{"firmware": "4.1.2"}',
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
with pytest.raises(
|
|
124
|
+
RuntimeError, match="Cannot toggle shaper: unknown shaper state."
|
|
125
|
+
):
|
|
126
|
+
await charger.toggle_shaper()
|
|
127
|
+
|
|
128
|
+
assert "Cannot toggle shaper: unknown shaper state." in caplog.text
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: python_openevse_http
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Python wrapper for OpenEVSE HTTP API
|
|
5
|
-
Home-page: https://github.com/firstof9/python-openevse-http
|
|
6
|
-
Download-URL: https://github.com/firstof9/python-openevse-http
|
|
7
|
-
Author: firstof9
|
|
8
|
-
Author-email: firstof9@gmail.com
|
|
9
|
-
License: Apache-2.0
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
-
Requires-Python: >=3.13
|
|
18
|
-
Description-Content-Type: text/markdown
|
|
19
|
-
License-File: LICENSE
|
|
20
|
-
Requires-Dist: aiohttp
|
|
21
|
-
Dynamic: author
|
|
22
|
-
Dynamic: author-email
|
|
23
|
-
Dynamic: classifier
|
|
24
|
-
Dynamic: description
|
|
25
|
-
Dynamic: description-content-type
|
|
26
|
-
Dynamic: download-url
|
|
27
|
-
Dynamic: home-page
|
|
28
|
-
Dynamic: license
|
|
29
|
-
Dynamic: license-file
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-

|
|
35
|
-

|
|
36
|
-

|
|
37
|
-

|
|
38
|
-
# python-openevse-http
|
|
39
|
-
Python Library for OpenEVSE HTTP API
|
|
40
|
-
|
|
41
|
-
A python library for communicating with the ESP8266- and ESP32-based wifi module from OpenEVSE. This library uses the HTTP API commands to query the OpenEVSE charger.
|
|
42
|
-
|
|
43
|
-
TODO:
|
|
44
|
-
- [ ] Finish tests
|
|
45
|
-
- [ ] Finish HTTP API functions
|
|
46
|
-
- [X] Setup webosocket listener for value updates
|
|
47
|
-
- [X] Convert to aiohttp from requests
|
|
48
|
-
- [X] Expose values as properties
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-

|
|
2
|
-

|
|
3
|
-

|
|
4
|
-

|
|
5
|
-
# python-openevse-http
|
|
6
|
-
Python Library for OpenEVSE HTTP API
|
|
7
|
-
|
|
8
|
-
A python library for communicating with the ESP8266- and ESP32-based wifi module from OpenEVSE. This library uses the HTTP API commands to query the OpenEVSE charger.
|
|
9
|
-
|
|
10
|
-
TODO:
|
|
11
|
-
- [ ] Finish tests
|
|
12
|
-
- [ ] Finish HTTP API functions
|
|
13
|
-
- [X] Setup webosocket listener for value updates
|
|
14
|
-
- [X] Convert to aiohttp from requests
|
|
15
|
-
- [X] Expose values as properties
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: python_openevse_http
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Python wrapper for OpenEVSE HTTP API
|
|
5
|
-
Home-page: https://github.com/firstof9/python-openevse-http
|
|
6
|
-
Download-URL: https://github.com/firstof9/python-openevse-http
|
|
7
|
-
Author: firstof9
|
|
8
|
-
Author-email: firstof9@gmail.com
|
|
9
|
-
License: Apache-2.0
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
-
Requires-Python: >=3.13
|
|
18
|
-
Description-Content-Type: text/markdown
|
|
19
|
-
License-File: LICENSE
|
|
20
|
-
Requires-Dist: aiohttp
|
|
21
|
-
Dynamic: author
|
|
22
|
-
Dynamic: author-email
|
|
23
|
-
Dynamic: classifier
|
|
24
|
-
Dynamic: description
|
|
25
|
-
Dynamic: description-content-type
|
|
26
|
-
Dynamic: download-url
|
|
27
|
-
Dynamic: home-page
|
|
28
|
-
Dynamic: license
|
|
29
|
-
Dynamic: license-file
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-

|
|
35
|
-

|
|
36
|
-

|
|
37
|
-

|
|
38
|
-
# python-openevse-http
|
|
39
|
-
Python Library for OpenEVSE HTTP API
|
|
40
|
-
|
|
41
|
-
A python library for communicating with the ESP8266- and ESP32-based wifi module from OpenEVSE. This library uses the HTTP API commands to query the OpenEVSE charger.
|
|
42
|
-
|
|
43
|
-
TODO:
|
|
44
|
-
- [ ] Finish tests
|
|
45
|
-
- [ ] Finish HTTP API functions
|
|
46
|
-
- [X] Setup webosocket listener for value updates
|
|
47
|
-
- [X] Convert to aiohttp from requests
|
|
48
|
-
- [X] Expose values as properties
|
|
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
|
|
File without changes
|
|
File without changes
|
{python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/requires.txt
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|