mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-09 20:24:02 +00:00
Add try_connect_all to allow initialisation without udp broadcast (#1171)
- Try all valid combinations of protocol/transport/device class and attempt to connect. - Add cli command `discover config` to return the connection options after connecting via `try_connect_all`. - The cli command does not return the actual device for processing as this is not a recommended way to regularly connect to devices.
This commit is contained in:
@@ -1158,3 +1158,78 @@ async def test_cli_child_commands(
|
||||
assert res.exit_code == 0
|
||||
parent_update_spy.assert_called_once()
|
||||
assert dev.children[0].update == child_update_method
|
||||
|
||||
|
||||
async def test_discover_config(dev: Device, mocker, runner):
|
||||
"""Test that device config is returned."""
|
||||
host = "127.0.0.1"
|
||||
mocker.patch("kasa.discover.Discover.try_connect_all", return_value=dev)
|
||||
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"--username",
|
||||
"foo",
|
||||
"--password",
|
||||
"bar",
|
||||
"--host",
|
||||
host,
|
||||
"discover",
|
||||
"config",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert res.exit_code == 0
|
||||
cparam = dev.config.connection_type
|
||||
expected = f"--device-family {cparam.device_family.value} --encrypt-type {cparam.encryption_type.value} {'--https' if cparam.https else '--no-https'}"
|
||||
assert expected in res.output
|
||||
|
||||
|
||||
async def test_discover_config_invalid(mocker, runner):
|
||||
"""Test the device config command with invalids."""
|
||||
host = "127.0.0.1"
|
||||
mocker.patch("kasa.discover.Discover.try_connect_all", return_value=None)
|
||||
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"--username",
|
||||
"foo",
|
||||
"--password",
|
||||
"bar",
|
||||
"--host",
|
||||
host,
|
||||
"discover",
|
||||
"config",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert res.exit_code == 1
|
||||
assert f"Unable to connect to {host}" in res.output
|
||||
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
["--username", "foo", "--password", "bar", "discover", "config"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert res.exit_code == 1
|
||||
assert "--host option must be supplied to discover config" in res.output
|
||||
|
||||
res = await runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"--username",
|
||||
"foo",
|
||||
"--password",
|
||||
"bar",
|
||||
"--host",
|
||||
host,
|
||||
"--target",
|
||||
"127.0.0.2",
|
||||
"discover",
|
||||
"config",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert res.exit_code == 1
|
||||
assert "--target is not a valid option for single host discovery" in res.output
|
||||
|
@@ -20,9 +20,15 @@ from kasa import (
|
||||
Device,
|
||||
DeviceType,
|
||||
Discover,
|
||||
IotProtocol,
|
||||
KasaException,
|
||||
)
|
||||
from kasa.aestransport import AesEncyptionSession
|
||||
from kasa.device_factory import (
|
||||
get_device_class_from_family,
|
||||
get_device_class_from_sys_info,
|
||||
get_protocol,
|
||||
)
|
||||
from kasa.deviceconfig import (
|
||||
DeviceConfig,
|
||||
DeviceConnectionParameters,
|
||||
@@ -35,7 +41,7 @@ from kasa.discover import (
|
||||
)
|
||||
from kasa.exceptions import AuthenticationError, UnsupportedDeviceError
|
||||
from kasa.iot import IotDevice
|
||||
from kasa.xortransport import XorEncryption
|
||||
from kasa.xortransport import XorEncryption, XorTransport
|
||||
|
||||
from .conftest import (
|
||||
bulb_iot,
|
||||
@@ -647,3 +653,51 @@ async def test_discovery_decryption():
|
||||
dr = DiscoveryResult(**info)
|
||||
Discover._decrypt_discovery_data(dr)
|
||||
assert dr.decrypted_data == data_dict
|
||||
|
||||
|
||||
async def test_discover_try_connect_all(discovery_mock, mocker):
|
||||
"""Test that device update is called on main."""
|
||||
if "result" in discovery_mock.discovery_data:
|
||||
dev_class = get_device_class_from_family(discovery_mock.device_type)
|
||||
cparams = DeviceConnectionParameters.from_values(
|
||||
discovery_mock.device_type,
|
||||
discovery_mock.encrypt_type,
|
||||
discovery_mock.login_version,
|
||||
False,
|
||||
)
|
||||
protocol = get_protocol(
|
||||
DeviceConfig(discovery_mock.ip, connection_type=cparams)
|
||||
)
|
||||
protocol_class = protocol.__class__
|
||||
transport_class = protocol._transport.__class__
|
||||
else:
|
||||
dev_class = get_device_class_from_sys_info(discovery_mock.discovery_data)
|
||||
protocol_class = IotProtocol
|
||||
transport_class = XorTransport
|
||||
|
||||
async def _query(self, *args, **kwargs):
|
||||
if (
|
||||
self.__class__ is protocol_class
|
||||
and self._transport.__class__ is transport_class
|
||||
):
|
||||
return discovery_mock.query_data
|
||||
raise KasaException()
|
||||
|
||||
async def _update(self, *args, **kwargs):
|
||||
if (
|
||||
self.protocol.__class__ is protocol_class
|
||||
and self.protocol._transport.__class__ is transport_class
|
||||
):
|
||||
return
|
||||
raise KasaException()
|
||||
|
||||
mocker.patch("kasa.IotProtocol.query", new=_query)
|
||||
mocker.patch("kasa.SmartProtocol.query", new=_query)
|
||||
mocker.patch.object(dev_class, "update", new=_update)
|
||||
|
||||
dev = await Discover.try_connect_all(discovery_mock.ip)
|
||||
|
||||
assert dev
|
||||
assert isinstance(dev, dev_class)
|
||||
assert isinstance(dev.protocol, protocol_class)
|
||||
assert isinstance(dev.protocol._transport, transport_class)
|
||||
|
Reference in New Issue
Block a user