From 3425f2bf3463d1752ab5f5f598526e149c20e749 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 11 Nov 2020 23:48:14 +0100 Subject: [PATCH] Add Playlist feature --- wled00/fcn_declare.h | 4 ++ wled00/json.cpp | 5 ++ wled00/playlist.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++ wled00/presets.cpp | 2 +- wled00/wled.cpp | 1 + wled00/wled.h | 2 + 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 wled00/playlist.cpp diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 035a4728..71ec9a00 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -147,6 +147,10 @@ void setCronixie(); void _overlayCronixie(); void _drawOverlayCronixie(); +//playlist.cpp +void loadPlaylist(JsonObject playlistObject); +void handlePlaylist(); + //presets.cpp bool applyPreset(byte index); void savePreset(byte index, bool persist = true, const char* pname = nullptr, JsonObject saveobj = JsonObject()); diff --git a/wled00/json.cpp b/wled00/json.cpp index 496bd6c5..be1a87e3 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -255,6 +255,11 @@ bool deserializeState(JsonObject root) } } + JsonObject playlist = root[F("playlist")]; + if (!playlist.isNull()) { + loadPlaylist(playlist); return stateResponse; + } + colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); return stateResponse; diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp new file mode 100644 index 00000000..d94126c9 --- /dev/null +++ b/wled00/playlist.cpp @@ -0,0 +1,106 @@ +#include "wled.h" + +/* + * Handles playlists, timed sequences of presets + */ + +typedef struct PlaylistEntry { + uint8_t preset; + uint16_t dur; + uint16_t tr; +} ple; + +byte playlistRepeat = 1; +byte playlistEndPreset = 0; + +uint8_t* playlistEntries; + +byte playlistLen; +int8_t playlistIndex = -1; + +uint16_t playlistEntryDur = 0; + +void loadPlaylist(JsonObject playlistObj) { + delete playlistEntries; + playlistIndex = -1; playlistEntryDur = 0; + JsonArray presets = playlistObj["ps"]; + playlistLen = presets.size(); + if (playlistLen == 0) return; + if (playlistLen > 100) playlistLen = 100; + uint16_t dataSize = sizeof(ple) * playlistLen; + playlistEntries = new byte[dataSize]; + PlaylistEntry* entries = reinterpret_cast(playlistEntries); + + byte it = 0; + for (int ps : presets) { + if (it >= playlistLen) break; + entries[it].preset = ps; + it++; + } + + it = 0; + JsonArray durations = playlistObj["dur"]; + if (durations.isNull()) { + entries[0].dur = playlistObj["dur"] | 100; + it = 1; + } else { + for (int dur : durations) { + if (it >= playlistLen) break; + entries[it].dur = dur; + it++; + } + } + for (int i = it; i < playlistLen; i++) entries[i].dur = entries[it -1].dur; + + it = 0; + JsonArray tr = playlistObj["transition"]; + if (tr.isNull()) { + entries[0].tr = playlistObj["transition"] | (transitionDelay / 100); + it = 1; + } else { + for (int transition : tr) { + if (it >= playlistLen) break; + entries[it].tr = transition; + it++; + } + } + for (int i = it; i < playlistLen; i++) entries[i].tr = entries[it -1].tr; + + playlistRepeat = playlistObj[F("repeat")] | 0; + playlistEndPreset = playlistObj[F("end")] | 0; + + currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved +} + +void handlePlaylist() +{ + if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return; + + if (millis() - presetCycledTime > (100*playlistEntryDur)) + { + presetCycledTime = millis(); + if (bri == 0 || nightlightActive) return; + + playlistIndex++; + if (playlistIndex >= playlistLen) { + playlistIndex = 0; + if (playlistRepeat == 1) { //stop + currentPlaylist = -1; + delete playlistEntries; + playlistEntries = nullptr; + if (playlistEndPreset) applyPreset(playlistEndPreset); + return; + } + if (playlistRepeat > 1) playlistRepeat--; + } + + PlaylistEntry* entries = reinterpret_cast(playlistEntries); + + jsonTransitionOnce = true; + transitionDelayTemp = entries[playlistIndex].tr * 100; + + applyPreset(entries[playlistIndex].preset); + playlistEntryDur = entries[playlistIndex].dur; + if (playlistEntryDur == 0) playlistEntryDur = 10; + } +} \ No newline at end of file diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 6a6e15da..e5e2015f 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -36,7 +36,7 @@ bool applyPreset(byte index) void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj) { - if (index == 0) return; + if (index == 0 || index > 250) return; bool docAlloc = fileDoc; JsonObject sObj = saveobj; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 27af9c38..dfcbf1ed 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -84,6 +84,7 @@ void WLED::loop() ArduinoOTA.handle(); #endif handleNightlight(); + handlePlaylist(); yield(); handleHue(); diff --git a/wled00/wled.h b/wled00/wled.h index 2f59cb51..3b4f1da1 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -436,6 +436,8 @@ WLED_GLOBAL unsigned long presetCycledTime _INIT(0); WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin); WLED_GLOBAL bool saveCurrPresetCycConf _INIT(false); +WLED_GLOBAL int16_t currentPlaylist _INIT(0); + // realtime WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE); WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);