Skip to content

Commit 623694a

Browse files
committed
Playlist additions
1 parent 374457d commit 623694a

File tree

7 files changed

+87
-46
lines changed

7 files changed

+87
-46
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
### Builds after release 0.12.0
44

5+
#### Build 2106100
6+
7+
- Added support for multiple buttons with various types (PR #1977)
8+
- Fixed infinite playlists (PR #2020)
9+
- Added `r` to playlist object, allows for shuffle regardless of the `repeat` value
10+
- Improved accuracy of NTP time sync
11+
- Added possibility for WLED UDP sync to sync system time
12+
- Improved UDP sync accuracy, if both sender and receiver are NTP synced
13+
- Fixed a cache issue with restored tabs
14+
- Cache CORS request
15+
- Disable WiFi sleep by default on ESP32
16+
517
#### Build 2105230
618

719
- No longer retain MQTT `/v` topic to alleviate storage loads on MQTT broker

wled00/const.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@
192192
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
193193
#define SEG_OPTION_TRANSITIONAL 7
194194

195+
//Playlist option byte
196+
#define PL_OPTION_SHUFFLE 0x01
197+
195198
// WLED Error modes
196199
#define ERR_NONE 0 // All good :)
197200
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)

wled00/fcn_declare.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ void handleIR();
9797
#include "src/dependencies/json/AsyncJson-v6.h"
9898
#include "FX.h"
9999

100-
void deserializeSegment(JsonObject elem, byte it);
101-
bool deserializeState(JsonObject root);
100+
void deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
101+
bool deserializeState(JsonObject root, byte presetId = 0);
102102
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
103103
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true);
104104
void serializeInfo(JsonObject root);
@@ -155,7 +155,7 @@ void _drawOverlayCronixie();
155155
//playlist.cpp
156156
void shufflePlaylist();
157157
void unloadPlaylist();
158-
void loadPlaylist(JsonObject playlistObject);
158+
void loadPlaylist(JsonObject playlistObject, byte presetId = 0);
159159
void handlePlaylist();
160160

161161
//presets.cpp

wled00/json.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* JSON API (De)serialization
77
*/
88

9-
void deserializeSegment(JsonObject elem, byte it)
9+
void deserializeSegment(JsonObject elem, byte it, byte presetId)
1010
{
1111
byte id = elem["id"] | it;
1212
if (id < strip.getMaxSegments())
@@ -95,13 +95,18 @@ void deserializeSegment(JsonObject elem, byte it)
9595

9696
//temporary, strip object gets updated via colorUpdated()
9797
if (id == strip.getMainSegmentId()) {
98+
byte effectPrev = effectCurrent;
9899
effectCurrent = elem[F("fx")] | effectCurrent;
100+
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
99101
effectSpeed = elem[F("sx")] | effectSpeed;
100102
effectIntensity = elem[F("ix")] | effectIntensity;
101103
effectPalette = elem["pal"] | effectPalette;
102104
} else { //permanent
103105
byte fx = elem[F("fx")] | seg.mode;
104-
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx);
106+
if (fx != seg.mode && fx < strip.getModeCount()) {
107+
strip.setMode(id, fx);
108+
if (!presetId) unloadPlaylist(); //stop playlist if active and FX changed manually
109+
}
105110
seg.speed = elem[F("sx")] | seg.speed;
106111
seg.intensity = elem[F("ix")] | seg.intensity;
107112
seg.palette = elem["pal"] | seg.palette;
@@ -156,7 +161,7 @@ void deserializeSegment(JsonObject elem, byte it)
156161
}
157162
}
158163

