From b7a1b81181bf8e922b04f6c0992c2f057c55ebae Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Sat, 18 Dec 2021 10:15:57 -0500 Subject: [PATCH] device: push settings when device requests software reconfiguration --- lib/logitech_receiver/base.py | 4 ++-- lib/logitech_receiver/device.py | 2 +- lib/logitech_receiver/hidpp20.py | 2 +- lib/logitech_receiver/notifications.py | 6 +++--- lib/logitech_receiver/status.py | 21 +++++++++------------ lib/solaar/listener.py | 5 +++-- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/logitech_receiver/base.py b/lib/logitech_receiver/base.py index 56cb5335..84db044c 100644 --- a/lib/logitech_receiver/base.py +++ b/lib/logitech_receiver/base.py @@ -69,8 +69,8 @@ DEFAULT_TIMEOUT = 4 _RECEIVER_REQUEST_TIMEOUT = 0.9 # devices may reply a lot slower, as the call has to go wireless to them and come back _DEVICE_REQUEST_TIMEOUT = DEFAULT_TIMEOUT -# when pinging, be extra patient -_PING_TIMEOUT = DEFAULT_TIMEOUT * 2 +# when pinging, be extra patient (no longer) +_PING_TIMEOUT = DEFAULT_TIMEOUT # # Exceptions that may be raised by this API. diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py index ff155907..538e515c 100644 --- a/lib/logitech_receiver/device.py +++ b/lib/logitech_receiver/device.py @@ -134,7 +134,7 @@ class Device: else: self.path = info.path self.handle = _hid.open_path(self.path) - self.online = True + self.online = None # a direct connected device might not be online (as reported by user) self.product_id = info.product_id self.bluetooth = info.bus_id == 0x0005 self.descriptor = _descriptors.get_btid(self.product_id diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index 5ede93dd..ff57aa46 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -263,7 +263,7 @@ class FeaturesArray: reply = self.device.request(0x0000, _pack('!H', FEATURE.FEATURE_SET)) if reply is None: - self.supported = False + return False # device might not be active so don't assume unsupported else: fs_index = ord(reply[0:1]) if fs_index: diff --git a/lib/logitech_receiver/notifications.py b/lib/logitech_receiver/notifications.py index 5aa1a129..b9a4b581 100644 --- a/lib/logitech_receiver/notifications.py +++ b/lib/logitech_receiver/notifications.py @@ -174,6 +174,8 @@ def _process_device_notification(device, status, n): else: return _process_hidpp10_notification(device, status, n) + # These notifications are from the device itself, so it must be active + device.online = True # At this point, we need to know the device's protocol, otherwise it's # possible to not know how to handle it. assert device.protocol is not None @@ -371,9 +373,7 @@ def _process_feature_notification(device, status, n, feature): reason = 'powered on' if n.data[2] == 1 else None if n.data[1] == 1: # device is asking for software reconfiguration so need to change status alert = _ALERT.NONE - status.changed(active=True, alert=alert, reason=reason) - else: - _log.warn('%s: unknown WIRELESS %s', device, n) + status.changed(active=True, alert=alert, reason=reason, push=True) else: _log.warn('%s: unknown WIRELESS %s', device, n) diff --git a/lib/logitech_receiver/status.py b/lib/logitech_receiver/status.py index 63137caa..4b98ea6b 100644 --- a/lib/logitech_receiver/status.py +++ b/lib/logitech_receiver/status.py @@ -282,7 +282,7 @@ class DeviceStatus(dict): self[KEYS.BATTERY_VOLTAGE] = None self.changed() - def changed(self, active=None, alert=ALERT.NONE, reason=None, timestamp=None): + def changed(self, active=None, alert=ALERT.NONE, reason=None, push=False, timestamp=None): assert self._changed_callback d = self._device # assert d # may be invalid when processing the 'unpaired' notification @@ -299,22 +299,19 @@ class DeviceStatus(dict): if d.protocol < 2.0: self[KEYS.NOTIFICATION_FLAGS] = d.enable_connection_notifications() - # If we've been inactive for a long time, forget anything - # about the battery. (This is probably unnecessary.) - if self.updated > 0 and timestamp - self.updated > _LONG_SLEEP: - self[KEYS.BATTERY_LEVEL] = None - self[KEYS.BATTERY_STATUS] = None - self[KEYS.BATTERY_CHARGING] = None - self[KEYS.BATTERY_VOLTAGE] = None + # battery information may have changed so try to read it now + self.read_battery(timestamp) - # Devices lose configuration when they are turned off, - # make sure they're up-to-date. + # Push settings for new devices (was_active is None), + # when devices request software reconfiguration + # and when devices become active if they don't have wireless device status feature, + if was_active is None or push or not was_active and ( + not d.features or _hidpp20.FEATURE.WIRELESS_DEVICE_STATUS not in d.features + ): if _log.isEnabledFor(_INFO): _log.info('%s pushing device settings %s', d, d.settings) _settings.apply_all_settings(d) - # battery information may have changed so try to read it now - self.read_battery(timestamp) else: if was_active: battery = self.get(KEYS.BATTERY_LEVEL) diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index d716f86b..4574ea97 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -78,8 +78,9 @@ class ReceiverListener(_listener.EventsListener): assert status_changed_callback self.status_changed_callback = status_changed_callback _status.attach_to(receiver, self._status_changed) - if receiver.isDevice: # (wired) devices start as active - receiver.status.changed(True) + if receiver.isDevice: # ping (wired) devices to see if they are really online + if receiver.ping(): + receiver.status.changed(True, reason='initialization') def has_started(self): if _log.isEnabledFor(_INFO):