FastLED 3.9.15
Loading...
Searching...
No Matches
wled.cpp.hpp
Go to the documentation of this file.
1// ok no header
2#include "fl/fx/wled.h"
3#include "fl/log/log.h"
4#include "fl/log/log.h"
5namespace fl {
6
7// WLED Constructor and Stub Implementations
8
10 : Remote(
11 [this]() { return stubRequestSource(); },
12 [this](const fl::json& response) { stubResponseSink(response); }
13 ) {}
14
16 FL_ERROR("WLED::stubRequestSource: Not implemented - provide a real RequestSource callback");
17 return fl::nullopt;
18}
19
20void WLED::stubResponseSink(const fl::json& response) {
21 FL_ERROR("WLED::stubResponseSink: Not implemented - provide a real ResponseSink callback");
22}
23
24// WLED State Management
25
26void WLED::setState(const fl::json& wledState) {
27 if (!wledState.has_value()) {
28 FL_WARN("WLED: setState called with invalid JSON");
29 return;
30 }
31
32 // Extract "on" field (bool) - optional, keep existing if missing
33 if (wledState.contains("on") && wledState["on"].is_bool()) {
34 bool newOn = wledState["on"] | mWledOn;
35 if (newOn != mWledOn) {
36 mWledOn = newOn;
37 FL_DBG("WLED: on=" << (mWledOn ? "true" : "false"));
38 }
39 }
40
41 // Extract "bri" field (0-255) - optional, keep existing if missing
42 if (wledState.contains("bri")) {
43 if (wledState["bri"].is_int()) {
44 i64 briInt = wledState["bri"] | static_cast<i64>(mWledBri);
45 // Clamp to valid range 0-255
46 if (briInt < 0) {
47 FL_WARN("WLED: brightness " << briInt << " out of range, clamping to 0");
48 briInt = 0;
49 } else if (briInt > 255) {
50 FL_WARN("WLED: brightness " << briInt << " out of range, clamping to 255");
51 briInt = 255;
52 }
53 u8 newBri = static_cast<u8>(briInt);
54 if (newBri != mWledBri) {
55 mWledBri = newBri;
56 FL_DBG("WLED: bri=" << static_cast<int>(mWledBri));
57 }
58 } else {
59 FL_WARN("WLED: 'bri' field has invalid type (expected int)");
60 }
61 }
62
63 // Extract "transition" field (0-65535) - optional, keep existing if missing
64 if (wledState.contains("transition")) {
65 if (wledState["transition"].is_int()) {
66 i64 transInt = wledState["transition"] | static_cast<i64>(mTransition);
67 // Clamp to valid range 0-65535
68 if (transInt < 0) {
69 FL_WARN("WLED: transition " << transInt << " out of range, clamping to 0");
70 transInt = 0;
71 } else if (transInt > 65535) {
72 FL_WARN("WLED: transition " << transInt << " out of range, clamping to 65535");
73 transInt = 65535;
74 }
75 u16 newTransition = static_cast<u16>(transInt);
76 if (newTransition != mTransition) {
77 mTransition = newTransition;
78 FL_DBG("WLED: transition=" << mTransition);
79 }
80 } else {
81 FL_WARN("WLED: 'transition' field has invalid type (expected int)");
82 }
83 }
84
85 // Extract "ps" field (preset ID: -1 to 250) - optional, keep existing if missing
86 if (wledState.contains("ps")) {
87 if (wledState["ps"].is_int()) {
88 i64 psInt = wledState["ps"] | static_cast<i64>(mPreset);
89 // Clamp to valid range -1 to 250
90 if (psInt < -1) {
91 FL_WARN("WLED: preset " << psInt << " out of range, clamping to -1");
92 psInt = -1;
93 } else if (psInt > 250) {
94 FL_WARN("WLED: preset " << psInt << " out of range, clamping to 250");
95 psInt = 250;
96 }
97 i16 newPreset = static_cast<i16>(psInt);
98 if (newPreset != mPreset) {
99 mPreset = newPreset;
100 FL_DBG("WLED: ps=" << mPreset);
101 }
102 } else {
103 FL_WARN("WLED: 'ps' field has invalid type (expected int)");
104 }
105 }
106
107 // Extract "pl" field (playlist ID: -1 to 250) - optional, keep existing if missing
108 if (wledState.contains("pl")) {
109 if (wledState["pl"].is_int()) {
110 i64 plInt = wledState["pl"] | static_cast<i64>(mPlaylist);
111 // Clamp to valid range -1 to 250
112 if (plInt < -1) {
113 FL_WARN("WLED: playlist " << plInt << " out of range, clamping to -1");
114 plInt = -1;
115 } else if (plInt > 250) {
116 FL_WARN("WLED: playlist " << plInt << " out of range, clamping to 250");
117 plInt = 250;
118 }
119 i16 newPlaylist = static_cast<i16>(plInt);
120 if (newPlaylist != mPlaylist) {
121 mPlaylist = newPlaylist;
122 FL_DBG("WLED: pl=" << mPlaylist);
123 }
124 } else {
125 FL_WARN("WLED: 'pl' field has invalid type (expected int)");
126 }
127 }
128
129 // Extract "lor" field (live override: 0-2) - optional, keep existing if missing
130 if (wledState.contains("lor")) {
131 if (wledState["lor"].is_int()) {
132 i64 lorInt = wledState["lor"] | static_cast<i64>(mLiveOverride);
133 // Clamp to valid range 0-2
134 if (lorInt < 0) {
135 FL_WARN("WLED: live override " << lorInt << " out of range, clamping to 0");
136 lorInt = 0;
137 } else if (lorInt > 2) {
138 FL_WARN("WLED: live override " << lorInt << " out of range, clamping to 2");
139 lorInt = 2;
140 }
141 u8 newLiveOverride = static_cast<u8>(lorInt);
142 if (newLiveOverride != mLiveOverride) {
143 mLiveOverride = newLiveOverride;
144 FL_DBG("WLED: lor=" << static_cast<int>(mLiveOverride));
145 }
146 } else {
147 FL_WARN("WLED: 'lor' field has invalid type (expected int)");
148 }
149 }
150
151 // Extract "mainseg" field (main segment: 0-255) - optional, keep existing if missing
152 if (wledState.contains("mainseg")) {
153 if (wledState["mainseg"].is_int()) {
154 i64 mainsegInt = wledState["mainseg"] | static_cast<i64>(mMainSegment);
155 // Clamp to valid range 0-255
156 if (mainsegInt < 0) {
157 FL_WARN("WLED: main segment " << mainsegInt << " out of range, clamping to 0");
158 mainsegInt = 0;
159 } else if (mainsegInt > 255) {
160 FL_WARN("WLED: main segment " << mainsegInt << " out of range, clamping to 255");
161 mainsegInt = 255;
162 }
163 u8 newMainSegment = static_cast<u8>(mainsegInt);
164 if (newMainSegment != mMainSegment) {
165 mMainSegment = newMainSegment;
166 FL_DBG("WLED: mainseg=" << static_cast<int>(mMainSegment));
167 }
168 } else {
169 FL_WARN("WLED: 'mainseg' field has invalid type (expected int)");
170 }
171 }
172
173 // Extract "nl" field (nightlight object) - optional
174 if (wledState.contains("nl")) {
175 if (wledState["nl"].is_object()) {
176 const fl::json& nl = wledState["nl"];
177
178 // Extract "on" field (bool)
179 if (nl.contains("on") && nl["on"].is_bool()) {
180 bool newNlOn = nl["on"] | mNightlightOn;
181 if (newNlOn != mNightlightOn) {
182 mNightlightOn = newNlOn;
183 FL_DBG("WLED: nl.on=" << (mNightlightOn ? "true" : "false"));
184 }
185 }
186
187 // Extract "dur" field (1-255 minutes)
188 if (nl.contains("dur")) {
189 if (nl["dur"].is_int()) {
190 i64 durInt = nl["dur"] | static_cast<i64>(mNightlightDuration);
191 // Clamp to valid range 1-255
192 if (durInt < 1) {
193 FL_WARN("WLED: nl.dur " << durInt << " out of range, clamping to 1");
194 durInt = 1;
195 } else if (durInt > 255) {
196 FL_WARN("WLED: nl.dur " << durInt << " out of range, clamping to 255");
197 durInt = 255;
198 }
199 u8 newDur = static_cast<u8>(durInt);
200 if (newDur != mNightlightDuration) {
201 mNightlightDuration = newDur;
202 FL_DBG("WLED: nl.dur=" << static_cast<int>(mNightlightDuration));
203 }
204 } else {
205 FL_WARN("WLED: 'nl.dur' field has invalid type (expected int)");
206 }
207 }
208
209 // Extract "mode" field (0-3)
210 if (nl.contains("mode")) {
211 if (nl["mode"].is_int()) {
212 i64 modeInt = nl["mode"] | static_cast<i64>(mNightlightMode);
213 // Clamp to valid range 0-3
214 if (modeInt < 0) {
215 FL_WARN("WLED: nl.mode " << modeInt << " out of range, clamping to 0");
216 modeInt = 0;
217 } else if (modeInt > 3) {
218 FL_WARN("WLED: nl.mode " << modeInt << " out of range, clamping to 3");
219 modeInt = 3;
220 }
221 u8 newMode = static_cast<u8>(modeInt);
222 if (newMode != mNightlightMode) {
223 mNightlightMode = newMode;
224 FL_DBG("WLED: nl.mode=" << static_cast<int>(mNightlightMode));
225 }
226 } else {
227 FL_WARN("WLED: 'nl.mode' field has invalid type (expected int)");
228 }
229 }
230
231 // Extract "tbri" field (0-255 target brightness)
232 if (nl.contains("tbri")) {
233 if (nl["tbri"].is_int()) {
234 i64 tbriInt = nl["tbri"] | static_cast<i64>(mNightlightTargetBrightness);
235 // Clamp to valid range 0-255
236 if (tbriInt < 0) {
237 FL_WARN("WLED: nl.tbri " << tbriInt << " out of range, clamping to 0");
238 tbriInt = 0;
239 } else if (tbriInt > 255) {
240 FL_WARN("WLED: nl.tbri " << tbriInt << " out of range, clamping to 255");
241 tbriInt = 255;
242 }
243 u8 newTbri = static_cast<u8>(tbriInt);
244 if (newTbri != mNightlightTargetBrightness) {
246 FL_DBG("WLED: nl.tbri=" << static_cast<int>(mNightlightTargetBrightness));
247 }
248 } else {
249 FL_WARN("WLED: 'nl.tbri' field has invalid type (expected int)");
250 }
251 }
252 } else {
253 FL_WARN("WLED: 'nl' field has invalid type (expected object)");
254 }
255 }
256
257 // Extract "udpn" field (UDP sync settings) - optional
258 if (wledState.contains("udpn")) {
259 if (wledState["udpn"].is_object()) {
260 const fl::json& udpn = wledState["udpn"];
261
262 // Extract "send" field (bool)
263 if (udpn.contains("send") && udpn["send"].is_bool()) {
264 bool newSend = udpn["send"] | mUdpSend;
265 if (newSend != mUdpSend) {
266 mUdpSend = newSend;
267 FL_DBG("WLED: udpn.send=" << (mUdpSend ? "true" : "false"));
268 }
269 }
270
271 // Extract "recv" field (bool)
272 if (udpn.contains("recv") && udpn["recv"].is_bool()) {
273 bool newRecv = udpn["recv"] | mUdpReceive;
274 if (newRecv != mUdpReceive) {
275 mUdpReceive = newRecv;
276 FL_DBG("WLED: udpn.recv=" << (mUdpReceive ? "true" : "false"));
277 }
278 }
279 } else {
280 FL_WARN("WLED: 'udpn' field has invalid type (expected object)");
281 }
282 }
283
284 // Extract "playlist" field (playlist configuration) - optional
285 if (wledState.contains("playlist")) {
286 if (wledState["playlist"].is_object()) {
287 const fl::json& pl = wledState["playlist"];
288
289 // Extract "ps" field (array of preset IDs)
290 if (pl.contains("ps") && pl["ps"].is_array()) {
291 mPlaylistPresets.clear();
292 for (size_t i = 0; i < pl["ps"].size(); i++) {
293 if (pl["ps"][i].is_int()) {
294 i64 psInt = pl["ps"][i] | -1;
295 // Clamp to valid range -1 to 250
296 if (psInt < -1) psInt = -1;
297 if (psInt > 250) psInt = 250;
298 mPlaylistPresets.push_back(static_cast<i16>(psInt));
299 }
300 }
301 FL_DBG("WLED: playlist.ps count=" << mPlaylistPresets.size());
302 }
303
304 // Extract "dur" field (array of durations in seconds)
305 if (pl.contains("dur") && pl["dur"].is_array()) {
306 mPlaylistDurations.clear();
307 for (size_t i = 0; i < pl["dur"].size(); i++) {
308 if (pl["dur"][i].is_int()) {
309 i64 durInt = pl["dur"][i] | 0;
310 if (durInt < 0) durInt = 0;
311 if (durInt > 65535) durInt = 65535;
312 mPlaylistDurations.push_back(static_cast<u16>(durInt));
313 }
314 }
315 }
316
317 // Extract "transition" field (array of transitions in ×100ms)
318 if (pl.contains("transition") && pl["transition"].is_array()) {
319 mPlaylistTransitions.clear();
320 for (size_t i = 0; i < pl["transition"].size(); i++) {
321 if (pl["transition"][i].is_int()) {
322 i64 transInt = pl["transition"][i] | 0;
323 if (transInt < 0) transInt = 0;
324 if (transInt > 65535) transInt = 65535;
325 mPlaylistTransitions.push_back(static_cast<u16>(transInt));
326 }
327 }
328 }
329
330 // Extract "repeat" field
331 if (pl.contains("repeat") && pl["repeat"].is_int()) {
332 i64 repeatInt = pl["repeat"] | 0;
333 if (repeatInt < 0) repeatInt = 0;
334 if (repeatInt > 65535) repeatInt = 65535;
335 mPlaylistRepeat = static_cast<u16>(repeatInt);
336 FL_DBG("WLED: playlist.repeat=" << mPlaylistRepeat);
337 }
338
339 // Extract "end" field
340 if (pl.contains("end") && pl["end"].is_int()) {
341 i64 endInt = pl["end"] | -1;
342 if (endInt < -1) endInt = -1;
343 if (endInt > 250) endInt = 250;
344 mPlaylistEnd = static_cast<i16>(endInt);
345 FL_DBG("WLED: playlist.end=" << mPlaylistEnd);
346 }
347
348 // Extract "r" field (randomize)
349 if (pl.contains("r") && pl["r"].is_bool()) {
350 mPlaylistRandomize = pl["r"] | false;
351 FL_DBG("WLED: playlist.r=" << (mPlaylistRandomize ? "true" : "false"));
352 }
353 } else {
354 FL_WARN("WLED: 'playlist' field has invalid type (expected object)");
355 }
356 }
357
358 // Extract "seg" field (segment array) - optional
359 if (wledState.contains("seg")) {
360 if (wledState["seg"].is_array()) {
361 for (size_t i = 0; i < wledState["seg"].size(); i++) {
362 const fl::json& segJson = wledState["seg"][i];
363 if (!segJson.is_object()) {
364 FL_WARN("WLED: segment at index " << i << " is not an object");
365 continue;
366 }
367
368 // Extract segment ID (required for updates)
369 u8 segId = 0;
370 if (segJson.contains("id") && segJson["id"].is_int()) {
371 i64 idInt = segJson["id"] | 0;
372 if (idInt < 0) idInt = 0;
373 if (idInt > 255) idInt = 255;
374 segId = static_cast<u8>(idInt);
375 } else {
376 // If no ID provided, use index
377 segId = static_cast<u8>(i);
378 }
379
380 // Find existing segment or create new one
381 WLEDSegment* seg = nullptr;
382 for (size_t j = 0; j < mSegments.size(); j++) {
383 if (mSegments[j].mId == segId) {
384 seg = &mSegments[j];
385 break;
386 }
387 }
388 if (!seg) {
389 // Create new segment
390 WLEDSegment newSeg;
391 newSeg.mId = segId;
392 mSegments.push_back(newSeg);
393 seg = &mSegments[mSegments.size() - 1];
394 }
395
396 // Parse segment fields using helper function
397 wled::parseSegmentFields(segJson, *seg);
398 }
399 } else {
400 FL_WARN("WLED: 'seg' field has invalid type (expected array)");
401 }
402 }
403}
404
407 state.set("on", mWledOn);
408 state.set("bri", static_cast<i64>(mWledBri));
409 state.set("transition", static_cast<i64>(mTransition));
410 state.set("ps", static_cast<i64>(mPreset));
411 state.set("pl", static_cast<i64>(mPlaylist));
412 state.set("lor", static_cast<i64>(mLiveOverride));
413 state.set("mainseg", static_cast<i64>(mMainSegment));
414
415 // Nightlight object
417 nl.set("on", mNightlightOn);
418 nl.set("dur", static_cast<i64>(mNightlightDuration));
419 nl.set("mode", static_cast<i64>(mNightlightMode));
420 nl.set("tbri", static_cast<i64>(mNightlightTargetBrightness));
421 state.set("nl", nl);
422
423 // UDP sync settings
424 fl::json udpn = fl::json::object();
425 udpn.set("send", mUdpSend);
426 udpn.set("recv", mUdpReceive);
427 state.set("udpn", udpn);
428
429 // Playlist configuration (if present)
430 if (hasPlaylistConfig()) {
431 state.set("playlist", getPlaylistConfig());
432 }
433
434 // Segments
435 if (!mSegments.empty()) {
436 fl::json segments = fl::json::array();
437 for (const auto& seg : mSegments) {
438 fl::json segJson = fl::json::object();
439
440 segJson.set("id", static_cast<i64>(seg.mId));
441 segJson.set("start", static_cast<i64>(seg.mStart));
442 segJson.set("stop", static_cast<i64>(seg.mStop));
443 segJson.set("len", static_cast<i64>(seg.mLen));
444 segJson.set("grp", static_cast<i64>(seg.mGrp));
445 segJson.set("spc", static_cast<i64>(seg.mSpc));
446 segJson.set("of", static_cast<i64>(seg.mOf));
447 segJson.set("on", seg.mOn);
448 segJson.set("bri", static_cast<i64>(seg.mBri));
449 segJson.set("cct", static_cast<i64>(seg.mCct));
450
451 // Effect properties
452 segJson.set("fx", static_cast<i64>(seg.mFx));
453 segJson.set("sx", static_cast<i64>(seg.mSx));
454 segJson.set("ix", static_cast<i64>(seg.mIx));
455 segJson.set("pal", static_cast<i64>(seg.mPal));
456 segJson.set("c1", static_cast<i64>(seg.mC1));
457 segJson.set("c2", static_cast<i64>(seg.mC2));
458 segJson.set("c3", static_cast<i64>(seg.mC3));
459
460 // Boolean flags
461 segJson.set("sel", seg.mSel);
462 segJson.set("rev", seg.mRev);
463 segJson.set("mi", seg.mMi);
464 segJson.set("o1", seg.mO1);
465 segJson.set("o2", seg.mO2);
466 segJson.set("o3", seg.mO3);
467 segJson.set("si", static_cast<i64>(seg.mSi));
468 segJson.set("m12", static_cast<i64>(seg.mM12));
469 segJson.set("rpt", seg.mRpt);
470
471 if (!seg.mName.empty()) {
472 segJson.set("n", seg.mName);
473 }
474
475 // Colors
476 if (!seg.mColors.empty()) {
477 fl::json colors = fl::json::array();
478 for (const auto& color : seg.mColors) {
479 if (color.size() >= 3) {
480 fl::json colorArray = fl::json::array();
481 for (size_t i = 0; i < color.size(); i++) {
482 colorArray.push_back(fl::json(static_cast<i64>(color[i])));
483 }
484 colors.push_back(colorArray);
485 }
486 }
487 segJson.set("col", colors);
488 }
489
490 // Individual LEDs
491 if (!seg.mIndividualLeds.empty()) {
493 for (const auto& led : seg.mIndividualLeds) {
494 if (led.size() >= 3) {
495 fl::string hexColor = wled::rgbToHex(led[0], led[1], led[2]);
496 leds.push_back(fl::json(hexColor.c_str()));
497 }
498 }
499 segJson.set("i", leds);
500 }
501
502 segments.push_back(segJson);
503 }
504 state.set("seg", segments);
505 }
506
507 return state;
508}
509
511 fl::json playlist = fl::json::object();
512
513 // Preset IDs
514 if (!mPlaylistPresets.empty()) {
516 for (const auto& preset : mPlaylistPresets) {
517 ps.push_back(fl::json(static_cast<i64>(preset)));
518 }
519 playlist.set("ps", ps);
520 }
521
522 // Durations
523 if (!mPlaylistDurations.empty()) {
525 for (const auto& duration : mPlaylistDurations) {
526 dur.push_back(fl::json(static_cast<i64>(duration)));
527 }
528 playlist.set("dur", dur);
529 }
530
531 // Transitions
532 if (!mPlaylistTransitions.empty()) {
533 fl::json trans = fl::json::array();
534 for (const auto& transition : mPlaylistTransitions) {
535 trans.push_back(fl::json(static_cast<i64>(transition)));
536 }
537 playlist.set("transition", trans);
538 }
539
540 // Other properties
541 playlist.set("repeat", static_cast<i64>(mPlaylistRepeat));
542 playlist.set("end", static_cast<i64>(mPlaylistEnd));
543 playlist.set("r", mPlaylistRandomize);
544
545 return playlist;
546}
547
549 for (const auto& seg : mSegments) {
550 if (seg.mId == id) {
551 return &seg;
552 }
553 }
554 return nullptr;
555}
556
557} // namespace fl
fl::CRGB leds[NUM_LEDS]
TestState state
Remote(RequestSource source, ResponseSink sink)
Construct with I/O callbacks.
fl::json getPlaylistConfig() const
Get playlist configuration.
Definition wled.cpp.hpp:510
fl::vector< u16 > mPlaylistDurations
Definition wled.h:448
void setState(const fl::json &wledState)
Set WLED state from JSON object.
Definition wled.cpp.hpp:26
bool mNightlightOn
Definition wled.h:441
fl::vector< u16 > mPlaylistTransitions
Definition wled.h:449
u8 mWledBri
Definition wled.h:433
i16 mPlaylistEnd
Definition wled.h:451
void stubResponseSink(const fl::json &response)
Stub response sink callback.
Definition wled.cpp.hpp:20
fl::optional< fl::json > stubRequestSource()
Stub request source callback.
Definition wled.cpp.hpp:15
u8 mLiveOverride
Definition wled.h:437
u16 mTransition
Definition wled.h:434
u8 mNightlightTargetBrightness
Definition wled.h:444
u8 mNightlightDuration
Definition wled.h:442
bool mUdpSend
Definition wled.h:455
bool mUdpReceive
Definition wled.h:456
i16 mPreset
Definition wled.h:435
i16 mPlaylist
Definition wled.h:436
fl::vector< i16 > mPlaylistPresets
Definition wled.h:447
WLED() FL_NOEXCEPT
Construct WLED with default stub I/O callbacks.
Definition wled.cpp.hpp:9
bool mWledOn
Definition wled.h:432
bool mPlaylistRandomize
Definition wled.h:452
u16 mPlaylistRepeat
Definition wled.h:450
fl::vector< WLEDSegment > mSegments
Definition wled.h:459
u8 mMainSegment
Definition wled.h:438
fl::json getState() const
Get current WLED state as JSON object.
Definition wled.cpp.hpp:405
u8 mNightlightMode
Definition wled.h:443
const WLEDSegment * findSegmentById(u8 id) const
Find segment by ID.
Definition wled.cpp.hpp:548
bool hasPlaylistConfig() const
Check if playlist is active.
Definition wled.h:372
const char * c_str() const FL_NOEXCEPT
void push_back(const json &value) FL_NOEXCEPT
Definition json.h:745
bool is_array() const FL_NOEXCEPT
Definition json.h:246
bool is_int() const FL_NOEXCEPT
Definition json.h:240
bool has_value() const FL_NOEXCEPT
Definition json.h:654
bool is_object() const FL_NOEXCEPT
Definition json.h:248
size_t size() const FL_NOEXCEPT
Definition json.h:633
bool is_bool() const FL_NOEXCEPT
Definition json.h:239
bool contains(size_t idx) const FL_NOEXCEPT
Definition json.h:625
void set(const fl::string &key, const json &value) FL_NOEXCEPT
Definition json.h:701
static json object() FL_NOEXCEPT
Definition json.h:692
static json array() FL_NOEXCEPT
Definition json.h:688
fl::UISlider transition("Transition", 0.0f, 0.0f, 1.0f, 0.01f)
P ps[MAXP]
Definition Luminova.h:57
#define FL_WARN(X)
Definition log.h:276
#define FL_ERROR(X)
Definition log.h:219
#define FL_DBG
Definition log.h:388
Centralized logging categories for FastLED hardware interfaces and subsystems.
void parseSegmentFields(const fl::json &segJson, WLEDSegment &seg)
Parse all fields from a segment JSON object into a WLEDSegment.
fl::string rgbToHex(u8 r, u8 g, u8 b)
Convert RGB components to hex string.
unsigned char u8
Definition stdint.h:131
Optional< T > optional
Definition optional.h:16
fl::i64 i64
Definition s16x16x4.h:222
constexpr nullopt_t nullopt
Definition optional.h:13
Base definition for an LED controller.
Definition crgb.hpp:179
WLED segment configuration.
Definition segment.h:15