From 2c1fbb0547cde7b3f7ea46396379e2a56fc55bd6 Mon Sep 17 00:00:00 2001 From: Brian May Date: Thu, 24 Mar 2016 12:54:23 +1100 Subject: [PATCH 1/2] Don't error if device switched off Previously get_device or the related functions would retrieve a list of devices that it contacted in the last x seconds. Then we would contact each light in turn to try and apply some sort of filtering. This would error out if the light had been switched off. This patch attempts to contact each light and skips it if it cannot be contacted. This also caches the label of the light so we can display the repr string even if the light is offline. Closes #6 --- lifx/client.py | 26 ++++++++++++++++++++------ lifx/device.py | 8 ++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lifx/client.py b/lifx/client.py index dc397a8..8360b88 100644 --- a/lifx/client.py +++ b/lifx/client.py @@ -169,11 +169,12 @@ def poll_devices(self): for device in filter(lambda x:x.seen_ago > poll_delta, self._devices.values()): device.send_poll_packet() - def get_devices(self, max_seen=None): + def get_devices(self, max_seen=None, refine=None): """ Get a list of all responding devices. :param max_seen: The number of seconds since the device was last seen, defaults to 3 times the devicepoll interval. + :param refine: Filter list of devices using this function """ if max_seen is None: max_seen = self._devicepolltime * MISSED_POLLS @@ -182,6 +183,19 @@ def get_devices(self, max_seen=None): devices = filter(lambda x:x.seen_ago < seen_delta, self._devices.values()) + if refine is None: + refine = lambda x: True + + alive = [] + for d in devices: + try: + d.label + if refine(d): + alive.append(d) + except device.DeviceTimeoutError: + pass + devices = alive + # Sort by device id to ensure consistent ordering return sorted(devices, key=lambda k:k.id) @@ -227,7 +241,7 @@ def by_label(self, label): :param by_label: The label we are looking for. :returns: list -- The devices that match criteria """ - return filter(lambda d: d.label == label, self.get_devices()) + return self.get_devices(refine=lambda d: d.label == label) def by_id(self, id): """ @@ -236,7 +250,7 @@ def by_id(self, id): :param id: The device id :returns: Device -- The device with the matching id. """ - return filter(lambda d: d.id == id, self.get_devices())[0] + return self.get_devices(refine=lambda d: d.id == id) def by_power(self, power): """ @@ -245,7 +259,7 @@ def by_power(self, power): :param power: True returns all devices that are on, False returns ones that are off. :returns: list -- The devices that match criteria """ - return filter(lambda d: d.power == power, self.get_devices()) + return self.get_devices(refine=lambda d: d.power == power) def by_group_id(self, group_id): """ @@ -254,7 +268,7 @@ def by_group_id(self, group_id): :param group_id: The group id to match on each light. :returns: list -- The devices that match criteria """ - return filter(lambda d: d.group_id == group_id, self.get_devices()) + return self.get_devices(refine=lambda d: d.group_id == group_id) def by_location_id(self, location_id): """ @@ -263,7 +277,7 @@ def by_location_id(self, location_id): :param group_id: The group id to match on each light. :returns: list -- The devices that match criteria """ - return filter(lambda d: d.location_id == location_id, self.get_devices()) + return self.get_devices(refine=lambda d: d.location_id == location_id) def __getitem__(self, key): return self.get_devices()[key] diff --git a/lifx/device.py b/lifx/device.py index 230f978..9a214cb 100644 --- a/lifx/device.py +++ b/lifx/device.py @@ -27,6 +27,7 @@ def __init__(self, device_id, host, client): # Our Device self._device_id = device_id self._host = host + self._label = None # Services self._services = {} @@ -257,13 +258,16 @@ def label(self): """ The label for the device, setting this will change the label on the device. """ - response = self._block_for_response(pkt_type=protocol.TYPE_GETLABEL) - return protocol.bytes_to_label(response.label) + if self._label is None: + response = self._block_for_response(pkt_type=protocol.TYPE_GETLABEL) + self._label = protocol.bytes_to_label(response.label) + return self._label @label.setter def label(self, label): newlabel = bytearray(label.encode('utf-8')[0:protocol.LABEL_MAXLEN]) + self._label = newlabel return self._block_for_ack(newlabel, pkt_type=protocol.TYPE_SETLABEL) def fade_power(self, power, duration=DEFAULT_DURATION): From 61fbfa04387b169efccd658b4a62288afe6c9875 Mon Sep 17 00:00:00 2001 From: Brian May Date: Sun, 8 Jan 2017 12:34:51 +1100 Subject: [PATCH 2/2] Update IP address for light If IP Address has changed for the light, make sure we use the new one. --- lifx/device.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lifx/device.py b/lifx/device.py index 9a214cb..a580571 100644 --- a/lifx/device.py +++ b/lifx/device.py @@ -52,6 +52,7 @@ def _seq(self): def _packethandler(self, host, port, packet): self._seen() + self._host = host # If it was a service packet if packet.protocol_header.pkt_type == protocol.TYPE_STATESERVICE: