Added LED support, cleaned up RGB docs
This commit is contained in:
@@ -92,21 +92,30 @@ class Firmware:
|
||||
uart_pin = None
|
||||
|
||||
# RGB config
|
||||
pixel_pin = None
|
||||
num_pixels = None
|
||||
rgb_pixel_pin = None
|
||||
rgb_pixels = None
|
||||
rgb_num_pixels = None
|
||||
rgb_order = (1, 0, 2) # GRB WS2812
|
||||
val_limit = 255
|
||||
hue_default = 0
|
||||
sat_default = 100
|
||||
val_default = val_limit
|
||||
hue_step = 1
|
||||
sat_step = 1
|
||||
val_step = 1
|
||||
animation_speed = 1
|
||||
breathe_center = 1.5 # 1.0-2.7
|
||||
knight_effect_length = 3
|
||||
animation_mode = 'static'
|
||||
pixels = None
|
||||
rgb_val_limit = 255
|
||||
rgb_hue_default = 0
|
||||
rgb_sat_default = 100
|
||||
rgb_val_default = rgb_val_limit
|
||||
rgb_hue_step = 1
|
||||
rgb_sat_step = 1
|
||||
rgb_val_step = 1
|
||||
rgb_animation_speed = 1
|
||||
rgb_breathe_center = 1.5 # 1.0-2.7
|
||||
rgb_knight_effect_length = 3
|
||||
rgb_animation_mode = 'static'
|
||||
|
||||
# led config (mono color)
|
||||
led = None
|
||||
led_pin = None
|
||||
led_brightness_step = 5
|
||||
led_brightness_limit = 100
|
||||
led_breathe_center = 1.5
|
||||
led_animation_mode = 'static'
|
||||
led_animation_speed = 1
|
||||
|
||||
def __init__(self):
|
||||
# Attempt to sanely guess a coord_mapping if one is not provided
|
||||
@@ -220,14 +229,21 @@ class Firmware:
|
||||
if self.uart_pin is not None:
|
||||
self.uart = self.init_uart(self.uart_pin)
|
||||
|
||||
if self.pixel_pin is not None:
|
||||
self.pixels = rgb.RGB(self.pixel_pin, self.rgb_order, self.num_pixels,
|
||||
self.hue_step, self.sat_step, self.val_step,
|
||||
self.hue_default, self.sat_default, self.val_default,
|
||||
self.breathe_center, self.knight_effect_length,
|
||||
self.val_limit, self.animation_mode, self.animation_speed,
|
||||
if self.rgb_pixel_pin is not None:
|
||||
self.pixels = rgb.RGB(self.rgb_pixel_pin, self.rgb_order, self.rgb_num_pixels,
|
||||
self.rgb_hue_step, self.rgb_sat_step, self.rgb_val_step,
|
||||
self.rgb_hue_default, self.rgb_sat_default, self.rgb_val_default,
|
||||
self.rgb_breathe_center, self.rgb_knight_effect_length,
|
||||
self.rgb_val_limit, self.rgb_animation_mode,
|
||||
self.rgb_animation_speed,
|
||||
)
|
||||
|
||||
if self.led_pin:
|
||||
self.led = led.led(self.led_pin, self.led_brightness_step, self.led_brightness_limit,
|
||||
self.led_animation_mode, self.led_animation_speed,
|
||||
self.led_breathe_center,
|
||||
)
|
||||
|
||||
self.matrix = MatrixScanner(
|
||||
cols=self.col_pins,
|
||||
rows=self.row_pins,
|
||||
@@ -286,7 +302,15 @@ class Firmware:
|
||||
if self.debug_enabled and state_changed and self.pixels.enabled:
|
||||
print('New State: {}'.format(self.pixels))
|
||||
|
||||
if self.pixels.animation_mode is not None:
|
||||
self.pixels = self.pixels.animate()
|
||||
if self.pixels:
|
||||
# Only check animations if pixels is initialized
|
||||
if self.pixels.animation_mode:
|
||||
if self.pixels.animation_mode is not 'static_standby':
|
||||
self.pixels = self.pixels.animate()
|
||||
|
||||
if self.led:
|
||||
# Only check animations if led is initialized
|
||||
if self.led.animation_mode:
|
||||
self.led = self.led.animate()
|
||||
|
||||
gc.collect()
|
||||
|
@@ -126,32 +126,32 @@ def rgb_tog(key, state, *args, **kwargs):
|
||||
|
||||
|
||||
def rgb_hui(key, state, *args, **kwargs):
|
||||
state.config.pixels.increase_hue(state.config.pixels.hue_step)
|
||||
state.config.pixels.increase_hue()
|
||||
return state
|
||||
|
||||
|
||||
def rgb_hud(key, state, *args, **kwargs):
|
||||
state.config.pixels.decrease_hue(state.config.pixels.hue_step)
|
||||
state.config.pixels.decrease_hue()
|
||||
return state
|
||||
|
||||
|
||||
def rgb_sai(key, state, *args, **kwargs):
|
||||
state.config.pixels.increase_sat(state.config.pixels.sat_step)
|
||||
state.config.pixels.increase_sat()
|
||||
return state
|
||||
|
||||
|
||||
def rgb_sad(key, state, *args, **kwargs):
|
||||
state.config.pixels.decrease_sat(state.config.pixels.sat_step)
|
||||
state.config.pixels.decrease_sat()
|
||||
return state
|
||||
|
||||
|
||||
def rgb_vai(key, state, *args, **kwargs):
|
||||
state.config.pixels.increase_val(state.config.pixels.val_step)
|
||||
state.config.pixels.increase_val()
|
||||
return state
|
||||
|
||||
|
||||
def rgb_vad(key, state, *args, **kwargs):
|
||||
state.config.pixels.decrease_val(state.config.pixels.val_step)
|
||||
state.config.pixels.decrease_val()
|
||||
return state
|
||||
|
||||
|
||||
@@ -193,3 +193,40 @@ def rgb_mode_knight(key, state, *args, **kwargs):
|
||||
state.config.pixels.effect_init = True
|
||||
state.config.pixels.animation_mode = 'knight'
|
||||
return state
|
||||
|
||||
|
||||
def led_tog(key, state, *args, **kwargs):
|
||||
state.config.led.enabled = not state.config.led.enabled
|
||||
return state
|
||||
|
||||
|
||||
def led_inc(key, state, *args, **kwargs):
|
||||
state.config.led.increase_brightness()
|
||||
return state
|
||||
|
||||
|
||||
def led_dec(key, state, *args, **kwargs):
|
||||
state.config.led.decrease_brightness()
|
||||
return state
|
||||
|
||||
|
||||
def led_ani(key, state, *args, **kwargs):
|
||||
state.config.led.increase_ani()
|
||||
return state
|
||||
|
||||
|
||||
def led_and(key, state, *args, **kwargs):
|
||||
state.config.led.decrease_ani()
|
||||
return state
|
||||
|
||||
|
||||
def led_mode_static(key, state, *args, **kwargs):
|
||||
state.config.led.effect_init = True
|
||||
state.config.led.animation_mode = 'static'
|
||||
return state
|
||||
|
||||
|
||||
def led_mode_breathe(key, state, *args, **kwargs):
|
||||
state.config.led.effect_init = True
|
||||
state.config.led.animation_mode = 'breathing'
|
||||
return state
|
||||
|
11
kmk/keys.py
11
kmk/keys.py
@@ -641,6 +641,17 @@ make_key(names=('RGB_MODE_RAINBOW', 'RGB_M_R'), on_press=handlers.rgb_mode_rainb
|
||||
make_key(names=('RGB_MODE_BREATHE_RAINBOW', 'RGB_M_BR'),
|
||||
on_press=handlers.rgb_mode_breathe_rainbow)
|
||||
make_key(names=('RGB_MODE_KNIGHT', 'RGB_M_K'), on_press=handlers.rgb_mode_knight)
|
||||
|
||||
|
||||
make_key(names=('LED_TOG',), on_press=handlers.led_tog)
|
||||
make_key(names=('LED_INC',), on_press=handlers.led_inc)
|
||||
make_key(names=('LED_DEC',), on_press=handlers.led_dec)
|
||||
make_key(names=('LED_ANI',), on_press=handlers.led_ani)
|
||||
make_key(names=('LED_AND',), on_press=handlers.led_and)
|
||||
make_key(names=('LED_MODE_PLAIN', 'LED_M_P'), on_press=handlers.led_mode_static)
|
||||
make_key(names=('LED_MODE_BREATHE', 'LED_M_B'), on_press=handlers.led_mode_breathe)
|
||||
|
||||
|
||||
make_key(
|
||||
names=('LEADER', 'LEAD'),
|
||||
on_press=handlers.leader_pressed,
|
||||
|
125
kmk/led.py
Normal file
125
kmk/led.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import time
|
||||
from math import e, exp, pi, sin
|
||||
|
||||
import pulseio
|
||||
|
||||
|
||||
class led:
|
||||
brightness = 0
|
||||
time = int(time.monotonic() * 1000)
|
||||
pos = 0
|
||||
effect_init = False
|
||||
|
||||
led = None
|
||||
brightness_step = 5
|
||||
brightness_limit = 100
|
||||
breath_center = 1.5
|
||||
animation_mode = 'static'
|
||||
animation_speed = 1
|
||||
enabled = True
|
||||
|
||||
def __init__(self, led_pin, brightness_step, brightness_limit,
|
||||
animation_mode, animation_speed, breath_center):
|
||||
self.led = pulseio.PWMOut(led_pin)
|
||||
self.brightness_step = brightness_step
|
||||
self.brightness_limit = brightness_limit
|
||||
self.animation_mode = animation_mode
|
||||
self.animation_speed = animation_speed
|
||||
self.breath_center = breath_center
|
||||
|
||||
def __repr__(self):
|
||||
return 'LED({})'.format(self._to_dict())
|
||||
|
||||
def _to_dict(self):
|
||||
return {
|
||||
'led': self.led,
|
||||
'brightness_step': self.brightness_step,
|
||||
'brightness_limit': self.brightness_limit,
|
||||
'animation_mode': self.animation_mode,
|
||||
'animation_speed': self.animation_speed,
|
||||
'breath_center': self.breath_center,
|
||||
}
|
||||
|
||||
def time_ms(self):
|
||||
return int(time.monotonic() * 1000)
|
||||
|
||||
def set_brightness(self, percent):
|
||||
self.led.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)
|
||||
|
||||
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)
|
||||
|
||||
def off(self):
|
||||
self.set_brightness(0)
|
||||
|
||||
def increase_ani(self):
|
||||
"""
|
||||
Increases animation speed by 1 amount stopping at 10
|
||||
:param step:
|
||||
"""
|
||||
if (self.animation_speed + 1) >= 10:
|
||||
self.animation_speed = 10
|
||||
else:
|
||||
self.val += 1
|
||||
|
||||
def decrease_ani(self):
|
||||
"""
|
||||
Decreases animation speed by 1 amount stopping at 0
|
||||
:param step:
|
||||
"""
|
||||
if (self.val - 1) <= 0:
|
||||
self.val = 0
|
||||
else:
|
||||
self.val -= 1
|
||||
|
||||
def effect_breathing(self):
|
||||
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
|
||||
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
|
||||
self.brightness = int((exp(sin((self.pos / 255.0) * pi)) - self.breath_center / e) *
|
||||
(self.brightness_limit / (e - 1 / e)))
|
||||
self.pos = (self.pos + self.animation_speed) % 256
|
||||
self.set_brightness(self.brightness)
|
||||
|
||||
return self
|
||||
|
||||
def effect_static(self):
|
||||
self.set_brightness(self.brightness)
|
||||
# Set animation mode to none to prevent cycles from being wasted
|
||||
self.animation_mode = None
|
||||
return self
|
||||
|
||||
def animate(self):
|
||||
"""
|
||||
Activates a "step" in the animation based on the active mode
|
||||
:return: Returns the new state in animation
|
||||
"""
|
||||
if self.effect_init:
|
||||
self.init_effect()
|
||||
if self.enabled:
|
||||
if self.animation_mode == 'breathing':
|
||||
return self.effect_breathing()
|
||||
elif self.animation_mode == 'static':
|
||||
return self.effect_static()
|
||||
else:
|
||||
self.off()
|
||||
|
||||
return self
|
53
kmk/rgb.py
53
kmk/rgb.py
@@ -1,6 +1,5 @@
|
||||
import time
|
||||
from math import e as M_E
|
||||
from math import exp, floor, pi, sin
|
||||
from math import e, exp, pi, sin
|
||||
|
||||
|
||||
class RGB:
|
||||
@@ -8,7 +7,7 @@ class RGB:
|
||||
sat = 100
|
||||
val = 80
|
||||
pos = 0
|
||||
time = floor(time.monotonic() * 10)
|
||||
time = int(time.monotonic() * 10)
|
||||
intervals = (30, 20, 10, 5)
|
||||
animation_speed = 1
|
||||
enabled = True
|
||||
@@ -61,7 +60,7 @@ class RGB:
|
||||
return 'RGB({})'.format(self._to_dict())
|
||||
|
||||
def _to_dict(self):
|
||||
ret = {
|
||||
return {
|
||||
'hue': self.hue,
|
||||
'sat': self.sat,
|
||||
'val': self.val,
|
||||
@@ -74,10 +73,8 @@ class RGB:
|
||||
'disable_auto_write': self.disable_auto_write,
|
||||
}
|
||||
|
||||
return ret
|
||||
|
||||
def time_ms(self):
|
||||
return floor(time.monotonic() * 1000)
|
||||
return int(time.monotonic() * 1000)
|
||||
|
||||
def hsv_to_rgb(self, hue, sat, val):
|
||||
"""
|
||||
@@ -101,9 +98,9 @@ class RGB:
|
||||
|
||||
else:
|
||||
base = ((100 - sat) * val) / 100
|
||||
color = floor((val - base) * ((hue % 60) / 60))
|
||||
color = int((val - base) * ((hue % 60) / 60))
|
||||
|
||||
x = floor(hue / 60)
|
||||
x = int(hue / 60)
|
||||
if x == 0:
|
||||
r = val
|
||||
g = base + color
|
||||
@@ -129,7 +126,7 @@ class RGB:
|
||||
g = base
|
||||
b = val - color
|
||||
|
||||
return floor(r), floor(g), floor(b)
|
||||
return int(r), int(g), int(b)
|
||||
|
||||
def hsv_to_rgbw(self, hue, sat, val):
|
||||
"""
|
||||
@@ -190,58 +187,76 @@ class RGB:
|
||||
if not self.disable_auto_write:
|
||||
self.neopixel.show()
|
||||
|
||||
def increase_hue(self, step):
|
||||
def increase_hue(self, step=None):
|
||||
"""
|
||||
Increases hue by step amount rolling at 360 and returning to 0
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.hue_step
|
||||
|
||||
self.hue = (self.hue + step) % 360
|
||||
|
||||
def decrease_hue(self, step):
|
||||
def decrease_hue(self, step=None):
|
||||
"""
|
||||
Decreases hue by step amount rolling at 0 and returning to 360
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.hue_step
|
||||
|
||||
if (self.hue - step) <= 0:
|
||||
self.hue = (self.hue + 360 - step) % 360
|
||||
else:
|
||||
self.hue = (self.hue - step) % 360
|
||||
|
||||
def increase_sat(self, step):
|
||||
def increase_sat(self, step=None):
|
||||
"""
|
||||
Increases saturation by step amount stopping at 100
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.sat_step
|
||||
|
||||
if self.sat + step >= 100:
|
||||
self.sat = 100
|
||||
else:
|
||||
self.sat += step
|
||||
|
||||
def decrease_sat(self, step):
|
||||
def decrease_sat(self, step=None):
|
||||
"""
|
||||
Decreases saturation by step amount stopping at 0
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.sat_step
|
||||
|
||||
if (self.sat - step) <= 0:
|
||||
self.sat = 0
|
||||
else:
|
||||
self.sat -= step
|
||||
|
||||
def increase_val(self, step):
|
||||
def increase_val(self, step=None):
|
||||
"""
|
||||
Increases value by step amount stopping at 100
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.val_step
|
||||
|
||||
if (self.val + step) >= 100:
|
||||
self.val = 100
|
||||
else:
|
||||
self.val += step
|
||||
|
||||
def decrease_val(self, step):
|
||||
def decrease_val(self, step=None):
|
||||
"""
|
||||
Decreases value by step amount stopping at 0
|
||||
:param step:
|
||||
"""
|
||||
if not step:
|
||||
step = self.val_step
|
||||
|
||||
if (self.val - step) <= 0:
|
||||
self.val = 0
|
||||
else:
|
||||
@@ -326,8 +341,8 @@ class RGB:
|
||||
def effect_breathing(self):
|
||||
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
|
||||
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
|
||||
self.val = floor((exp(sin((self.pos / 255.0) * pi)) - self.breath_center / M_E) *
|
||||
(self.val_limit / (M_E - 1 / M_E)))
|
||||
self.val = int((exp(sin((self.pos / 255.0) * pi)) - self.breath_center / e) *
|
||||
(self.val_limit / (e - 1 / e)))
|
||||
self.pos = (self.pos + self.animation_speed) % 256
|
||||
self.set_hsv_fill(self.hue, self.sat, self.val)
|
||||
|
||||
@@ -351,7 +366,7 @@ class RGB:
|
||||
# Determine which LEDs should be lit up
|
||||
self.disable_auto_write = True # Turn off instantly showing
|
||||
self.off() # Fill all off
|
||||
pos = floor(self.pos)
|
||||
pos = int(self.pos)
|
||||
|
||||
# Set all pixels on in range of animation length offset by position
|
||||
for i in range(pos, (pos + self.knight_effect_length)):
|
||||
|
Reference in New Issue
Block a user