159-
bool deserializeState(JsonObject root)
164+
bool deserializeState(JsonObject root, byte presetId)
160165
{
161166
strip.applyToAllSelected = false;
162167
bool stateResponse = root[F("v")] | false;
@@ -168,12 +173,15 @@ bool deserializeState(JsonObject root)
168173

169174
if (root["on"].is<const char*>() && root["on"].as<const char*>()[0] == 't') toggleOnOff();
170175

171-
int tr = root[F("transition")] | -1;
172-
if (tr >= 0)
173-
{
174-
transitionDelay = tr;
175-
transitionDelay *= 100;
176-
transitionDelayTemp = transitionDelay;
176+
int tr = -1;
177+
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
178+
tr = root[F("transition")] | -1;
179+
if (tr >= 0)
180+
{
181+
transitionDelay = tr;
182+
transitionDelay *= 100;
183+
transitionDelayTemp = transitionDelay;
184+
}
177185
}
178186

179187
tr = root[F("tt")] | -1;
@@ -245,20 +253,20 @@ bool deserializeState(JsonObject root)
245253
{
246254
if (lowestActive == 99) lowestActive = s;
247255
if (sg.isSelected()) {
248-
deserializeSegment(segVar, s);
256+
deserializeSegment(segVar, s, presetId);
249257
didSet = true;
250258
}
251259
}
252260
}
253-
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive);
261+
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
254262
} else { //set only the segment with the specified ID
255-
deserializeSegment(segVar, it);
263+
deserializeSegment(segVar, it, presetId);
256264
}
257265
} else {
258266
JsonArray segs = segVar.as<JsonArray>();
259267
for (JsonObject elem : segs)
260268
{
261-
deserializeSegment(elem, it);
269+
deserializeSegment(elem, it, presetId);
262270
it++;
263271
}
264272
}
@@ -280,7 +288,11 @@ bool deserializeState(JsonObject root)
280288
deletePreset(ps);
281289
}
282290
ps = root["ps"] | -1; //load preset (clears state request!)
283-
if (ps >= 0) {applyPreset(ps); return stateResponse;}
291+
if (ps >= 0) {
292+
if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually
293+
applyPreset(ps);
294+
return stateResponse;
295+
}
284296

285297
//HTTP API commands
286298
const char* httpwin = root["win"];
@@ -293,7 +305,7 @@ bool deserializeState(JsonObject root)
293305

294306
JsonObject playlist = root[F("playlist")];
295307
if (!playlist.isNull()) {
296-
loadPlaylist(playlist);
308+
loadPlaylist(playlist, presetId);
297309
noNotification = true; //do not notify both for this request and the first playlist entry
298310
}
299311

@@ -309,7 +321,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
309321
root[F("start")] = seg.start;
310322
root["stop"] = seg.stop;
311323
}
312-
if (!forPreset) root[F("len")] = seg.stop - seg.start;
324+
if (!forPreset) root[F("len")] = seg.stop - seg.start;
313325
root[F("grp")] = seg.grouping;
314326
root[F("spc")] = seg.spacing;
315327
root["on"] = seg.getOption(SEG_OPTION_ON);

wled00/playlist.cpp

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55
*/
66

77
typedef struct PlaylistEntry {
8-
uint8_t preset;
9-
uint16_t dur;
10-
uint16_t tr;
8+
uint8_t preset; //ID of the preset to apply
9+
uint16_t dur; //Duration of the entry (in tenths of seconds)
10+
uint16_t tr; //Duration of the transition TO this entry (in tenths of seconds)
1111
} ple;
1212

13-
bool playlistEndless = false;
14-
int8_t playlistRepeat = 1;
15-
byte playlistEndPreset = 0;
13+
byte playlistRepeat = 1; //how many times to repeat the playlist (0 = infinitely)
14+
byte playlistEndPreset = 0; //what preset to apply after playlist end (0 = stay on last preset)
15+
byte playlistOptions = 0; //bit 0: shuffle playlist after each iteration. bits 1-7 TBD
16+
1617
PlaylistEntry *playlistEntries = nullptr;
17-
byte playlistLen;
18+
byte playlistLen; //number of playlist entries
1819
int8_t playlistIndex = -1;
19-
uint16_t playlistEntryDur = 0;
20+
uint16_t playlistEntryDur = 0; //duration of the current entry in tenths of seconds
21+
22+
//values we need to keep about the parent playlist while inside sub-playlist
23+
//int8_t parentPlaylistIndex = -1;
24+
//byte parentPlaylistRepeat = 0;
25+
//byte parentPlaylistPresetId = 0; //for re-loading
2026

2127

2228
void shufflePlaylist() {
@@ -42,12 +48,12 @@ void unloadPlaylist() {
4248
playlistEntries = nullptr;
4349
}
4450
currentPlaylist = playlistIndex = -1;
45-
playlistLen = playlistEntryDur = 0;
51+
playlistLen = playlistEntryDur = playlistOptions = 0;
4652
DEBUG_PRINTLN(F("Playlist unloaded."));
4753
}
4854

4955

