Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Discover.discover() add selecting network interface [pull request] #78

Copy link
Copy link
@dmitryelj

Description

@dmitryelj
Issue body actions

Hi, thanks for the cool product.

On my dd-wrt router, the broadcast socket does not work without specifying the network interface name. Please add to the code possibility to specify the network interface name during the discovery process.

I am too lazy to create a full pull-request, so, just a code:

async def discover(*, target="255.255.255.255",
                      on_discovered=None,
                      timeout=5,
                      discovery_packets=3,
                      return_raw=False,
                      interface=None) -> Mapping[str, Union[SmartDevice, Dict]]:
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        lambda: __DiscoverProtocol(
            target=target,
            on_discovered=on_discovered,
            timeout=timeout,
            discovery_packets=discovery_packets,
            interface=interface
        ),
        local_addr=("0.0.0.0", 0),
    )
    protocol = cast(__DiscoverProtocol, protocol)

    try:
        await asyncio.sleep(5)
    finally:
        transport.close()

    if return_raw:
        return protocol.discovered_devices_raw

    return protocol.discovered_devices


class _DiscoverProtocol(asyncio.DatagramProtocol):
    discovered_devices: Dict[str, SmartDevice]
    discovered_devices_raw: Dict[str, Dict]

    def __init__(
        self,
        *,
        on_discovered: OnDiscoveredCallable = None,
        target: str = "255.255.255.255",
        timeout: int = 5,
        discovery_packets: int = 3,
        interface: bytes = b""
    ):
        self.transport = None
        self.tries = discovery_packets
        self.timeout = timeout
        self.interface = interface
        self.on_discovered = on_discovered
        self.protocol = TPLinkSmartHomeProtocol()
        self.target = (target, Discover.DISCOVERY_PORT)
        self.discovered_devices = {}
        self.discovered_devices_raw = {}

    def connection_made(self, transport) -> None:
        """Set socket options for broadcasting."""
        self.transport = transport
        sock = transport.get_extra_info("socket")
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if self.interface is not None and len(self.interface) > 0:
            sock.setsockopt(socket.SOL_SOCKET, 25, self.interface)

        self.do_discover()

Usage on my dd-wrt router:

devices = asyncio.run(Discover.discover(interface=b"br0"))
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.