Skip to content

Commit

Permalink
device: move battery constants common to HID++ 1.0 and 2.0 to common
Browse files Browse the repository at this point in the history
  • Loading branch information
pfps committed Feb 21, 2024
1 parent 7bcbef5 commit 320d880
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 41 deletions.
15 changes: 15 additions & 0 deletions lib/logitech_receiver/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,4 +550,19 @@ def __getattr__(self, k):

BATTERY_APPROX = NamedInts(empty=0, critical=5, low=20, good=50, full=90)

BATTERY_STATUS = NamedInts(
discharging=0x00,
recharging=0x01,
almost_full=0x02,
full=0x03,
slow_recharge=0x04,
invalid_battery=0x05,
thermal_error=0x06,
)


def BATTERY_OK(status):
return status not in (BATTERY_STATUS.invalid_battery, BATTERY_STATUS.thermal_error)


del namedtuple
15 changes: 8 additions & 7 deletions lib/logitech_receiver/hidpp10.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
import logging

from .common import BATTERY_APPROX as _BATTERY_APPROX
from .common import BATTERY_STATUS as _BATTERY_STATUS
from .common import FirmwareInfo as _FirmwareInfo
from .common import bytes2int as _bytes2int
from .common import int2bytes as _int2bytes
from .common import strhex as _strhex
from .hidpp10_constants import REGISTERS
from .hidpp20_constants import BATTERY_STATUS, FIRMWARE_KIND
from .hidpp20_constants import FIRMWARE_KIND

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -83,11 +84,11 @@ def parse_battery_status(register, reply):
charge = ord(reply[:1])
status_byte = ord(reply[2:3]) & 0xF0
status_text = (
BATTERY_STATUS.discharging
_BATTERY_STATUS.discharging
if status_byte == 0x30
else BATTERY_STATUS.recharging
else _BATTERY_STATUS.recharging
if status_byte == 0x50
else BATTERY_STATUS.full
else _BATTERY_STATUS.full
if status_byte == 0x90
else None
)
Expand All @@ -110,11 +111,11 @@ def parse_battery_status(register, reply):

charging_byte = ord(reply[1:2])
if charging_byte == 0x00:
status_text = BATTERY_STATUS.discharging
status_text = _BATTERY_STATUS.discharging
elif charging_byte & 0x21 == 0x21:
status_text = BATTERY_STATUS.recharging
status_text = _BATTERY_STATUS.recharging
elif charging_byte & 0x22 == 0x22:
status_text = BATTERY_STATUS.full
status_text = _BATTERY_STATUS.full
else:
logger.warning("could not parse 0x07 battery status: %02X (level %02X)", charging_byte, status_byte)
status_text = None
Expand Down
18 changes: 9 additions & 9 deletions lib/logitech_receiver/hidpp20.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@
from . import exceptions, special_keys
from . import hidpp10_constants as _hidpp10_constants
from .common import BATTERY_APPROX as _BATTERY_APPROX
from .common import BATTERY_STATUS as _BATTERY_STATUS
from .common import FirmwareInfo as _FirmwareInfo
from .common import NamedInt as _NamedInt
from .common import NamedInts as _NamedInts
from .common import UnsortedNamedInts as _UnsortedNamedInts
from .common import bytes2int as _bytes2int
from .common import crc16 as _crc16
from .common import int2bytes as _int2bytes
from .hidpp20_constants import BATTERY_STATUS, CHARGE_LEVEL, CHARGE_STATUS, CHARGE_TYPE, DEVICE_KIND, ERROR, FEATURE, FIRMWARE_KIND, GESTURE
from .hidpp20_constants import CHARGE_LEVEL, CHARGE_STATUS, CHARGE_TYPE, DEVICE_KIND, ERROR, FEATURE, FIRMWARE_KIND, GESTURE
from .i18n import _

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -1400,7 +1401,6 @@ def get_ids(device):


KIND_MAP = {kind: _hidpp10_constants.DEVICE_KIND[str(kind)] for kind in DEVICE_KIND}
print(KIND_MAP)


def get_kind(device):
Expand Down Expand Up @@ -1472,7 +1472,7 @@ def get_battery_status(device):
def decipher_battery_status(report):
discharge, next, status = _unpack("!BBB", report[:3])
discharge = None if discharge == 0 else discharge
status = BATTERY_STATUS[status]
status = _BATTERY_STATUS[status]
if logger.isEnabledFor(logging.DEBUG):
logger.debug("battery status %s%% charged, next %s%%, status %s", discharge, next, status)
return FEATURE.BATTERY_STATUS, discharge, next, status, None
Expand All @@ -1486,7 +1486,7 @@ def get_battery_unified(device):

