# Discover devices

Note

The library is fully async and methods that perform IO need to be run inside an async coroutine. Code examples assume you are following them inside `asyncio REPL`:

        $ python -m asyncio

Or the code is running inside an async function:

    import asyncio
    from kasa import Discover

    async def main():
        dev = await Discover.discover_single("127.0.0.1",username="un@example.com",password="pw")
        await dev.turn_on()
        await dev.update()

    if __name__ == "__main__":
        asyncio.run(main())

All of your code needs to run inside the same event loop so only call `asyncio.run` once.

The main entry point for the API is `discover()` and `discover_single()` which return Device objects. Most newer devices require your TP-Link cloud username and password, but this can be omitted for older devices.

Discover TPLink Smart Home devices.

The main entry point for this library is `Discover.discover()`, which returns a dictionary of the found devices. The key is the IP address of the device and the value contains ready-to-use, SmartDevice-derived device object.

`discover_single()` can be used to initialize a single device given its IP address. If the `DeviceConfig` of the device is already known, you can initialize the corresponding device class directly without discovery.

The protocol uses UDP broadcast datagrams on port 9999 and 20002 for discovery. Legacy devices support discovery on port 9999 and newer devices on 20002.

Newer devices that respond on port 20002 will most likely require TP-Link cloud credentials to be passed if queries or updates are to be performed on the returned devices.

Discovery returns a dict of {ip: discovered devices}:

    >>> from kasa import Discover, Credentials
    >>>
    >>> found_devices = await Discover.discover()
    >>> [dev.model for dev in found_devices.values()]
    ['KP303', 'HS110', 'L530E', 'KL430', 'HS220', 'H200']

You can pass username and password for devices requiring authentication

    >>> devices = await Discover.discover(
    >>>     username="user@example.com",
    >>>     password="great_password",
    >>> )
    >>> print(len(devices))
    6

You can also pass a `kasa.Credentials`

    >>> creds = Credentials("user@example.com", "great_password")
    >>> devices = await Discover.discover(credentials=creds)
    >>> print(len(devices))
    6

Discovery can also be targeted to a specific broadcast address instead of the default 255.255.255.255:

    >>> found_devices = await Discover.discover(target="127.0.0.255", credentials=creds)
    >>> print(len(found_devices))
    6

Basic information is available on the device from the discovery broadcast response but it is important to call device.update() after discovery if you want to access all the attributes without getting errors or None.

    >>> dev = found_devices["127.0.0.3"]
    >>> dev.alias
    None
    >>> await dev.update()
    >>> dev.alias
    'Living Room Bulb'

It is also possible to pass a coroutine to be executed for each found device:

    >>> async def print_dev_info(dev):
    >>>     await dev.update()
    >>>     print(f"Discovered {dev.alias} (model: {dev.model})")
    >>>
    >>> devices = await Discover.discover(on_discovered=print_dev_info, credentials=creds)
    Discovered Bedroom Power Strip (model: KP303)
    Discovered Bedroom Lamp Plug (model: HS110)
    Discovered Living Room Bulb (model: L530)
    Discovered Bedroom Lightstrip (model: KL430)
    Discovered Living Room Dimmer Switch (model: HS220)
    Discovered Tapo Hub (model: H200)

Discovering a single device returns a kasa.Device object.

    >>> device = await Discover.discover_single("127.0.0.1", credentials=creds)
    >>> device.model
    'KP303'