Different color for each figure

This commit is contained in:
Martin Bauer 2021-12-19 13:46:45 +01:00
parent 7a1ed75998
commit bb5d3e1870
3 changed files with 104 additions and 38 deletions

View File

@ -1,5 +1,6 @@
from dataclasses import dataclass
import struct
import colorsys
@dataclass
@ -9,8 +10,8 @@ class ColorRGBW:
b: float
w: float
def repr(self):
return f"ColorRGBW({self.r}, {self.g}, {self.b}, {self.w}"
def __repr__(self):
return f"#({self.r}, {self.g}, {self.b}, {self.w})"
def as_bytes(self) -> bytes:
assert self.is_valid(), "Trying to send invalid " + repr(self)
@ -28,6 +29,14 @@ class ColorHSV:
s: float
v: float
@staticmethod
def fromRGB(rgb):
conv = colorsys.rgb_to_hsv(rgb.r, rgb.g, rgb.b)
return ColorHSV(conv[0] * 360, conv[1], conv[2])
def __repr__(self):
return f"ColorHSV({self.h}, {self.s}, {self.v})"
def as_bytes(self) -> bytes:
return struct.pack("<fff", self.h, self.s, self.v)
@ -47,6 +56,9 @@ class EffectStaticConfig:
begin: int = 0
end: int = 0
def __repr__(self):
return f"EffectStaticConfig {str(self.color)}, beg: {self.begin}, end {self.end}"
def as_bytes(self) -> bytes:
return self.color.as_bytes() + struct.pack("<HH", self.begin, self.end)
@ -68,6 +80,9 @@ class EffectAlexaSwipeConfig:
self.bell_curve_width_in_leds, self.start_position,
self.forward) + self.primary_color.as_bytes() + self.secondary_color.as_bytes()
def __repr__(self):
return f"EffectAlexaSwipe primary {str(self.primary_color)}, {str(self.secondary_color)}"
@dataclass
class EffectRandomTwoColorInterpolationConfig:
@ -80,9 +95,14 @@ class EffectRandomTwoColorInterpolationConfig:
color2: ColorHSV = ColorHSV(192, 1, 1)
def as_bytes(self) -> bytes:
c1 = ColorHSV.fromRGB(self.color1) if isinstance(self.color1, ColorRGBW) else self.color1
c2 = ColorHSV.fromRGB(self.color2) if isinstance(self.color2, ColorRGBW) else self.color2
return struct.pack("<i?i??", self.cycle_durations_ms, self.start_with_existing,
self.num_segments, self.hue1_random,
self.hue2_random) + self.color1.as_bytes() + self.color2.as_bytes()
self.hue2_random) + c1.as_bytes() + c2.as_bytes()
def __repr__(self):
return f"RandTwoColor {str(self.color1)}, {str(self.color2)}, segments {self.num_segments}"
@dataclass
@ -101,4 +121,7 @@ class EffectSwipeAndChange:
change: EffectRandomTwoColorInterpolationConfig = EffectRandomTwoColorInterpolationConfig()
def as_bytes(self) -> bytes:
return self.swipe.as_bytes() + self.change.as_bytes()
return self.swipe.as_bytes() + self.change.as_bytes()
def __repr__(self) -> str:
return f"Swipe and Change: \n {str(self.swipe)}\n {str(self.change)}"

View File

