Skip to content

Commit db8b43a

Browse files
authored
feat: add current_power property (#490)
1 parent df6f35b commit db8b43a

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

openevsehttp/__main__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,3 +1379,11 @@ async def async_override_state(self) -> str | None:
13791379
if "state" in override.keys():
13801380
return override["state"]
13811381
return "auto"
1382+
1383+
@property
1384+
def current_power(self) -> int:
1385+
"""Return the current power (live) in watts."""
1386+
if not self._version_check("4.2.2"):
1387+
_LOGGER.debug("Feature not supported for older firmware.")
1388+
raise UnsupportedFeature
1389+
return self._status.get("power", 0)

tests/fixtures/v4_json/status-new.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"evse_connected": 1,
2020
"amp": 0,
2121
"voltage": 220,
22-
"power": 0,
22+
"power": 4500,
2323
"pilot": 48,
2424
"max_current": 48,
2525
"temp": 440,

tests/test_main.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,7 +2215,7 @@ async def test_set_divert_mode(
22152215

22162216

22172217
async def test_main_auth_instantiation():
2218-
"""Test OpenEVSE auth instantiation (covers __main__.py:111-113)."""
2218+
"""Test OpenEVSE auth instantiation."""
22192219
charger = OpenEVSE(SERVER_URL, user="user", pwd="password")
22202220

22212221
# Setup mock session to be an async context manager
@@ -2247,7 +2247,7 @@ async def test_main_auth_instantiation():
22472247

22482248

22492249
async def test_main_sync_callback():
2250-
"""Test synchronous callback in _update_status (covers __main__.py:293)."""
2250+
"""Test synchronous callback in _update_status."""
22512251
charger = OpenEVSE(SERVER_URL)
22522252
sync_callback = MagicMock()
22532253
charger.callback = sync_callback
@@ -2259,7 +2259,7 @@ async def test_main_sync_callback():
22592259

22602260

22612261
async def test_send_command_msg_fallback():
2262-
"""Test send_command return logic fallback (covers __main__.py:181)."""
2262+
"""Test send_command return logic fallback."""
22632263
charger = OpenEVSE(SERVER_URL)
22642264

22652265
# Mock response with 'msg' but no 'ret'
@@ -2278,3 +2278,28 @@ async def test_send_command_empty_fallback():
22782278
cmd, ret = await charger.send_command("$ST")
22792279
assert cmd is False
22802280
assert ret == ""
2281+
2282+
2283+
@pytest.mark.parametrize(
2284+
"fixture, expected",
2285+
[
2286+
("test_charger", UnsupportedFeature),
2287+
("test_charger_v2", UnsupportedFeature),
2288+
("test_charger_broken", UnsupportedFeature),
2289+
("test_charger_new", 4500),
2290+
],
2291+
)
2292+
async def test_power(fixture, expected, request):
2293+
"""Test current_power property."""
2294+
charger = request.getfixturevalue(fixture)
2295+
await charger.update()
2296+
2297+
# If we expect an exception (UnsupportedFeature), we must use pytest.raises
2298+
if expected is UnsupportedFeature:
2299+
with pytest.raises(UnsupportedFeature):
2300+
_ = charger.current_power
2301+
else:
2302+
# Otherwise, we check the returned value
2303+
assert charger.current_power == expected
2304+
2305+
await charger.ws_disconnect()

tests/test_websocket.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ async def ws_client_auth():
162162

163163
@pytest.mark.asyncio
164164
async def test_websocket_auth(ws_client_auth):
165-
"""Test WebSocket connection with authentication (covers websocket.py:72-73)."""
165+
"""Test WebSocket connection with authentication."""
166166
mock_ws = MagicMock()
167167
mock_ws.__aenter__ = AsyncMock(return_value=mock_ws)
168168
mock_ws.__aexit__ = AsyncMock(return_value=None)
@@ -189,7 +189,7 @@ async def empty_iter():
189189

190190
@pytest.mark.asyncio
191191
async def test_websocket_message_types(ws_client_auth):
192-
"""Test CLOSED and ERROR message types (covers websocket.py:93-101)."""
192+
"""Test CLOSED and ERROR message types."""
193193
# 1. Test CLOSED message
194194
msg_closed = MagicMock()
195195
msg_closed.type = aiohttp.WSMsgType.CLOSED
@@ -223,15 +223,15 @@ async def async_iter_error():
223223

224224
@pytest.mark.asyncio
225225
async def test_websocket_exceptions_generic(ws_client_auth):
226-
"""Test generic exception during run (covers websocket.py:125-129)."""
226+
"""Test generic exception during run."""
227227
with patch("aiohttp.ClientSession.ws_connect", side_effect=Exception("Boom")):
228228
await ws_client_auth.running()
229229
assert ws_client_auth.state == STATE_STOPPED
230230

231231

232232
@pytest.mark.asyncio
233233
async def test_websocket_unexpected_response_error(ws_client_auth):
234-
"""Test unexpected client response error (covers websocket.py:108-109)."""
234+
"""Test unexpected client response error."""
235235
# Status 500 triggers the "else" block in the exception handler
236236
error = aiohttp.ClientResponseError(
237237
request_info=MagicMock(), history=MagicMock(), status=500
@@ -249,15 +249,15 @@ async def test_websocket_unexpected_response_error(ws_client_auth):
249249

250250
@pytest.mark.asyncio
251251
async def test_keepalive_client_missing(ws_client_auth):
252-
"""Test keepalive when client is None (covers websocket.py:139)."""
252+
"""Test keepalive when client is None."""
253253
ws_client_auth._client = None
254254
# Should log warning but not crash
255255
await ws_client_auth.keepalive()
256256

257257

258258
@pytest.mark.asyncio
259259
async def test_keepalive_send_exceptions(ws_client_auth):
260-
"""Test exceptions during keepalive send (covers websocket.py:164-174)."""
260+
"""Test exceptions during keepalive send."""
261261
ws_client_auth._client = AsyncMock()
262262

263263
# TypeError

0 commit comments

Comments
 (0)