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.battery_info = None
self.link_encrypted = None self.link_encrypted = None
self._active = None # lags self.online - is used to help determine when to setup devices 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._feature_settings_checked = False
self._gestures_lock = threading.Lock() self._gestures_lock = threading.Lock()
@ -432,6 +433,8 @@ class Device:
def changed(self, active=None, alert=Alert.NONE, reason=None, push=False): def changed(self, active=None, alert=Alert.NONE, reason=None, push=False):
"""The status of the device had changed, so invoke the status callback. """The status of the device had changed, so invoke the status callback.
Also push notifications and settings to the device when necessary.""" 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: if active is not None:
self.online = active self.online = active
was_active, self._active = self._active, 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) return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply)
def ping(self): 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 ( 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) 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) protocol = self.low_level.ping(handle, self.number, long_message=long)
except exceptions.NoReceiver: # if ping fails, device is offline except exceptions.NoReceiver: # if ping fails, device is offline
protocol = None protocol = None
self.online = protocol is not None self.online = protocol is not None and self.present
if protocol: if protocol:
self._protocol = 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 return self.online
def notify_devices(self): # no need to notify, as there are none 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): 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: try:
feature = device.features.get_feature(notification.sub_id) feature = device.features.get_feature(notification.sub_id)
except IndexError: except IndexError:
@ -277,10 +278,11 @@ def _process_feature_notification(device: Device, notification: HIDPPNotificatio
elif feature == SupportedFeature.ADC_MEASUREMENT: elif feature == SupportedFeature.ADC_MEASUREMENT:
if notification.address == 0x00: if notification.address == 0x00:
result = hidpp20.decipher_adc_measurement(notification.data) 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.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 else: # this feature is also used to signal device becoming inactive
device.present = False # exception to device presence
device.changed(active=False) device.changed(active=False)
else: else:
logger.warning("%s: unknown ADC MEASUREMENT %s", device, notification) 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) isinstance(err, exceptions.FeatureCallError)
and err.error == hidpp20_constants.ErrorCode.LOGITECH_ERROR 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.online = False
device.present = False
return False return False
else: else:
logger.warning(f"ignore feature {sclass.name} because of error {err}") 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 sliding = profiles = _backlight = _keys = _remap_keys = _led_effects = _gestures = None
_gestures_lock = threading.Lock() _gestures_lock = threading.Lock()
number = "d1" number = "d1"
present = True
read_register = device.Device.read_register read_register = device.Device.read_register
write_register = device.Device.write_register write_register = device.Device.write_register