@ -3,7 +3,7 @@ import serial_asyncio
from led_cmds import (ColorRGBW, ColorHSV, EffectStaticConfig,
EffectRandomTwoColorInterpolationConfig, EffectAlexaSwipeConfig,
EffectSwipeAndChange)
from host_driver import MusicMouseProtocol, RfidTokenRead, RotaryEncoderEvent, ButtonEvent
from host_driver import MusicMouseProtocol, RfidTokenRead, RotaryEncoderEvent, ButtonEvent, TouchButton, TouchButtonPress, TouchButtonRelease
from player import AudioPlayer
from glob import glob
import os
@ -11,6 +11,8 @@ import os
MUSIC_FOLDER = "/home/martin/code/musicmouse/espmusicmouse/host_driver/music"
audio_player = AudioPlayer()
current_figure = None
last_figure = None
rfid_token_map = {
bytes.fromhex("88041174e9"): "elefant",
@ -21,24 +23,45 @@ rfid_token_map = {
bytes.fromhex("8804bc7444"): "hund",
}
def parse_hex_color(color_str: str):
if isinstance(color_str, ColorRGBW):
return color_str
color_str = color_str.lstrip('#')
t = tuple(int(color_str[i:i + 2], 16) / 255 for i in (0, 2, 4))
return ColorRGBW(*t, 0)
class FigureColorCfg:
def __init__(self, primary, secondary, background, accent):
self.primary = parse_hex_color(primary)
self.secondary = parse_hex_color(secondary)
self.background = parse_hex_color(background)
self.accent = parse_hex_color(accent)
color_cfg = {
"elefant": FigureColorCfg("#ffff00", "#00c8ff", "#094b46", "#c20099"),
"fuchs": FigureColorCfg("#F4D35E", "#F95738", "#F95738", "#083d77"),
"omnom": FigureColorCfg("#005102", "#3bc405", "#005102", "#3bc405"),
"eichhoernchen": FigureColorCfg("#ff0ada", "#4BC6B9", "#69045a", "#4BC6B9"),
"hund": FigureColorCfg("#ffff00", "#00c8ff", "#094b46", "#c20099"),
"eule": FigureColorCfg("#e5a200", "#f8e300", ColorRGBW(0, 0, 0, 0.2), ColorRGBW(0, 0, 0, 1)),
}
playlists = {
fig: audio_player.create_playlist(sorted(glob(os.path.join(MUSIC_FOLDER, fig, "*.mp3"))))
for fig in rfid_token_map.values()
}
mouse_leds = {
'right_foot': (0, 6),
'left_foot': (6, 6 + 6),
'left_ear': (6 + 6, 6 + 6 + 16),
'right_ear': (6 + 6 + 16, 6 + 6 + 16 + 17),
TouchButton.RIGHT_FOOT: (0, 6),
TouchButton.LEFT_FOOT: (6, 6 + 6),
TouchButton.LEFT_EAR: (6 + 6, 6 + 6 + 16),
TouchButton.RIGHT_EAR: (6 + 6 + 16, 6 + 6 + 16 + 17),
}
def set_mouse_leds(protocol, position: str, color: ColorRGBW):
start, end = mouse_leds[position]
protocol.led_ring_effect(EffectStaticConfig(color, start, end))
def on_music_end_callback(protocol):
eff = EffectAlexaSwipeConfig()
eff.forward = False
@ -46,35 +69,47 @@ def on_music_end_callback(protocol):
protocol.mouse_led_effect(EffectStaticConfig(ColorRGBW(0, 0, 0, 0)))
def on_firmware_msg(protocol: MusicMouseProtocol, message):
print("Got message", message)
if isinstance(message, RfidTokenRead) and message.id == bytes.fromhex("0000000000"):
def on_rfid(protocol, tagid):
global current_figure, last_figure
if tagid == bytes.fromhex("0000000000"):
# Off
if audio_player.is_playing():
eff = EffectAlexaSwipeConfig()
eff.forward = False
ring_eff = EffectAlexaSwipeConfig()
ring_eff.forward = False
else:
eff = EffectStaticConfig(ColorRGBW(0, 0, 0, 0))
protocol.led_ring_effect(eff)
ring_eff = EffectStaticConfig(ColorRGBW(0, 0, 0, 0))
protocol.led_ring_effect(ring_eff)
protocol.mouse_led_effect(EffectStaticConfig(ColorRGBW(0, 0, 0, 0)))
audio_player.pause()
elif isinstance(message, RfidTokenRead) and message.id in rfid_token_map:
eff = EffectSwipeAndChange()
eff.swipe.primary_color = ColorRGBW(1, 1, 0, 0)
figure = rfid_token_map[message.id]
if figure == "eule":
eff.swipe.primary_color = ColorRGBW(0.96, 0.7, 0, 0)
eff.swipe.secondary_color = ColorRGBW(0.96, 0.7, 0, 0)
eff.swipe.swipe_speed = 180
eff.swipe.bell_curve_width_in_leds = 6
last_figure = current_figure
else:
figure = rfid_token_map[tagid]
current_figure = figure
ccfg = color_cfg[figure]
ring_eff = EffectSwipeAndChange()
ring_eff.swipe.primary_color = ccfg.primary
ring_eff.swipe.secondary_color = ccfg.secondary
ring_eff.change.color1 = ccfg.primary
ring_eff.change.color2 = ccfg.secondary
protocol.led_ring_effect(ring_eff)
mouse_eff = EffectStaticConfig(ccfg.background)
protocol.mouse_led_effect(mouse_eff)
protocol.led_ring_effect(eff)
protocol.mouse_led_effect(
EffectStaticConfig(ColorRGBW(18 / 255 / 2, 156 / 255 / 2, 140 / 255 / 2, 0)))
print(figure)
if figure in playlists:
audio_player.set_playlist(playlists[figure])
audio_player.play_from_start()
if last_figure == current_figure:
audio_player.play()
else:
audio_player.play_from_start()
def on_firmware_msg(protocol: MusicMouseProtocol, message):
print("FW msg:", message)
if isinstance(message, RfidTokenRead):
on_rfid(protocol, message.id)
elif isinstance(message, RotaryEncoderEvent):
if audio_player.is_playing():
if message.direction == 2:
@ -86,6 +121,14 @@ def on_firmware_msg(protocol: MusicMouseProtocol, message):
audio_player.previous()
elif message.button == "right" and message.event == "pressed":
audio_player.next()
elif isinstance(message, TouchButtonPress):
ccfg = color_cfg[current_figure]
protocol.mouse_led_effect(EffectStaticConfig(ccfg.accent,
*mouse_leds[message.touch_button]))
elif isinstance(message, TouchButtonRelease):
ccfg = color_cfg[current_figure]
color = ccfg.background if audio_player.is_playing() else ColorRGBW(0, 0, 0, 0)
protocol.mouse_led_effect(EffectStaticConfig(color, *mouse_leds[message.touch_button]))
loop = asyncio.get_event_loop()

View File

@ -113,11 +113,11 @@ class AudioPlayer:
def _callback(self, event, *args, **kwargs):
if True: # event.type == vlc.EventType.MediaPlayerEndReached:
print("End reached")
#print("End reached")
if self.on_playlist_end_callback:
self.on_playlist_end_callback()
print("Callback from VLC", event, args, kwargs)
print(event.meta_type, event.obj, event.type)
#print("Callback from VLC", event, args, kwargs)
#print(event.meta_type, event.obj, event.type)
def change_volume(self, amount=1):
vol = self.media_player.audio_get_volume() + amount