8000 Discover.discover() add selecting network interface [pull request] · Issue #78 · python-kasa/python-kasa · GitHub
[go: up one dir, main page]

Skip to content
8000

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dmitryelj opened this issue Jun 24, 2020 · 2 comments
Closed

Comments

@dmitryelj
Copy link
Contributor
dmitryelj commented Jun 24, 2020

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"))
@kirichkov
Copy link
Contributor

You'd need to submit at least a patch. Just looking at the code I wouldn't even know which file I have to add it to! Furthermore a test that can be part out of the automated testing would be a good idea, since someone could break it by mistake at any point in the future.

Furthermore, the code you have won't work properly on a dd-wrt router, because you haven't made interface a required argument on that platform, while I understand from your explanation it must be!

@dmitryelj
Copy link
Contributor Author

Pull request created

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
0