コード例 #1
0
    async def discover_single(host: str) -> SmartDevice:
        """Discover a single device by the given IP address.

        :param host: Hostname of device to query
        :rtype: SmartDevice
        :return: Object for querying/controlling found device.
        """
        protocol = TPLinkSmartHomeProtocol(host)

        info = await protocol.query(Discover.DISCOVERY_QUERY)

        device_class = Discover._get_device_class(info)
        dev = device_class(host)
        await dev.update()

        return dev
コード例 #2
0
    def datagram_received(self, data, addr) -> None:
        """Handle discovery responses."""
        ip, port = addr
        if ip in self.discovered_devices:
            return

        if port == 9999:
            info = json.loads(TPLinkSmartHomeProtocol.decrypt(data))
            device_class = Discover._get_device_class(info)
            device = device_class(ip)
        else:
            info = json.loads(data[16:])
            device_class = Discover._get_new_device_class(info)
            owner = Discover._get_new_owner(info)
            if owner is not None:
                owner_bin = bytes.fromhex(owner)

            _LOGGER.debug(
                "[DISCOVERY] Device owner is %s, empty owner is %s",
                owner_bin,
                self.emptyUser,
            )
            if owner is None or owner == "" or owner_bin == self.emptyUser:
                _LOGGER.debug("[DISCOVERY] Device %s has no owner", ip)
                device = device_class(ip, Auth())
            elif (self.authentication is not None
                  and owner_bin == self.authentication.owner()):
                _LOGGER.debug("[DISCOVERY] Device %s has authenticated owner",
                              ip)
                device = device_class(ip, self.authentication)
            else:
                _LOGGER.debug("[DISCOVERY] Found %s with unknown owner %s", ip,
                              owner)
                return

        _LOGGER.debug("[DISCOVERY] %s << %s", ip, info)

        asyncio.ensure_future(device.update())

        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)
コード例 #3
0
    async def discover_single(host: str) -> SmartDevice:
        """Discover a single device by the given IP address.

        :param host: Hostname of device to query
        :rtype: SmartDevice
        :return: Object for querying/controlling found device.
        """
        protocol = TPLinkSmartHomeProtocol()

        info = await protocol.query(host, Discover.DISCOVERY_QUERY)

        device_class = Discover._get_device_class(info)
        if device_class is not None:
            return device_class(host)

        raise SmartDeviceException("Unable to discover device, received: %s" %
                                   info)
コード例 #4
0
    def __init__(self, host: str, *, cache_ttl: int = 3) -> None:
        """Create a new SmartDevice instance.

        :param str host: host name or ip address on which the device listens
        :param child_id: optional child ID for context in a parent device
        """
        self.host = host

        self.protocol = TPLinkSmartHomeProtocol()
        self.emeter_type = "emeter"
        self.cache_ttl = timedelta(seconds=cache_ttl)
        _LOGGER.debug("Initializing %s with cache ttl %s", self.host,
                      self.cache_ttl)
        self.cache = defaultdict(
            lambda: defaultdict(lambda: None))  # type: ignore
        self._device_type = DeviceType.Unknown
        self._sys_info: Optional[Dict] = None
コード例 #5
0
def read_payloads_from_file(file):
    """Read the given pcap file and yield json payloads."""
    pcap = dpkt.pcap.Reader(file)
    for ts, pkt in pcap:
        eth = Ethernet(pkt)
        if eth.type != ETH_TYPE_IP:
            continue

        ip = eth.ip
        if ip.p == 6:
            transport = ip.tcp
        elif ip == 17:
            transport = ip.udp
        else:
            continue

        if transport.sport != 9999 and transport.dport != 9999:
            continue

        data = transport.data

        try:
            decrypted = TPLinkSmartHomeProtocol.decrypt(data[4:])
        except Exception as ex:
            click.echo(
                click.style(f"Unable to decrypt the data, ignoring: {ex}", fg="red")
            )
            continue

        try:
            json_payload = json.loads(decrypted)
        except Exception as ex:
            click.echo(
                click.style(f"Unable to parse payload, ignoring: {ex}", fg="red")
            )
            continue

        if not json_payload:  # ignore empty payloads
            click.echo(click.style("Got empty payload, ignoring", fg="red"))
            continue

        yield json_payload
コード例 #6
0
ファイル: discover.py プロジェクト: dlee1j1/python-kasa
    def datagram_received(self, data, addr) -> None:
        """Handle discovery responses."""
        ip, port = addr
        if ip in self.discovered_devices:
            return

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

        try:
            device = Discover._create_device_from_discovery_info(ip, info)
        except SmartDeviceException as ex:
            _LOGGER.debug("Unable to find device type from %s: %s", info, ex)
            return

        self.discovered_devices[ip] = device

        if device 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)
コード例 #7
0
    async def discover_single(host: str, complete: bool) -> SmartDevice:
        """Discover a single device by the given IP address.

        :param host: Hostname of device to query
        :param complete: Whether to discover only with get_sysinfo or all options
        :rtype: SmartDevice
        :return: Object for querying/controlling found device.
        """
        protocol = TPLinkSmartHomeProtocol()

        if complete:
            info = await protocol.query(host,
                                        Discover.COMPLETE_DISCOVERY_QUERY)
        else:
            info = await protocol.query(host, Discover.DISCOVERY_QUERY)

        device_class = Discover._get_device_class(info)
        if device_class is not None:
            dev = device_class(host)
            await dev.update()
            return dev

        raise SmartDeviceException("Unable to discover device, received: %s" %
                                   info)
コード例 #8
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."""