From 6f3910a48e779bf6b432c015fefc333aba1b1477 Mon Sep 17 00:00:00 2001 From: taleden Date: Fri, 21 Feb 2020 16:59:37 -0600 Subject: [PATCH] extend --led option to support shading LED color by battery level --- ds4drv/__main__.py | 1 - ds4drv/actions/led.py | 74 ++++++++++++++++++++++++++++++++++++++----- ds4drv/config.py | 7 ++-- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/ds4drv/__main__.py b/ds4drv/__main__.py index 511b462..29de92f 100644 --- a/ds4drv/__main__.py +++ b/ds4drv/__main__.py @@ -75,7 +75,6 @@ def setup_device(self, device): self.logger.info("Connected to {0}", device.name) self.device = device - self.device.set_led(*self.options.led) self.fire_event("device-setup", device) self.loop.add_watcher(device.report_fd, self.read_report) self.load_options(self.options) diff --git a/ds4drv/actions/led.py b/ds4drv/actions/led.py index 76f06de..4763148 100644 --- a/ds4drv/actions/led.py +++ b/ds4drv/actions/led.py @@ -1,17 +1,75 @@ -from ..action import Action +from ..action import ReportAction from ..config import hexcolor -Action.add_option("--led", metavar="color", default="0000ff", type=hexcolor, - help="Sets color of the LED. Uses hex color codes, " - "e.g. 'ff0000' is red. Default is '0000ff' (blue)") +BATTERY_MAX = 9 +BATTERY_MAX_CHARGING = 11 +DEFAULT_COLORS = [(255,0,0),(255,255,0),(0,255,0),(0,255,255),(0,0,255)] +ReportAction.add_option("--led", metavar="color", nargs="*", type=hexcolor, + help="Sets color of the LED using hex color codes, " + "e.g. 'ff0000' or 'f00' is red. With multiple " + "colors, fades by increasing battery level; " + "with none, uses a default fade palette") -class ActionLED(Action): + +class ReportActionLED(ReportAction): """Sets the LED color on the device.""" + def __init__(self, *args, **kwargs): + super(ReportActionLED, self).__init__(*args, **kwargs) + + self.colors = None + self.handle_next = False + self.timer = self.create_timer(15, self.check_battery) + def setup(self, device): - device.set_led(*self.controller.options.led) + self.update() def load_options(self, options): - if self.controller.device: - self.controller.device.set_led(*options.led) + if options.led is None: + self.colors = None + else: + self.colors = DEFAULT_COLORS if len(options.led) < 1 else list(options.led) + if len(self.colors) == 1: + self.colors.append(self.colors[0]) + self.update() + + def update(self): + if self._last_report: + self.check_battery(self._last_report) + + if self.controller.device and self.colors and len(self.colors) > 1: + self.enable() + else: + self.disable() + + def enable(self): + self.handle_next = True + self.timer.start() + + def disable(self): + self.handle_next = False + self.timer.stop() + + def handle_report(self, report): + if self.handle_next: + self.handle_next = False + self.check_battery(report) + + def check_battery(self, report): + if self.colors and self.controller.device: + battery = max(0, report.battery) + battery_max = max(battery, BATTERY_MAX_CHARGING if report.plug_usb else BATTERY_MAX) + battery_lvl = float(battery) / battery_max + index_max = len(self.colors) - 1 + index = min(int(battery_lvl * index_max), index_max - 1) + color0 = self.colors[index] + color1 = self.colors[index + 1] + weight1 = min(max(battery_lvl * index_max - index, 0.0), 1.0) + weight0 = 1.0 - weight1 + color_r = int(weight0 * color0[0] + weight1 * color1[0] + 0.5) + color_g = int(weight0 * color0[1] + weight1 * color1[1] + 0.5) + color_b = int(weight0 * color0[2] + weight1 * color1[2] + 0.5) + self.controller.device.set_led(color_r, color_g, color_b) + + return True diff --git a/ds4drv/config.py b/ds4drv/config.py index d01a791..e306f16 100644 --- a/ds4drv/config.py +++ b/ds4drv/config.py @@ -160,10 +160,13 @@ def __call__(self, parser, namespace, values, option_string=None): def hexcolor(color): color = color.strip("#") - if len(color) != 6: + if len(color) == 6: + values = (color[:2], color[2:4], color[4:6]) + elif len(color) == 3: + values = (color[:1]*2, color[1:2]*2, color[2:3]*2) + else: raise ValueError - values = (color[:2], color[2:4], color[4:6]) values = map(lambda x: int(x, 16), values) return tuple(values)