mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
Add --child option to feature command (#789)
This allows listing and changing child device features that were previously not accessible using the cli tool.
This commit is contained in:
parent
7884436679
commit
c61f2e931c
25
kasa/cli.py
25
kasa/cli.py
@ -1156,22 +1156,39 @@ async def shell(dev: Device):
|
||||
@cli.command(name="feature")
|
||||
@click.argument("name", required=False)
|
||||
@click.argument("value", required=False)
|
||||
@click.option("--child", required=False)
|
||||
@pass_dev
|
||||
async def feature(dev, name: str, value):
|
||||
async def feature(dev: Device, child: str, name: str, value):
|
||||
"""Access and modify features.
|
||||
|
||||
If no *name* is given, lists available features and their values.
|
||||
If only *name* is given, the value of named feature is returned.
|
||||
If both *name* and *value* are set, the described setting is changed.
|
||||
"""
|
||||
if child is not None:
|
||||
echo(f"Targeting child device {child}")
|
||||
dev = dev.get_child_device(child)
|
||||
if not name:
|
||||
|
||||
def _print_features(dev):
|
||||
for name, feat in dev.features.items():
|
||||
try:
|
||||
echo(f"\t{feat.name} ({name}): {feat.value}")
|
||||
except Exception as ex:
|
||||
echo(f"\t{feat.name} ({name}): [red]{ex}[/red]")
|
||||
|
||||
echo("[bold]== Features ==[/bold]")
|
||||
for name, feat in dev.features.items():
|
||||
echo(f"{feat.name} ({name}): {feat.value}")
|
||||
_print_features(dev)
|
||||
|
||||
if dev.children:
|
||||
for child_dev in dev.children:
|
||||
echo(f"[bold]== Child {child_dev.alias} ==")
|
||||
_print_features(child_dev)
|
||||
|
||||
return
|
||||
|
||||
if name not in dev.features:
|
||||
echo(f"No feature by name {name}")
|
||||
echo(f"No feature by name '{name}'")
|
||||
return
|
||||
|
||||
feat = dev.features[name]
|
||||
|
@ -573,7 +573,7 @@ def unsupported_device_info(request, mocker):
|
||||
yield discovery_data
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def dummy_protocol():
|
||||
"""Return a smart protocol instance with a mocking-ready dummy transport."""
|
||||
|
||||
|
@ -32,7 +32,14 @@ from kasa.cli import (
|
||||
from kasa.discover import Discover, DiscoveryResult
|
||||
from kasa.iot import IotDevice
|
||||
|
||||
from .conftest import device_iot, device_smart, handle_turn_on, new_discovery, turn_on
|
||||
from .conftest import (
|
||||
device_iot,
|
||||
device_smart,
|
||||
get_device_for_file,
|
||||
handle_turn_on,
|
||||
new_discovery,
|
||||
turn_on,
|
||||
)
|
||||
|
||||
|
||||
async def test_update_called_by_cli(dev, mocker):
|
||||
@ -684,3 +691,99 @@ async def test_errors(mocker):
|
||||
)
|
||||
assert res.exit_code == 2
|
||||
assert "Raised error:" not in res.output
|
||||
|
||||
|
||||
async def test_feature(mocker):
|
||||
"""Test feature command."""
|
||||
dummy_device = await get_device_for_file("P300(EU)_1.0_1.0.13.json", "SMART")
|
||||
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
|
||||
runner = CliRunner()
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
["--host", "127.0.0.123", "--debug", "feature"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert "LED" in res.output
|
||||
assert "== Child " in res.output # child listing
|
||||
|
||||
assert res.exit_code == 0
|
||||
|
||||
|
||||
async def test_feature_single(mocker):
|
||||
"""Test feature command returning single value."""
|
||||
dummy_device = await get_device_for_file("P300(EU)_1.0_1.0.13.json", "SMART")
|
||||
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
|
||||
runner = CliRunner()
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
["--host", "127.0.0.123", "--debug", "feature", "led"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert "LED" in res.output
|
||||
assert "== Features ==" not in res.output
|
||||
assert res.exit_code == 0
|
||||
|
||||
async def test_feature_missing(mocker):
|
||||
"""Test feature command returning single value."""
|
||||
dummy_device = await get_device_for_file("P300(EU)_1.0_1.0.13.json", "SMART")
|
||||
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
|
||||
runner = CliRunner()
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
["--host", "127.0.0.123", "--debug", "feature", "missing"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert "No feature by name 'missing'" in res.output
|
||||
assert "== Features ==" not in res.output
|
||||
assert res.exit_code == 0
|
||||
|
||||
async def test_feature_set(mocker):
|
||||
"""Test feature command's set value."""
|
||||
dummy_device = await get_device_for_file("P300(EU)_1.0_1.0.13.json", "SMART")
|
||||
led_setter = mocker.patch("kasa.smart.modules.ledmodule.LedModule.set_led")
|
||||
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
|
||||
|
||||
runner = CliRunner()
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
["--host", "127.0.0.123", "--debug", "feature", "led", "True"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
|
||||
led_setter.assert_called_with(True)
|
||||
assert "Setting led to True" in res.output
|
||||
assert res.exit_code == 0
|
||||
|
||||
|
||||
async def test_feature_set_child(mocker):
|
||||
"""Test feature command's set value."""
|
||||
dummy_device = await get_device_for_file("P300(EU)_1.0_1.0.13.json", "SMART")
|
||||
setter = mocker.patch("kasa.smart.smartdevice.SmartDevice.set_state")
|
||||
|
||||
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
|
||||
get_child_device = mocker.spy(dummy_device, "get_child_device")
|
||||
|
||||
child_id = "000000000000000000000000000000000000000001"
|
||||
|
||||
runner = CliRunner()
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"--host",
|
||||
"127.0.0.123",
|
||||
"--debug",
|
||||
"feature",
|
||||
"--child",
|
||||
child_id,
|
||||
"state",
|
||||
"False",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
|
||||
get_child_device.assert_called()
|
||||
setter.assert_called_with(False)
|
||||
|
||||
assert f"Targeting child device {child_id}"
|
||||
assert "Setting state to False" in res.output
|
||||
assert res.exit_code == 0
|
||||
|
Loading…
Reference in New Issue
Block a user