Fix discovery by alias for smart devices (#1260)

Fixes #1259
This commit is contained in:
Steven B. 2024-11-18 13:03:13 +00:00 committed by GitHub
parent 410c3d2623
commit fd5258c28b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 21 deletions

View File

@ -239,13 +239,48 @@ def _echo_discovery_info(discovery_info) -> None:
_conditional_echo("Decrypted", pf(dr.decrypted_data) if dr.decrypted_data else None)
async def find_host_from_alias(alias, target="255.255.255.255", timeout=1, attempts=3):
async def find_dev_from_alias(
alias: str,
credentials: Credentials | None,
target: str = "255.255.255.255",
timeout: int = 5,
attempts: int = 3,
) -> Device | None:
"""Discover a device identified by its alias."""
for _attempt in range(1, attempts):
found_devs = await Discover.discover(target=target, timeout=timeout)
for _ip, dev in found_devs.items():
if dev.alias.lower() == alias.lower():
host = dev.host
return host
found_event = asyncio.Event()
found_device = []
seen_hosts = set()
return None
async def on_discovered(dev: Device):
if dev.host in seen_hosts:
return
seen_hosts.add(dev.host)
try:
await dev.update()
except Exception as ex:
echo(f"Error querying device {dev.host}: {ex}")
return
finally:
await dev.protocol.close()
if not dev.alias:
echo(f"Skipping device {dev.host} with no alias")
return
if dev.alias.lower() == alias.lower():
found_device.append(dev)
found_event.set()
async def do_discover():
for _ in range(1, attempts):
await Discover.discover(
target=target,
timeout=timeout,
credentials=credentials,
on_discovered=on_discovered,
)
if found_event.is_set():
break
found_event.set()
asyncio.create_task(do_discover())
await found_event.wait()
return found_device[0] if found_device else None

View File

@ -275,18 +275,6 @@ async def cli(
if alias is not None and host is not None:
raise click.BadOptionUsage("alias", "Use either --alias or --host, not both.")
if alias is not None and host is None:
echo(f"Alias is given, using discovery to find host {alias}")
from .discover import find_host_from_alias
host = await find_host_from_alias(alias=alias, target=target)
if host:
echo(f"Found hostname is {host}")
else:
echo(f"No device with name {alias} found")
return
if bool(password) != bool(username):
raise click.BadOptionUsage(
"username", "Using authentication requires both --username and --password"
@ -299,7 +287,7 @@ async def cli(
else:
credentials = None
if host is None:
if host is None and alias is None:
if ctx.invoked_subcommand and ctx.invoked_subcommand != "discover":
error("Only discover is available without --host or --alias")
@ -309,6 +297,7 @@ async def cli(
return await ctx.invoke(discover)
device_updated = False
if type is not None and type not in {"smart", "camera"}:
from kasa.deviceconfig import DeviceConfig
@ -347,6 +336,19 @@ async def cli(
)
dev = await Device.connect(config=config)
device_updated = True
elif alias:
echo(f"Alias is given, using discovery to find host {alias}")
from .discover import find_dev_from_alias
dev = await find_dev_from_alias(
alias=alias, target=target, credentials=credentials
)
if not dev:
echo(f"No device with name {alias} found")
return
echo(f"Found hostname by alias: {dev.host}")
device_updated = True
else:
from .discover import discover