device: add present flag, unset when internal error occurs, set when notification appears

This commit is contained in:
Peter F. Patel-Schneider 2025-04-12 09:36:13 -04:00
parent 217b9360e6
commit abea1c4341
4 changed files with 15 additions and 5 deletions

View File

@ -147,6 +147,7 @@ class Device:
self.battery_info = None
self.link_encrypted = None
self._active = None # lags self.online - is used to help determine when to setup devices
self.present = True # used for devices that are integral with their receiver but that separately be disconnected
self._feature_settings_checked = False
self._gestures_lock = threading.Lock()
@ -432,6 +433,8 @@ class Device:
def changed(self, active=None, alert=Alert.NONE, reason=None, push=False):
"""The status of the device had changed, so invoke the status callback.
Also push notifications and settings to the device when necessary."""
if logger.isEnabledFor(logging.DEBUG):
logger.debug("device %d changing: active=%s %s present=%s", self.number, active, self._active, self.present)
if active is not None:
self.online = active
was_active, self._active = self._active, active
@ -533,7 +536,8 @@ class Device:
return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply)
def ping(self):
"""Checks if the device is online, returns True of False"""
"""Checks if the device is online and present, returns True of False.
Some devices are integral with their receiver but may not be present even if the receiver responds to ping."""
long = self.hidpp_long is True or (
self.hidpp_long is None and (self.bluetooth or self._protocol is not None and self._protocol >= 2.0)
)
@ -542,9 +546,11 @@ class Device:
protocol = self.low_level.ping(handle, self.number, long_message=long)
except exceptions.NoReceiver: # if ping fails, device is offline
protocol = None
self.online = protocol is not None
self.online = protocol is not None and self.present
if protocol:
self._protocol = protocol
if logger.isEnabledFor(logging.DEBUG):
logger.debug("pinged %s: online %s protocol %s present %s", self.number, self.online, protocol, self.present)
return self.online
def notify_devices(self): # no need to notify, as there are none

View File

@ -238,6 +238,7 @@ def _process_hidpp10_notification(device: Device, notification: HIDPPNotificatio
def _process_feature_notification(device: Device, notification: HIDPPNotification):
old_present, device.present = device.present, True # the device is generating a feature notification so it must be present
try:
feature = device.features.get_feature(notification.sub_id)
except IndexError:
@ -277,10 +278,11 @@ def _process_feature_notification(device: Device, notification: HIDPPNotificatio
elif feature == SupportedFeature.ADC_MEASUREMENT:
if notification.address == 0x00:
result = hidpp20.decipher_adc_measurement(notification.data)
if result: # this may be the only message signalling that the device has become active
if result: # if good data and the device was not present then a push is needed
device.set_battery_info(result[1])
device.changed(active=True, alert=Alert.ALL, reason=_("ADC measurement notification"))
device.changed(active=True, alert=Alert.ALL, reason=_("ADC measurement notification"), push=not old_present)
else: # this feature is also used to signal device becoming inactive
device.present = False # exception to device presence
device.changed(active=False)
else:
logger.warning("%s: unknown ADC MEASUREMENT %s", device, notification)

View File

@ -1936,8 +1936,9 @@ def check_feature_settings(device, already_known) -> bool:
isinstance(err, exceptions.FeatureCallError)
and err.error == hidpp20_constants.ErrorCode.LOGITECH_ERROR
):
logger.warning(f"HID++ internal error when checking feature {sclass.name}: make device offline")
logger.warning(f"HID++ internal error checking feature {sclass.name}: make device not present")
device.online = False
device.present = False
return False
else:
logger.warning(f"ignore feature {sclass.name} because of error {err}")

View File

@ -389,6 +389,7 @@ class Device:
sliding = profiles = _backlight = _keys = _remap_keys = _led_effects = _gestures = None
_gestures_lock = threading.Lock()
number = "d1"
present = True
read_register = device.Device.read_register
write_register = device.Device.write_register