Exemplo n.º 1
0
 def do_discover(self) -> None:
     """Send number of discovery datagrams."""
     req = json.dumps(Discover.DISCOVERY_QUERY)
     _LOGGER.debug("[DISCOVERY] %s >> %s", self.target,
                   Discover.DISCOVERY_QUERY)
     encrypted_req = TPLinkSmartHomeProtocol.encrypt(req)
     for i in range(self.discovery_packets):
         self.transport.sendto(encrypted_req[4:],
                               self.target)  # type: ignore
Exemplo n.º 2
0
class _DiscoverProtocol(asyncio.DatagramProtocol):
    """Implementation of the discovery protocol handler.

    This is internal class, use :func:Discover.discover: instead.
    """

    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,
    ):
        self.transport = None
        self.tries = discovery_packets
        self.timeout = timeout
        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)

        self.do_discover()

    def do_discover(self) -> None:
        """Send number of discovery datagrams."""
        req = json.dumps(Discover.DISCOVERY_QUERY)
        _LOGGER.debug("[DISCOVERY] %s >> %s", self.target,
                      Discover.DISCOVERY_QUERY)
        encrypted_req = self.protocol.encrypt(req)
        for i in range(self.tries):
            self.transport.sendto(encrypted_req[4:],
                                  self.target)  # type: ignore

    def datagram_received(self, data, addr) -> None:
        """Handle discovery responses."""
        ip, port = addr
        if ip in self.discovered_devices:
            return

        info = json.loads(self.protocol.decrypt(data))
        _LOGGER.debug("[DISCOVERY] %s << %s", ip, info)

        device_class = Discover._get_device_class(info)
        device = device_class(ip)

        self.discovered_devices[ip] = device
        self.discovered_devices_raw[ip] = info

        if device_class is not None:
            if self.on_discovered is not None:
                asyncio.ensure_future(self.on_discovered(device))
        else:
            _LOGGER.error("Received invalid response: %s", info)

    def error_received(self, ex):
        """Handle asyncio.Protocol errors."""
        _LOGGER.error("Got error: %s", ex)

    def connection_lost(self, ex):
        """NOP implementation of connection lost."""