diff --git a/docs/extension_statusled.md b/docs/extension_statusled.md new file mode 100644 index 0000000..a0a401d --- /dev/null +++ b/docs/extension_statusled.md @@ -0,0 +1,46 @@ +# Status LEDs + +Indicate which layer you are on with ah array of single leds. + +During startup the leds light up to indicte that the bootup is finished. + +For the time being just a simple consecutive single led +indicator. And when there are more layers than leds it +wraps around to the first led again. +(Also works for a single led, which just lights when any +layer is active) + +_Most of the code comes from the Mono color LED backlight extension_. + +## Enabling the extension + +To enable the extension you need to define a list of `led_pins`. It can be a list of a one, two or three pins. + +```python +from kmk.extensions.statusled import statusLED +import board + +statusLED = statusLED(led_pins=[board.GP0, board.GP1, board.GP2]) +keyboard.extensions.append(statusLED) +``` + +## [Keycodes] + +| Key | Aliases | Description | +| ------------- | ------- | ------------------- | +| `KC.SLED_INC` | | Increase Brightness | +| `KC.SLED_DEC` | | Decrease Brightness | + +## Configuration + +All of these values can be set by default for when the keyboard boots. + +```python +from kmk.extensions.led import AnimationModes +led_ext = LED( + led_pin=led_pin, + brightness=30, + brightness_step=5, + brightness_limit=100, + ) +``` diff --git a/kmk/extensions/statusled.py b/kmk/extensions/statusled.py new file mode 100644 index 0000000..5863313 --- /dev/null +++ b/kmk/extensions/statusled.py @@ -0,0 +1,145 @@ +# Use this extension for showing layer status with three leds + +import pwmio +import time + +from kmk.extensions import Extension, InvalidExtensionEnvironment +from kmk.keys import make_key + + +class statusLED(Extension): + def __init__( + self, + led_pins, + brightness=30, + brightness_step=5, + brightness_limit=100, + ): + self._leds = [] + for led in led_pins: + try: + self._leds.append(pwmio.PWMOut(led)) + except Exception as e: + print(e) + raise InvalidExtensionEnvironment( + "Unable to create pulseio.PWMOut() instance with provided led_pin" + ) + self._led_count = len(self._leds) + + self.brightness = brightness + self._layer_last = -1 + + self.brightness_step = brightness_step + self.brightness_limit = brightness_limit + + make_key(names=("SLED_INC",), on_press=self._key_led_inc) + make_key(names=("SLED_DEC",), on_press=self._key_led_dec) + + def _layer_indicator(self, layer_active, *args, **kwargs): + """ + Indicates layer with leds + + For the time being just a simple consecutive single led + indicator. And when there are more layers than leds it + wraps around to the first led again. + (Also works for a single led, which just lights when any + layer is active) + """ + + if self._layer_last != layer_active: + led_last = 0 if self._layer_last == 0 else 1 + (self._layer_last - 1) % 3 + if layer_active > 0: + led_active = 0 if layer_active == 0 else 1 + (layer_active - 1) % 3 + self.set_brightness(self.brightness, led_active) + self.set_brightness(0, led_last) + else: + self.set_brightness(0, led_last) + self._layer_last = layer_active + + def __repr__(self): + return "SLED({})".format(self._to_dict()) + + def _to_dict(self): + return { + "_brightness": self.brightness, + "brightness_step": self.brightness_step, + "brightness_limit": self.brightness_limit, + } + + def on_runtime_enable(self, sandbox): + return + + def on_runtime_disable(self, sandbox): + return + + def during_bootup(self, sandbox): + '''Light up every single led once for 200 ms''' + for i in range(self._led_count + 2): + if i < self._led_count: + self._leds[i].duty_cycle = int(self.brightness / 100 * 65535) + i_off = i - 2 + if i_off >= 0 and i_off < self._led_count: + self._leds[i_off].duty_cycle = int(0) + time.sleep(0.1) + for led in self._leds: + led.duty_cycle = int(0) + return + + def before_matrix_scan(self, sandbox): + return + + def after_matrix_scan(self, sandbox): + self._layer_indicator(sandbox.active_layers[0]) + return + + def before_hid_send(self, sandbox): + return + + def after_hid_send(self, sandbox): + return + + def on_powersave_enable(self, sandbox): + self.set_brightness(0) + return + + def on_powersave_disable(self, sandbox): + self.set_brightness(self._brightness) + self._leds[2].duty_cycle = int(50 / 100 * 65535) + time.sleep(0.2) + self._leds[2].duty_cycle = int(0) + return + + def set_brightness(self, percent, layer_id=-1): + if layer_id < 0: + for led in self._leds: + led.duty_cycle = int(percent / 100 * 65535) + else: + self._leds[layer_id - 1].duty_cycle = int(percent / 100 * 65535) + + def increase_brightness(self, step=None): + if not step: + self._brightness += self.brightness_step + else: + self._brightness += step + + if self._brightness > 100: + self._brightness = 100 + + self.set_brightness(self._brightness, self._layer_last) + + def decrease_brightness(self, step=None): + if not step: + self._brightness -= self.brightness_step + else: + self._brightness -= step + + if self._brightness < 0: + self._brightness = 0 + + self.set_brightness(self._brightness, self._layer_last) + + def _key_led_inc(self, *args, **kwargs): + self.increase_brightness() + + def _key_led_dec(self, *args, **kwargs): + self.decrease_brightness()