From edbb12070f48152c4cd48b0e5460981e23f4f854 Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 20 Feb 2026 12:34:30 -0700 Subject: [PATCH 1/3] feat: Add `shaper_live_pwr` method --- openevsehttp/__main__.py | 10 ++++++++++ tests/test_main.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/openevsehttp/__main__.py b/openevsehttp/__main__.py index 356049e..960cee4 100644 --- a/openevsehttp/__main__.py +++ b/openevsehttp/__main__.py @@ -1312,6 +1312,16 @@ def charging_power(self) -> float | None: return round(self._status["voltage"] * self._status["amp"], 2) return None + # Shaper HTTP Posting + async def shaper_live_pwr(self, shaper_live_pwr: int) -> None: + """Send pushed sensor data to shaper.""" + url = f"{self.url}status" + data = {"shaper_live_pwr": shaper_live_pwr} + + _LOGGER.debug("Posting shaper data: %s", data) + response = await self.process_request(url=url, method="post", data=data) + _LOGGER.debug("Shaper response: %s", response) + # Shaper values @property def shaper_active(self) -> bool | None: diff --git a/tests/test_main.py b/tests/test_main.py index a5923c8..dbc5ae2 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1271,6 +1271,21 @@ async def test_shaper_max_power(fixture, expected, request): await charger.ws_disconnect() +async def test_set_shaper_live_power(test_charger, mock_aioclient, caplog): + """Test setting shaper live power.""" + await test_charger.update() + mock_aioclient.post( + TEST_URL_STATUS, + status=200, + body='{"shaper_live_pwr": 210}', + repeat=True, + ) + with caplog.at_level(logging.DEBUG): + await test_charger.shaper_live_pwr(210) + assert "Posting shaper data: {'shaper_live_pwr': 210}" in caplog.text + assert "Shaper response: {'shaper_live_pwr': 210}" in caplog.text + + @pytest.mark.parametrize( "fixture, expected", [("test_charger", 75), ("test_charger_v2", None)] ) From d794de6a317b56183d34921fdd13271125484cbd Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 20 Feb 2026 12:46:01 -0700 Subject: [PATCH 2/3] changes based on feedback --- openevsehttp/__main__.py | 8 ++++++-- tests/test_external_session.py | 3 +-- tests/test_main.py | 24 ++++++++++++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/openevsehttp/__main__.py b/openevsehttp/__main__.py index 960cee4..231e4a1 100644 --- a/openevsehttp/__main__.py +++ b/openevsehttp/__main__.py @@ -1313,10 +1313,14 @@ def charging_power(self) -> float | None: return None # Shaper HTTP Posting - async def shaper_live_pwr(self, shaper_live_pwr: int) -> None: + async def set_shaper_live_pwr(self, power: int) -> None: """Send pushed sensor data to shaper.""" + if not self._version_check("4.0.0"): + _LOGGER.debug("Feature not supported for older firmware.") + raise UnsupportedFeature + url = f"{self.url}status" - data = {"shaper_live_pwr": shaper_live_pwr} + data = {"shaper_live_pwr": power} _LOGGER.debug("Posting shaper data: %s", data) response = await self.process_request(url=url, method="post", data=data) diff --git a/tests/test_external_session.py b/tests/test_external_session.py index 7da7e9d..7e3e6f0 100644 --- a/tests/test_external_session.py +++ b/tests/test_external_session.py @@ -1,12 +1,11 @@ """Test external session management.""" import json -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock import aiohttp import pytest -import openevsehttp.__main__ as main from openevsehttp.__main__ import OpenEVSE from tests.common import load_fixture diff --git a/tests/test_main.py b/tests/test_main.py index dbc5ae2..6dc615a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -11,7 +11,6 @@ import pytest from aiohttp.client_exceptions import ContentTypeError, ServerTimeoutError from aiohttp.client_reqrep import ConnectionKey -from awesomeversion import AwesomeVersion from awesomeversion.exceptions import AwesomeVersionCompareException from freezegun import freeze_time @@ -1271,20 +1270,37 @@ async def test_shaper_max_power(fixture, expected, request): await charger.ws_disconnect() -async def test_set_shaper_live_power(test_charger, mock_aioclient, caplog): +async def test_set_shaper_live_power( + test_charger, test_charger_v2, mock_aioclient, caplog +): """Test setting shaper live power.""" await test_charger.update() mock_aioclient.post( TEST_URL_STATUS, status=200, body='{"shaper_live_pwr": 210}', - repeat=True, ) with caplog.at_level(logging.DEBUG): - await test_charger.shaper_live_pwr(210) + await test_charger.set_shaper_live_pwr(210) assert "Posting shaper data: {'shaper_live_pwr': 210}" in caplog.text assert "Shaper response: {'shaper_live_pwr': 210}" in caplog.text + mock_aioclient.post( + TEST_URL_STATUS, + status=200, + body='{"shaper_live_pwr": 0}', + ) + with caplog.at_level(logging.DEBUG): + await test_charger.set_shaper_live_pwr(0) + assert "Posting shaper data: {'shaper_live_pwr': 0}" in caplog.text + + with pytest.raises(UnsupportedFeature): + with caplog.at_level(logging.DEBUG): + await test_charger_v2.update() + await test_charger_v2.set_shaper_live_pwr(210) + assert "Feature not supported for older firmware." in caplog.text + await test_charger_v2.ws_disconnect() + @pytest.mark.parametrize( "fixture, expected", [("test_charger", 75), ("test_charger_v2", None)] From e7e7f1d01fb80b6501006860ae8ff808f7d76ee6 Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 20 Feb 2026 12:56:37 -0700 Subject: [PATCH 3/3] update test based on feedback --- tests/test_main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 6dc615a..8ab54d2 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1294,12 +1294,12 @@ async def test_set_shaper_live_power( await test_charger.set_shaper_live_pwr(0) assert "Posting shaper data: {'shaper_live_pwr': 0}" in caplog.text + await test_charger_v2.update() with pytest.raises(UnsupportedFeature): with caplog.at_level(logging.DEBUG): - await test_charger_v2.update() await test_charger_v2.set_shaper_live_pwr(210) - assert "Feature not supported for older firmware." in caplog.text - await test_charger_v2.ws_disconnect() + assert "Feature not supported for older firmware." in caplog.text + await test_charger_v2.ws_disconnect() @pytest.mark.parametrize(