50-
void loadPlaylist(JsonObject playlistObj) {
56+
void loadPlaylist(JsonObject playlistObj, byte presetId) {
5157
unloadPlaylist();
5258

5359
JsonArray presets = playlistObj["ps"];
@@ -68,12 +74,12 @@ void loadPlaylist(JsonObject playlistObj) {
6874
it = 0;
6975
JsonArray durations = playlistObj["dur"];
7076
if (durations.isNull()) {
71-
playlistEntries[0].dur = playlistObj["dur"] | 100;
77+
playlistEntries[0].dur = playlistObj["dur"] | 100; //10 seconds as fallback
7278
it = 1;
7379
} else {
7480
for (int dur : durations) {
7581
if (it >= playlistLen) break;
76-
playlistEntries[it].dur = (dur > 0) ? dur : presetCycleTime;
82+
playlistEntries[it].dur = (dur > 1) ? dur : 100;
7783
it++;
7884
}
7985
}
@@ -93,12 +99,19 @@ void loadPlaylist(JsonObject playlistObj) {
9399
}
94100
for (int i = it; i < playlistLen; i++) playlistEntries[i].tr = playlistEntries[it -1].tr;
95101

96-
playlistRepeat = playlistObj[F("repeat")] | 0;
97-
playlistEndPreset = playlistObj[F("end")] | 0;
102+
int rep = playlistObj[F("repeat")];
103+
bool shuffle = false;
104+
if (rep < 0) { //support negative values as infinite + shuffle
105+
rep = 0; shuffle = true;
106+
}
98107

99-
if (playlistRepeat <= 0) playlistRepeat--; // make it endless (-2 == endless & random)
108+
playlistRepeat = rep;
109+
if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start
110+
playlistEndPreset = playlistObj[F("end")] | 0;
111+
shuffle = shuffle || playlistObj["r"];
112+
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE;
100113

101-
currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved
114+
currentPlaylist = presetId;
102115
DEBUG_PRINTLN(F("Playlist loaded."));
103116
}
104117

@@ -112,16 +125,16 @@ void handlePlaylist() {
112125

113126
++playlistIndex %= playlistLen; // -1 at 1st run (limit to playlistLen)
114127

115-
if (!playlistRepeat && !playlistIndex) { //stop if repeat == 0 and restart of playlist
116-
unloadPlaylist();
117-
if (playlistEndPreset) applyPreset(playlistEndPreset);
118-
return;
119-
}
120128
// playlist roll-over
121129
if (!playlistIndex) {
122-
// playlistRepeat < 0 => endless loop
123-
if (playlistRepeat > 0) playlistRepeat--; // decrease repeat count on each index reset if not an endless playlist
124-
if (playlistRepeat < -1) shufflePlaylist(); // shuffle playlist and start over
130+
if (playlistRepeat == 1) { //stop if all repetitions are done
131+
unloadPlaylist();
132+
if (playlistEndPreset) applyPreset(playlistEndPreset);
133+
return;
134+
}
135+
if (playlistRepeat > 1) playlistRepeat--; // decrease repeat count on each index reset if not an endless playlist
136+
// playlistRepeat == 0: endless loop
137+
if (playlistOptions & PL_OPTION_SHUFFLE) shufflePlaylist(); // shuffle playlist and start over
125138
}
126139

127140
jsonTransitionOnce = true;

wled00/presets.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bool applyPreset(byte index)
1414
#ifdef WLED_DEBUG_FS
1515
serializeJson(*fileDoc, Serial);
1616
#endif
17-
deserializeState(fdo);
17+
deserializeState(fdo, index);
1818
} else {
1919
DEBUGFS_PRINTLN(F("Make read buf"));
2020
DynamicJsonDocument fDoc(JSON_BUFFER_SIZE);
@@ -24,7 +24,7 @@ bool applyPreset(byte index)
2424
#ifdef WLED_DEBUG_FS
2525
serializeJson(fDoc, Serial);
2626
#endif
27-
deserializeState(fdo);
27+
deserializeState(fdo, index);
2828
}
2929

3030
if (!errorFlag) {
@@ -35,6 +35,7 @@ bool applyPreset(byte index)
3535
return false;
3636
}
3737

38+
//persist=false is not currently honored
3839
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
3940
{
4041
if (index == 0 || index > 250) return;

wled00/wled.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
// version code in format yymmddb (b = daily build)
11-
#define VERSION 2106070
11+
#define VERSION 2106100
1212

1313
//uncomment this if you have a "my_config.h" file you'd like to use
1414
//#define WLED_USE_MY_CONFIG

0 commit comments

Comments
 (0)