def decipher_battery_unified(report):
discharge, level, status, _ignore = _unpack("!BBBB", report[:4])
status = BATTERY_STATUS[status]
status = _BATTERY_STATUS[status]
if logger.isEnabledFor(logging.DEBUG):
logger.debug("battery unified %s%% charged, level %s, charging %s", discharge, level, status)
level = (
Expand Down Expand Up @@ -1530,23 +1530,23 @@ def get_battery_voltage(device):

def decipher_battery_voltage(report):
voltage, flags = _unpack(">HB", report[:3])
status = BATTERY_STATUS.discharging
status = _BATTERY_STATUS.discharging
charge_sts = ERROR.unknown
charge_lvl = CHARGE_LEVEL.average
charge_type = CHARGE_TYPE.standard
if flags & (1 << 7):
status = BATTERY_STATUS.recharging
status = _BATTERY_STATUS.recharging
charge_sts = CHARGE_STATUS[flags & 0x03]
if charge_sts is None:
charge_sts = ERROR.unknown
elif charge_sts == CHARGE_STATUS.full:
charge_lvl = CHARGE_LEVEL.full
status = BATTERY_STATUS.full
status = _BATTERY_STATUS.full
if flags & (1 << 3):
charge_type = CHARGE_TYPE.fast
elif flags & (1 << 4):
charge_type = CHARGE_TYPE.slow
status = BATTERY_STATUS.slow_recharge
status = _BATTERY_STATUS.slow_recharge
elif flags & (1 << 5):
charge_lvl = CHARGE_LEVEL.critical
for level in battery_voltage_remaining:
Expand Down Expand Up @@ -1583,7 +1583,7 @@ def decipher_adc_measurement(report):
charge_level = level[1]
break
if flags & 0x01:
status = BATTERY_STATUS.recharging if flags & 0x02 else BATTERY_STATUS.discharging
status = _BATTERY_STATUS.recharging if flags & 0x02 else _BATTERY_STATUS.discharging
return FEATURE.ADC_MEASUREMENT, charge_level, None, status, adc


Expand Down
15 changes: 0 additions & 15 deletions lib/logitech_receiver/hidpp20_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,6 @@

FIRMWARE_KIND = NamedInts(Firmware=0x00, Bootloader=0x01, Hardware=0x02, Other=0x03)


def BATTERY_OK(status):
return status not in (BATTERY_STATUS.invalid_battery, BATTERY_STATUS.thermal_error)


BATTERY_STATUS = NamedInts(
discharging=0x00,
recharging=0x01,
almost_full=0x02,
full=0x03,
slow_recharge=0x04,
invalid_battery=0x05,
thermal_error=0x06,
)

ONBOARD_MODES = NamedInts(MODE_NO_CHANGE=0x00, MODE_ONBOARD=0x01, MODE_HOST=0x02)

CHARGE_STATUS = NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07)
Expand Down
5 changes: 3 additions & 2 deletions lib/logitech_receiver/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from . import hidpp20_constants as _hidpp20_constants
from . import settings_templates as _st
from .base import DJ_MESSAGE_ID as _DJ_MESSAGE_ID
from .common import BATTERY_STATUS as _BATTERY_STATUS
from .common import strhex as _strhex
from .i18n import _
from .status import ALERT as _ALERT
Expand Down Expand Up @@ -357,14 +358,14 @@ def _process_feature_notification(device, status, n, feature):
charge, lux, adc = _unpack("!BHH", n.data[:5])
# guesstimate the battery voltage, emphasis on 'guess'
# status_text = '%1.2fV' % (adc * 2.67793237653 / 0x0672)
status_text = _hidpp20_constants.BATTERY_STATUS.discharging
status_text = _BATTERY_STATUS.discharging
if n.address == 0x00:
status[_K.LIGHT_LEVEL] = None
status.set_battery_info(charge, None, status_text, None)
elif n.address == 0x10:
status[_K.LIGHT_LEVEL] = lux
if lux > 200:
status_text = _hidpp20_constants.BATTERY_STATUS.recharging
status_text = _BATTERY_STATUS.recharging
status.set_battery_info(charge, None, status_text, None)
elif n.address == 0x20:
if logger.isEnabledFor(logging.DEBUG):
Expand Down
18 changes: 10 additions & 8 deletions lib/logitech_receiver/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from . import hidpp20_constants as _hidpp20_constants
from . import settings as _settings
from .common import BATTERY_APPROX as _BATTERY_APPROX
from .common import BATTERY_OK as _BATTERY_OK
from .common import BATTERY_STATUS as _BATTERY_STATUS
from .common import NamedInt as _NamedInt
from .common import NamedInts as _NamedInts
from .i18n import _, ngettext
Expand Down Expand Up @@ -156,11 +158,11 @@ def set_battery_info(self, level, nextLevel, status, voltage):
# Some notifications may come with no battery level info, just
# charging state info, so do our best to infer a level (even if it is just the last level)
# It is not always possible to do this well
if status == _hidpp20_constants.BATTERY_STATUS.full:
if status == _BATTERY_STATUS.full:
level = _BATTERY_APPROX.full
elif status in (_hidpp20_constants.BATTERY_STATUS.almost_full, _hidpp20_constants.BATTERY_STATUS.recharging):
elif status in (_BATTERY_STATUS.almost_full, _BATTERY_STATUS.recharging):
level = _BATTERY_APPROX.good
elif status == _hidpp20_constants.BATTERY_STATUS.slow_recharge:
elif status == _BATTERY_STATUS.slow_recharge:
level = _BATTERY_APPROX.low
else:
level = self.get(KEYS.BATTERY_LEVEL)
Expand All @@ -174,17 +176,17 @@ def set_battery_info(self, level, nextLevel, status, voltage):
old_voltage, self[KEYS.BATTERY_VOLTAGE] = self.get(KEYS.BATTERY_VOLTAGE), voltage

charging = status in (
_hidpp20_constants.BATTERY_STATUS.recharging,
_hidpp20_constants.BATTERY_STATUS.almost_full,
_hidpp20_constants.BATTERY_STATUS.full,
_hidpp20_constants.BATTERY_STATUS.slow_recharge,
_BATTERY_STATUS.recharging,
_BATTERY_STATUS.almost_full,
_BATTERY_STATUS.full,
_BATTERY_STATUS.slow_recharge,
)
old_charging, self[KEYS.BATTERY_CHARGING] = self.get(KEYS.BATTERY_CHARGING), charging

changed = old_level != level or old_status != status or old_charging != charging or old_voltage != voltage
alert, reason = ALERT.NONE, None

if _hidpp20_constants.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL):
if _BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL):
self[KEYS.ERROR] = None
else:
logger.warning("%s: battery %d%%, ALERT %s", self._device, level, status)
Expand Down

0 comments on commit 320d880

Please sign in to comment.