Added LED support, cleaned up RGB docs

This commit is contained in:
Kyle Brown
2019-02-26 17:30:53 -08:00
parent 7ebfaa3bf7
commit f7a1d54752
8 changed files with 356 additions and 130 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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)):