adding shelve leds

This commit is contained in:
Martin Bauer 2022-01-12 18:13:59 +01:00
parent 32b1c54fbc
commit 1a17d49599
6 changed files with 112 additions and 160 deletions

View File

@ -39,6 +39,14 @@ mouse_led_effect_to_message_id = {
EffectReverseSwipe: 10,
}
shelve_led_effect_to_message_id = {
EffectStaticConfig: 15,
EffectCircularConfig: 16,
EffectRandomTwoColorInterpolationConfig: 17,
EffectSwipeAndChange: 18,
EffectReverseSwipe: 19,
}
mouse_leds_index_ranges = {
TouchButton.RIGHT_FOOT: (0, 6),
TouchButton.LEFT_FOOT: (6, 6 + 6),
@ -126,17 +134,20 @@ class MusicMouseProtocol(asyncio.Protocol):
self.transport = transport
self.in_buff = bytes()
def led_ring_effect(self, effect_cfg):
def __led_effect(self, effect_cfg, msg_dict):
msg_content = effect_cfg.as_bytes()
header = struct.pack("<IBH", MAGIC_TOKEN_HOST_TO_FW,
led_ring_effect_to_message_id[type(effect_cfg)], len(msg_content))
header = struct.pack("<IBH", MAGIC_TOKEN_HOST_TO_FW, msg_dict[type(effect_cfg)],
len(msg_content))
self.transport.write(header + msg_content)
def led_ring_effect(self, effect_cfg):
self.__led_effect(effect_cfg, led_ring_effect_to_message_id)
def mouse_led_effect(self, effect_cfg):
msg_content = effect_cfg.as_bytes()
header = struct.pack("<IBH", MAGIC_TOKEN_HOST_TO_FW,
mouse_led_effect_to_message_id[type(effect_cfg)], len(msg_content))
self.transport.write(header + msg_content)
self.__led_effect(effect_cfg, mouse_led_effect_to_message_id)
def shelve_led_effect(self, effect_cfg):
self.__led_effect(effect_cfg, shelve_led_effect_to_message_id)
def button_background_led_prev(self, val):
msg_content = struct.pack("<f", val)

View File

@ -3,7 +3,7 @@
import asyncio
import sys
import serial_asyncio
from led_cmds import (ColorRGBW, ColorHSV, EffectStaticConfig,
from led_cmds import (ColorRGBW, ColorHSV, EffectCircularConfig, EffectStaticConfig,
EffectRandomTwoColorInterpolationConfig, EffectAlexaSwipeConfig,
EffectSwipeAndChange, EffectReverseSwipe)
from host_driver import MusicMouseProtocol, RfidTokenRead, RotaryEncoderEvent, ButtonEvent, TouchButton, TouchButtonPress, TouchButtonRelease, mouse_leds_index_ranges
@ -16,6 +16,7 @@ import argparse
from ruamel.yaml import YAML
import warnings
from pprint import pprint
from typing import Optional
yaml = YAML(typ='safe')
@ -50,8 +51,11 @@ def hass_service(hass, domain, service, **kwargs):
class MusicMouseState:
def __init__(self, protocol: MusicMouseProtocol):
self.current_figure: str = None
self.last_figure: str = None
self.active_figure: Optional[
str] = None # None if no figure is placed on the reader, or the name of the figure
self.last_partially_played_figure: Optional[
str] = None # figure whose playlist wasn't played completely and was removed
self.current_mouse_led_effect = None
self.current_led_ring_effect = None
self.protocol: MusicMouseProtocol = protocol
@ -75,13 +79,6 @@ class MusicMouseState:
self.mouse_led_effect(EffectStaticConfig(OFF_COLOR))
self.led_ring_effect(EffectStaticConfig(OFF_COLOR))
def figure_placed(self, figure_state):
self.last_figure = self.current_figure
self.current_figure = figure_state
def figure_removed(self):
self.last_figure = self.current_figure
class Controller:
def __init__(self, protocol, hass, cfg):
@ -97,7 +94,7 @@ class Controller:
self.audio_player.set_volume_limits(vol_min, vol_max)
protocol.register_message_callback(self.on_firmware_msg)
self.audio_player.on_playlist_end_callback = self._run_off_animation
self.audio_player.on_playlist_end_callback = self._on_playlist_end
self.playlists = {
fig: self.audio_player.create_playlist(fig_cfg['media_files'])
for fig, fig_cfg in cfg['figures'].items()
@ -107,27 +104,49 @@ class Controller:
for figure_name, figure_cfg in cfg["figures"].items()
}
self.protocol.shelve_led_effect(EffectStaticConfig(ColorRGBW(0, 0, 0.1, 0)))
shelf_eff = EffectCircularConfig()
shelf_eff.color = ColorRGBW(0, 0, 0.4, 0)
shelf_eff = EffectStaticConfig(ColorRGBW(0, 0, 0, 0))
self.protocol.shelve_led_effect(shelf_eff)
def _on_playlist_end(self):
if not self.audio_player.is_playing():
self.mmstate.last_partially_played_figure = None
self._run_off_animation()
else:
print("Playlist end was called, even if player remains playing?!")
def handle_rfid_event(self, tagid):
if tagid == bytes.fromhex("0000000000"):
if self.audio_player.is_playing():
print("Got 000 rfid -> playing off animation")
self._run_off_animation()
self.audio_player.pause()
self.mmstate.figure_removed()
self.mmstate.last_partially_played_figure = self.mmstate.active_figure
else:
self.mmstate.last_partially_played_figure = None
self.mmstate.active_figure = None
elif tagid in self._rfid_to_figure_name:
figure = self._rfid_to_figure_name[tagid]
primary_color, secondary_color, *rest = self.cfg["figures"][figure]["colors"]
newly_placed_figure = self._rfid_to_figure_name[tagid]
primary_color, secondary_color, *rest = self.cfg["figures"][newly_placed_figure][
"colors"]
self._start_animation(primary_color, secondary_color)
self.mmstate.button_leds(self.cfg["general"].get("button_leds_brightness", 0.5))
if figure in self.playlists:
self.audio_player.set_playlist(self.playlists[figure])
if self.mmstate.last_figure == figure:
if newly_placed_figure in self.cfg['figures']:
if self.mmstate.last_partially_played_figure == newly_placed_figure:
print("Continuing playlist")
self.audio_player.play()
else:
print("Restarting playlist")
self.audio_player.set_playlist(
self.audio_player.create_playlist(
self.cfg['figures'][newly_placed_figure]['media_files']))
self.audio_player.play_from_start()
self.mmstate.figure_placed(figure)
self.mmstate.active_figure = newly_placed_figure
else:
warnings.warn(f"Unknown figure/tag with id {tagid}")
@ -145,15 +164,13 @@ class Controller:
elif isinstance(message, ButtonEvent):
btn = message.button
if btn == "left" and message.event == "pressed" and self.audio_player.is_playing():
res = self.audio_player.previous()
print(f"Prev {res}")
self.audio_player.previous()
elif btn == "right" and message.event == "pressed" and self.audio_player.is_playing():
res = self.audio_player.nex()
print(f"Next {res}")
self.audio_player.next()
elif message.button == "rotary" and message.event == "pressed":
hass_service(self.hass, "light", "toggle", entity_id="light.kinderzimmer_fluter")
elif isinstance(message, TouchButtonPress):
figure = self.mmstate.current_figure
figure = self.mmstate.active_figure
if figure and self.audio_player.is_playing():
primary_color, secondary_color, bg, accent = self.cfg["figures"][figure]["colors"]
self.protocol.mouse_led_effect(
@ -180,7 +197,7 @@ class Controller:
**colors[message.touch_button])
elif isinstance(message, TouchButtonRelease):
figure = self.mmstate.current_figure
figure = self.mmstate.active_figure
eff_change = EffectRandomTwoColorInterpolationConfig()
eff_static = EffectStaticConfig(ColorRGBW(0, 0, 0, 0),
*mouse_leds_index_ranges[message.touch_button])

View File

@ -1,72 +1,5 @@
import vlc
all_events = (
vlc.EventType.MediaDiscovererEnded,
vlc.EventType.MediaDiscovererStarted,
vlc.EventType.MediaDurationChanged,
vlc.EventType.MediaFreed,
vlc.EventType.MediaListEndReached,
vlc.EventType.MediaListItemAdded,
vlc.EventType.MediaListItemDeleted,
vlc.EventType.MediaListPlayerNextItemSet,
vlc.EventType.MediaListPlayerPlayed,
vlc.EventType.MediaListPlayerStopped,
vlc.EventType.MediaListViewItemAdded,
vlc.EventType.MediaListViewItemDeleted,
vlc.EventType.MediaListViewWillAddItem,
vlc.EventType.MediaListViewWillDeleteItem,
vlc.EventType.MediaListWillAddItem,
vlc.EventType.MediaListWillDeleteItem,
vlc.EventType.MediaMetaChanged,
vlc.EventType.MediaParsedChanged,
vlc.EventType.MediaPlayerAudioDevice,
vlc.EventType.MediaPlayerAudioVolume,
vlc.EventType.MediaPlayerBackward,
vlc.EventType.MediaPlayerBuffering,
vlc.EventType.MediaPlayerChapterChanged,
vlc.EventType.MediaPlayerCorked,
vlc.EventType.MediaPlayerESAdded,
vlc.EventType.MediaPlayerESDeleted,
vlc.EventType.MediaPlayerESSelected,
vlc.EventType.MediaPlayerEncounteredError,
vlc.EventType.MediaPlayerEndReached,
vlc.EventType.MediaPlayerForward,
#vlc.EventType.MediaPlayerLengthChanged,
vlc.EventType.MediaPlayerMediaChanged,
vlc.EventType.MediaPlayerMuted,
vlc.EventType.MediaPlayerNothingSpecial,
vlc.EventType.MediaPlayerOpening,
vlc.EventType.MediaPlayerPausableChanged,
vlc.EventType.MediaPlayerPaused,
vlc.EventType.MediaPlayerPlaying,
#vlc.EventType.MediaPlayerPositionChanged,
vlc.EventType.MediaPlayerScrambledChanged,
vlc.EventType.MediaPlayerSeekableChanged,
vlc.EventType.MediaPlayerSnapshotTaken,
vlc.EventType.MediaPlayerStopped,
#vlc.EventType.MediaPlayerTimeChanged,
vlc.EventType.MediaPlayerTitleChanged,
vlc.EventType.MediaPlayerUncorked,
vlc.EventType.MediaPlayerUnmuted,
vlc.EventType.MediaPlayerVout,
vlc.EventType.MediaStateChanged,
vlc.EventType.MediaSubItemAdded,
vlc.EventType.MediaSubItemTreeAdded,
vlc.EventType.RendererDiscovererItemAdded,
vlc.EventType.RendererDiscovererItemDeleted,
vlc.EventType.VlmMediaAdded,
vlc.EventType.VlmMediaChanged,
vlc.EventType.VlmMediaInstanceStarted,
vlc.EventType.VlmMediaInstanceStatusEnd,
vlc.EventType.VlmMediaInstanceStatusError,
vlc.EventType.VlmMediaInstanceStatusInit,
vlc.EventType.VlmMediaInstanceStatusOpening,
vlc.EventType.VlmMediaInstanceStatusPause,
vlc.EventType.VlmMediaInstanceStatusPlaying,
vlc.EventType.VlmMediaInstanceStopped,
vlc.EventType.VlmMediaRemoved,
)
class AudioPlayer:
def __init__(self, alsa_device=None):

View File

@ -18,6 +18,7 @@ class EffectStatic
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
using ConfigType = EffectStaticConfig;
EffectStatic(const EffectStaticConfig &cfg, TLedStrip &ledStrip)
: config_(cfg),

View File

@ -104,12 +104,19 @@ enum class MessageHostToFw : uint8_t
LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 3,
LED_WHEEL_EFFECT_SWIPE_AND_CHANGE = 4,
LED_WHEEL_EFFECT_REVERSE_SWIPE = 5,
MOUSE_LED_EFFECT_STATIC = 6,
MOUSE_LED_EFFECT_CIRCULAR = 7,
MOUSE_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 8,
MOUSE_LED_EFFECT_SWIPE_AND_CHANGE = 9,
MOUSE_LED_EFFECT_REVERSE_SWIPE = 10,
SHELF_LED_EFFECT_STATIC = 15,
SHELF_LED_EFFECT_CIRCULAR = 16,
SHELF_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 17,
SHELF_LED_EFFECT_SWIPE_AND_CHANGE = 18,
SHELF_LED_EFFECT_REVERSE_SWIPE = 19,
PREV_BUTTON_LED = 20,
NEXT_BUTTON_LED = 21,
};
@ -158,8 +165,21 @@ void sendMessageToHost(const TMessage &msg)
Serial.write((uint8_t *)&msg, sizeof(msg));
}
template <typename LedTask1, typename LedTask2>
inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *ledTaskMouse, uint8_t ledChannelLeft, uint8_t ledChannelRight)
template <typename TEffectConfig, typename TLedTask>
inline bool handleLedEffect(TLedTask *ledTask, MessageHostToFw msgType, MessageHostToFw incomingMsgType, uint8_t *msgBuffer)
{
if (msgType == incomingMsgType)
{
auto cfg = reinterpret_cast<TEffectConfig *>(msgBuffer);
ledTask->startEffect(*cfg);
return true;
}
else
return false;
}
template <typename LedTask1, typename LedTask2, typename LedTaskShelf>
inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *ledTaskMouse, LedTaskShelf *ledTaskShelf, uint8_t ledChannelLeft, uint8_t ledChannelRight)
{
if (Serial.available() < sizeof(MAGIC_TOKEN_FW_TO_HOST) + sizeof(MessageHostToFw) + sizeof(uint16_t))
return;
@ -180,65 +200,35 @@ inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *le
static constexpr int maxIncomingBufferSize = 1024;
static uint8_t msgBuffer[maxIncomingBufferSize];
if (msgSize < maxIncomingBufferSize)
{
Serial.readBytes(msgBuffer, msgSize);
if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_STATIC)
{
auto cfg = reinterpret_cast<EffectStaticConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_ALEXA_SWIPE)
{
auto cfg = reinterpret_cast<EffectAlexaSwipeConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_CIRCULAR)
{
auto cfg = reinterpret_cast<EffectCircularConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION)
{
auto cfg = reinterpret_cast<EffectRandomTwoColorInterpolationConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE)
{
auto cfg = reinterpret_cast<EffectSwipeAndChangeConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::LED_WHEEL_EFFECT_REVERSE_SWIPE)
{
auto cfg = reinterpret_cast<EffectReverseSwipeConfig *>(msgBuffer);
ledTaskCircle->startEffect(*cfg);
}
//
else if (msgType == MessageHostToFw::MOUSE_LED_EFFECT_STATIC)
{
auto cfg = reinterpret_cast<EffectStaticConfig *>(msgBuffer);
ledTaskMouse->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::MOUSE_LED_EFFECT_CIRCULAR)
{
auto cfg = reinterpret_cast<EffectCircularConfig *>(msgBuffer);
ledTaskMouse->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::MOUSE_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION)
{
auto cfg = reinterpret_cast<EffectRandomTwoColorInterpolationConfig *>(msgBuffer);
ledTaskMouse->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::MOUSE_LED_EFFECT_SWIPE_AND_CHANGE)
{
auto cfg = reinterpret_cast<EffectSwipeAndChangeConfig *>(msgBuffer);
ledTaskMouse->startEffect(*cfg);
}
else if (msgType == MessageHostToFw::MOUSE_LED_EFFECT_REVERSE_SWIPE)
{
auto cfg = reinterpret_cast<EffectReverseSwipeConfig *>(msgBuffer);
ledTaskMouse->startEffect(*cfg);
}
// clang-format off
// LED Circle
if(handleLedEffect<EffectStaticConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_STATIC, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectAlexaSwipeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_ALEXA_SWIPE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectCircularConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectReverseSwipeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
// Mouse LEDs
else if(handleLedEffect<EffectStaticConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_STATIC, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectCircularConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectReverseSwipeConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
// Shelf LEDs
else if (handleLedEffect<EffectStaticConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_STATIC, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectCircularConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectReverseSwipeConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
// clang-format on
else if (msgType == MessageHostToFw::PREV_BUTTON_LED)
{
float *val = reinterpret_cast<float *>(msgBuffer);

View File

@ -166,7 +166,7 @@ void setupShelfLeds()
{
ledDriverShelf.begin(17, 2);
ledTaskShelf.begin(ledStripShelf, ledDriverShelf);
ledTaskShelf.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 30}, 0, 0});
ledTaskShelf.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0});
}
// -------------------------------------------------- Touch Buttons ----------------------------------------
@ -233,7 +233,7 @@ void setup()
void loop()
{
handleIncomingMessagesFromHost(&ledTaskCircle, &ledTaskMouse, 0, 1);
handleIncomingMessagesFromHost(&ledTaskCircle, &ledTaskMouse, &ledTaskShelf, 0, 1);
handleTouchInputs();
handleRotaryEncoder();
handleButtons();