Expose energy command to cli (#1307)

Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
Teemu R.
2024-11-26 10:42:55 +01:00
committed by GitHub
parent 3dfada7575
commit 69e08c2385
5 changed files with 44 additions and 42 deletions

View File

@@ -2,7 +2,7 @@ import json
import os
import re
from datetime import datetime
from unittest.mock import ANY
from unittest.mock import ANY, PropertyMock, patch
from zoneinfo import ZoneInfo
import asyncclick as click
@@ -40,7 +40,7 @@ from kasa.cli.light import (
)
from kasa.cli.main import TYPES, _legacy_type_to_class, cli, cmd_command, raw_command
from kasa.cli.time import time
from kasa.cli.usage import emeter, energy
from kasa.cli.usage import energy
from kasa.cli.wifi import wifi
from kasa.discover import Discover, DiscoveryResult
from kasa.iot import IotDevice
@@ -432,38 +432,45 @@ async def test_time_set(dev: Device, mocker, runner):
async def test_emeter(dev: Device, mocker, runner):
res = await runner.invoke(emeter, obj=dev)
mocker.patch("kasa.Discover.discover_single", return_value=dev)
base_cmd = ["--host", "dummy", "energy"]
res = await runner.invoke(cli, base_cmd, obj=dev)
if not (energy := dev.modules.get(Module.Energy)):
assert "Device has no energy module." in res.output
return
assert "== Emeter ==" in res.output
assert "== Energy ==" in res.output
if dev.device_type is not DeviceType.Strip:
res = await runner.invoke(emeter, ["--index", "0"], obj=dev)
res = await runner.invoke(cli, [*base_cmd, "--index", "0"], obj=dev)
assert f"Device: {dev.host} does not have children" in res.output
res = await runner.invoke(emeter, ["--name", "mock"], obj=dev)
res = await runner.invoke(cli, [*base_cmd, "--name", "mock"], obj=dev)
assert f"Device: {dev.host} does not have children" in res.output
if dev.device_type is DeviceType.Strip and len(dev.children) > 0:
child_energy = dev.children[0].modules.get(Module.Energy)
assert child_energy
realtime_emeter = mocker.patch.object(child_energy, "get_status")
realtime_emeter.return_value = EmeterStatus({"voltage_mv": 122066})
res = await runner.invoke(emeter, ["--index", "0"], obj=dev)
assert "Voltage: 122.066 V" in res.output
realtime_emeter.assert_called()
assert realtime_emeter.call_count == 1
with patch.object(
type(child_energy), "status", new_callable=PropertyMock
) as child_status:
child_status.return_value = EmeterStatus({"voltage_mv": 122066})
res = await runner.invoke(emeter, ["--name", dev.children[0].alias], obj=dev)
assert "Voltage: 122.066 V" in res.output
assert realtime_emeter.call_count == 2
res = await runner.invoke(cli, [*base_cmd, "--index", "0"], obj=dev)
assert "Voltage: 122.066 V" in res.output
child_status.assert_called()
assert child_status.call_count == 1
res = await runner.invoke(
cli, [*base_cmd, "--name", dev.children[0].alias], obj=dev
)
assert "Voltage: 122.066 V" in res.output
assert child_status.call_count == 2
if isinstance(dev, IotDevice):
monthly = mocker.patch.object(energy, "get_monthly_stats")
monthly.return_value = {1: 1234}
res = await runner.invoke(emeter, ["--year", "1900"], obj=dev)
res = await runner.invoke(cli, [*base_cmd, "--year", "1900"], obj=dev)
if not isinstance(dev, IotDevice):
assert "Device does not support historical statistics" in res.output
return
@@ -474,7 +481,7 @@ async def test_emeter(dev: Device, mocker, runner):
if isinstance(dev, IotDevice):
daily = mocker.patch.object(energy, "get_daily_stats")
daily.return_value = {1: 1234}
res = await runner.invoke(emeter, ["--month", "1900-12"], obj=dev)
res = await runner.invoke(cli, [*base_cmd, "--month", "1900-12"], obj=dev)
if not isinstance(dev, IotDevice):
assert "Device has no historical statistics" in res.output
return

View File

@@ -23,14 +23,16 @@ from .conftest import has_emeter, has_emeter_iot, no_emeter
CURRENT_CONSUMPTION_SCHEMA = Schema(
Any(
{
"voltage": Any(All(float, Range(min=0, max=300)), None),
"power": Any(Coerce(float), None),
"total": Any(Coerce(float), None),
"current": Any(All(float), None),
"voltage_mv": Any(All(float, Range(min=0, max=300000)), int, None),
"power_mw": Any(Coerce(float), None),
"total_wh": Any(Coerce(float), None),
"current_ma": Any(All(float), int, None),
"energy_wh": Any(Coerce(float), None),
"total_wh": Any(Coerce(float), None),
"voltage": Any(All(float, Range(min=0, max=300)), None),
"power": Any(Coerce(float), None),
"current": Any(All(float), None),
"total": Any(Coerce(float), None),
"energy": Any(Coerce(float), None),
"slot_id": Any(Coerce(int), None),
},
None,
@@ -65,6 +67,10 @@ async def test_get_emeter_realtime(dev):
emeter = dev.modules[Module.Energy]
current_emeter = await emeter.get_status()
# Check realtime query gets the same value as status property
# iot _query_helper strips out the error code from module responses.
# but it's not stripped out of the _modular_update queries.
assert current_emeter == {k: v for k, v in emeter.status.items() if k != "err_code"}
CURRENT_CONSUMPTION_SCHEMA(current_emeter)