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.
Files changed (35) hide show
  1. python_openevse_http-0.3.1/PKG-INFO +121 -0
  2. python_openevse_http-0.3.1/README.md +88 -0
  3. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/commands.py +32 -0
  4. python_openevse_http-0.3.1/python_openevse_http.egg-info/PKG-INFO +121 -0
  5. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/SOURCES.txt +1 -0
  6. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/setup.py +1 -1
  7. python_openevse_http-0.3.1/tests/test_shaper.py +128 -0
  8. python_openevse_http-0.3.0/PKG-INFO +0 -48
  9. python_openevse_http-0.3.0/README.md +0 -15
  10. python_openevse_http-0.3.0/python_openevse_http.egg-info/PKG-INFO +0 -48
  11. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/LICENSE +0 -0
  12. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/__init__.py +0 -0
  13. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/__main__.py +0 -0
  14. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/client.py +0 -0
  15. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/const.py +0 -0
  16. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/exceptions.py +0 -0
  17. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/managers.py +0 -0
  18. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/properties.py +0 -0
  19. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/sensors.py +0 -0
  20. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/openevsehttp/websocket.py +0 -0
  21. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/pyproject.toml +0 -0
  22. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/dependency_links.txt +0 -0
  23. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/not-zip-safe +0 -0
  24. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/requires.txt +0 -0
  25. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/python_openevse_http.egg-info/top_level.txt +0 -0
  26. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/setup.cfg +0 -0
  27. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_client.py +0 -0
  28. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_commands.py +0 -0
  29. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_external_session.py +0 -0
  30. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_main_edge_cases.py +0 -0
  31. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_managers.py +0 -0
  32. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_mixins.py +0 -0
  33. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_properties.py +0 -0
  34. {python_openevse_http-0.3.0 → python_openevse_http-0.3.1}/tests/test_sensors.py +0 -0
  35. {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
+ ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
35
+ ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
36
+ ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
37
+ ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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
+ ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
2
+ ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
3
+ ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
4
+ ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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
+ ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
35
+ ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
36
+ ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
37
+ ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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.
@@ -26,4 +26,5 @@ tests/test_managers.py
26
26
  tests/test_mixins.py
27
27
  tests/test_properties.py
28
28
  tests/test_sensors.py
29
+ tests/test_shaper.py
29
30
  tests/test_websocket.py
@@ -6,7 +6,7 @@ from setuptools import find_packages, setup
6
6
 
7
7
  PROJECT_DIR = Path(__file__).parent.resolve()
8
8
  README_FILE = PROJECT_DIR / "README.md"
9
- VERSION = "0.3.0"
9
+ VERSION = "0.3.1"
10
10
 
11
11
  setup(
12
12
  name="python_openevse_http",
@@ -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
- ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
35
- ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
36
- ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
37
- ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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
- ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
2
- ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
3
- ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
4
- ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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
- ![Codecov branch](https://img.shields.io/codecov/c/github/firstof9/python-openevse-http/main?style=flat-square)
35
- ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/firstof9/python-openevse-http?style=flat-square)
36
- ![GitHub last commit](https://img.shields.io/github/last-commit/firstof9/python-openevse-http?style=flat-square)
37
- ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firstof9/python-openevse-http?style=flat-square)
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