mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
143 lines
3.6 KiB
Python
143 lines
3.6 KiB
Python
"""Module for cli feature commands."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
|
|
import asyncclick as click
|
|
|
|
from kasa import (
|
|
Device,
|
|
Feature,
|
|
)
|
|
|
|
from .common import (
|
|
echo,
|
|
error,
|
|
pass_dev_or_child,
|
|
)
|
|
|
|
|
|
def _echo_features(
|
|
features: dict[str, Feature],
|
|
title: str,
|
|
category: Feature.Category | None = None,
|
|
verbose: bool = False,
|
|
indent: str = "\t",
|
|
) -> None:
|
|
"""Print out a listing of features and their values."""
|
|
if category is not None:
|
|
features = {
|
|
id_: feat for id_, feat in features.items() if feat.category == category
|
|
}
|
|
|
|
echo(f"{indent}[bold]{title}[/bold]")
|
|
for _, feat in features.items():
|
|
try:
|
|
echo(f"{indent}{feat}")
|
|
if verbose:
|
|
echo(f"{indent}\tType: {feat.type}")
|
|
echo(f"{indent}\tCategory: {feat.category}")
|
|
echo(f"{indent}\tIcon: {feat.icon}")
|
|
except Exception as ex:
|
|
echo(f"{indent}{feat.name} ({feat.id}): [red]got exception ({ex})[/red]")
|
|
|
|
|
|
def _echo_all_features(
|
|
features, *, verbose=False, title_prefix=None, indent=""
|
|
) -> None:
|
|
"""Print out all features by category."""
|
|
if title_prefix is not None:
|
|
echo(f"[bold]\n{indent}== {title_prefix} ==[/bold]")
|
|
echo()
|
|
_echo_features(
|
|
features,
|
|
title="== Primary features ==",
|
|
category=Feature.Category.Primary,
|
|
verbose=verbose,
|
|
indent=indent,
|
|
)
|
|
echo()
|
|
_echo_features(
|
|
features,
|
|
title="== Information ==",
|
|
category=Feature.Category.Info,
|
|
verbose=verbose,
|
|
indent=indent,
|
|
)
|
|
echo()
|
|
_echo_features(
|
|
features,
|
|
title="== Configuration ==",
|
|
category=Feature.Category.Config,
|
|
verbose=verbose,
|
|
indent=indent,
|
|
)
|
|
echo()
|
|
_echo_features(
|
|
features,
|
|
title="== Debug ==",
|
|
category=Feature.Category.Debug,
|
|
verbose=verbose,
|
|
indent=indent,
|
|
)
|
|
|
|
|
|
@click.command(name="feature")
|
|
@click.argument("name", required=False)
|
|
@click.argument("value", required=False)
|
|
@pass_dev_or_child
|
|
@click.pass_context
|
|
async def feature(
|
|
ctx: click.Context,
|
|
dev: Device,
|
|
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.
|
|
"""
|
|
verbose = ctx.parent.params.get("verbose", False) if ctx.parent else False
|
|
|
|
if not name:
|
|
_echo_all_features(dev.features, verbose=verbose, indent="")
|
|
|
|
if dev.children:
|
|
for child_dev in dev.children:
|
|
_echo_all_features(
|
|
child_dev.features,
|
|
verbose=verbose,
|
|
title_prefix=f"Child {child_dev.alias}",
|
|
indent="\t",
|
|
)
|
|
|
|
return
|
|
|
|
if name not in dev.features:
|
|
error(f"No feature by name '{name}'")
|
|
return
|
|
|
|
feat = dev.features[name]
|
|
|
|
if value is None and feat.type is Feature.Type.Action:
|
|
echo(f"Executing action {name}")
|
|
response = await dev.features[name].set_value(value)
|
|
echo(response)
|
|
return response
|
|
|
|
if value is None:
|
|
unit = f" {feat.unit}" if feat.unit else ""
|
|
echo(f"{feat.name} ({name}): {feat.value}{unit}")
|
|
return feat.value
|
|
|
|
value = ast.literal_eval(value)
|
|
echo(f"Changing {name} from {feat.value} to {value}")
|
|
response = await dev.features[name].set_value(value)
|
|
await dev.update()
|
|
echo(f"New state: {feat.value}")
|
|
|
|
return response
|