Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions wled00/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(analogClock5MinuteMarks, ol[F("o5m")]);
CJSON(analogClockSecondsTrail, ol[F("osec")]);

CJSON(digitalLedPerSegment, ol[F("lps")]);
CJSON(digitalColon, ol[F("dc")]);

//timed macro rules
JsonObject tm = doc[F("timers")];
JsonObject cntdwn = tm[F("cntdwn")];
Expand Down
816 changes: 408 additions & 408 deletions wled00/data/settings_leds.htm

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions wled00/data/settings_time.htm
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@
{
return d.getElementById(s);
}
function gId(s)
{
return d.getElementById(s);
}
function Cs()
{
gId("cac").style.display="none";
gId("coc").style.display="block";
gId("ccc").style.display="none";
gId("cdc").style.display="none";

if (gId("ca").selected)
{
gId("cac").style.display="block";
Expand All @@ -36,6 +42,11 @@
gId("coc").style.display="none";
gId("ccc").style.display="block";
}
if (gId("cd").selected)
{
gId("coc").style.display="none";
gId("cdc").style.display="block";
}
if (gId("cn").selected)
{
gId("coc").style.display="none";
Expand Down Expand Up @@ -141,6 +152,7 @@ <h3>Clock</h3>
<option value="1" id="ca">Analog Clock</option>
<option value="2">Single Digit Clock</option>
<option value="3" id="cc">Cronixie Clock</option>
<option value="4" id="cd">Digital Clock</option>
</select><br>
<div id="coc">
First LED: <input name="O1" type="number" min="0" max="255" required> Last LED: <input name="O2" type="number" min="0" max="255" required><br>
Expand All @@ -153,6 +165,10 @@ <h3>Clock</h3>
Cronixie Display: <input name="CX" maxlength="6"><br>
Cronixie Backlight: <input type="checkbox" name="CB"><br>
</div>
<div id="cdc">
LED per segment: <input name="DL" type="number" min="0" max="255" value="7"><br>
Colon led's between hours and minutes: <input type="number" name="DC" min="0" max="255" value="4"><br></div>
</div>
Countdown Mode: <input type="checkbox" name="CE"><br>
Countdown Goal:<br>
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
Expand Down
34 changes: 19 additions & 15 deletions wled00/html_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ type="submit">Save</button></form></body></html>)=====";
// Autogenerated from wled00/data/settings_time.htm, do not edit!!
const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=500">
<meta charset="utf-8"><title>Time Settings</title><script>
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings")}function B(){window.open("/settings","_self")}function S(){BTa(),GetV(),Cs(),FC()}function gId(t){return d.getElementById(t)}function Cs(){gId("cac").style.display="none",gId("coc").style.display="block",gId("ccc").style.display="none",gId("ca").selected&&(gId("cac").style.display="block"),gId("cc").selected&&(gId("coc").style.display="none",gId("ccc").style.display="block"),gId("cn").selected&&(gId("coc").style.display="none")}function BTa(){var t="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for(i=0;i<8;i++)for(t+='<tr><td><input name="W'+i+'" id="W'+i+'" type="number" style="display:none"><input id="W'+i+'0" type="checkbox"></td><td><input name="H'+i+'" type="number" min="0" max="24"></td><td><input name="N'+i+'" type="number" min="0" max="59"></td><td><input name="T'+i+'" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W'+i+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W8" id="W8" type="number" style="display:none"><input id="W80" type="checkbox"></td><td>Sunrise<input name="H8" value="255" type="hidden"></td><td><input name="N8" type="number" min="-59" max="59"></td><td><input name="T8" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W8'+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W9" id="W9" type="number" style="display:none"><input id="W90" type="checkbox"></td><td>Sunset<input name="H9" value="255" type="hidden"></td><td><input name="N9" type="number" min="-59" max="59"><td><input name="T9" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W9'+j+'" type="checkbox"></td>';gId("TMT").innerHTML=t}function FC(){for(j=0;j<8;j++)for(i=0;i<10;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1}function Wd(){for(a=[0,0,0,0,0,0,0,0,0,0],i=0;i<10;i++){for(m=1,j=0;j<8;j++)a[i]+=gId("W"+i+j).checked*m,m*=2;gId("W"+i).value=a[i]}}function addRow(t,e,n,i){var d=gId("macros"),u=d.rows.length,c=d.insertRow(u);document.createElement("td");c.insertCell(0).innerHTML=`Button ${t}:`,c.insertCell(1).innerHTML=`<input name="MP${t}" type="number" min="0" max="250" value="${e}" required>`,c.insertCell(2).innerHTML=`<input name="ML${t}" type="number" min="0" max="250" value="${n}" required>`,c.insertCell(3).innerHTML=`<input name="MD${t}" type="number" min="0" max="250" value="${i}" required>`}function GetV() {
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings")}function B(){window.open("/settings","_self")}function S(){BTa(),GetV(),Cs(),FC()}function gId(t){return d.getElementById(t)}function gId(t){return d.getElementById(t)}function Cs(){gId("cac").style.display="none",gId("coc").style.display="block",gId("ccc").style.display="none",gId("cdc").style.display="none",gId("ca").selected&&(gId("cac").style.display="block"),gId("cc").selected&&(gId("coc").style.display="none",gId("ccc").style.display="block"),gId("cd").selected&&(gId("coc").style.display="none",gId("cdc").style.display="block"),gId("cn").selected&&(gId("coc").style.display="none")}function BTa(){var t="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for(i=0;i<8;i++)for(t+='<tr><td><input name="W'+i+'" id="W'+i+'" type="number" style="display:none"><input id="W'+i+'0" type="checkbox"></td><td><input name="H'+i+'" type="number" min="0" max="24"></td><td><input name="N'+i+'" type="number" min="0" max="59"></td><td><input name="T'+i+'" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W'+i+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W8" id="W8" type="number" style="display:none"><input id="W80" type="checkbox"></td><td>Sunrise<input name="H8" value="255" type="hidden"></td><td><input name="N8" type="number" min="-59" max="59"></td><td><input name="T8" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W8'+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W9" id="W9" type="number" style="display:none"><input id="W90" type="checkbox"></td><td>Sunset<input name="H9" value="255" type="hidden"></td><td><input name="N9" type="number" min="-59" max="59"><td><input name="T9" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W9'+j+'" type="checkbox"></td>';gId("TMT").innerHTML=t}function FC(){for(j=0;j<8;j++)for(i=0;i<10;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1}function Wd(){for(a=[0,0,0,0,0,0,0,0,0,0],i=0;i<10;i++){for(m=1,j=0;j<8;j++)a[i]+=gId("W"+i+j).checked*m,m*=2;gId("W"+i).value=a[i]}}function addRow(t,e,n,i){var d=gId("macros"),c=d.rows.length,u=d.insertRow(c);document.createElement("td");u.insertCell(0).innerHTML=`Button ${t}:`,u.insertCell(1).innerHTML=`<input name="MP${t}" type="number" min="0" max="250" value="${e}" required>`,u.insertCell(2).innerHTML=`<input name="ML${t}" type="number" min="0" max="250" value="${n}" required>`,u.insertCell(3).innerHTML=`<input name="MD${t}" type="number" min="0" max="250" value="${i}" required>`}function GetV() {
%CSS%%SCSS%</head><body onload="S()"><form
id="form_s" name="Sf" method="post" onsubmit="Wd()"><div class="helpB"><button
type="button" onclick="H()">?</button></div><button type="button" onclick="B()">
Expand All @@ -325,20 +325,24 @@ step="0.01"><div id="sun" class="times"></div><h3>Clock</h3>Clock Overlay:
<select name="OL" onchange="Cs()"><option value="0" id="cn" selected="selected">
None</option><option value="1" id="ca">Analog Clock</option><option value="2">
Single Digit Clock</option><option value="3" id="cc">Cronixie Clock</option>
</select><br><div id="coc">First LED: <input name="O1" type="number" min="0"
max="255" required> Last LED: <input name="O2" type="number" min="0" max="255"
required><br><div id="cac">12h LED: <input name="OM" type="number" min="0"
max="255" required><br>Show 5min marks: <input type="checkbox" name="O5"><br>
</div>Seconds (as trail): <input type="checkbox" name="OS"><br></div><div
id="ccc">Cronixie Display: <input name="CX" maxlength="6"><br>
Cronixie Backlight: <input type="checkbox" name="CB"><br></div>Countdown Mode:
<input type="checkbox" name="CE"><br>Countdown Goal:<br>Year: 20 <input
name="CY" type="number" min="0" max="99" required> Month: <input name="CI"
type="number" min="1" max="12" required> Day: <input name="CD" type="number"
min="1" max="31" required><br>Hour: <input name="CH" type="number" min="0"
max="23" required> Minute: <input name="CM" type="number" min="0" max="59"
required> Second: <input name="CS" type="number" min="0" max="59" required><br>
<h3>Macro presets</h3><b>Macros have moved!</b><br><i>
<option value="4" id="cd">Digital Clock</option></select><br><div id="coc">
First LED: <input name="O1" type="number" min="0" max="255" required> Last LED:
<input name="O2" type="number" min="0" max="255" required><br><div id="cac">
12h LED: <input name="OM" type="number" min="0" max="255" required><br>
Show 5min marks: <input type="checkbox" name="O5"><br></div>Seconds (as trail):
<input type="checkbox" name="OS"><br></div><div id="ccc">Cronixie Display:
<input name="CX" maxlength="6"><br>Cronixie Backlight: <input type="checkbox"
name="CB"><br></div><div id="cdc">LED per segment: <input name="DL"
type="number" min="0" max="255" value="7"><br>
Colon led's between hours and minutes: <input type="number" name="DC" min="0"
max="255" value="4"><br></div>Countdown Mode: <input type="checkbox" name="CE">
<br>Countdown Goal:<br>Year: 20 <input name="CY" type="number" min="0" max="99"
required> Month: <input name="CI" type="number" min="1" max="12" required> Day:
<input name="CD" type="number" min="1" max="31" required><br>Hour: <input
name="CH" type="number" min="0" max="23" required> Minute: <input name="CM"
type="number" min="0" max="59" required> Second: <input name="CS" type="number"
min="0" max="59" required><br><h3>Macro presets</h3><b>Macros have moved!</b>
<br><i>
Presets now also can be used as macros to save both JSON and HTTP API commands.
<br>Just enter the preset id below!</i> <i>
Use 0 for the default action instead of a preset</i><br>Alexa On/Off Preset:
Expand Down
34 changes: 23 additions & 11 deletions wled00/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,27 +328,39 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
byte segbri = seg.opacity;
root["bri"] = (segbri) ? segbri : 255;

char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
JsonArray colarr = root.createNestedArray("col");

char colstr[70]; //max len 68 (5 chan, all 255)
obuf = colstr; olen = 0;
oappend("[");

for (uint8_t i = 0; i < 3; i++)
{
byte segcol[4]; byte* c = segcol;
oappend("[");

if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
{
c = (i == 0)? col:colSec;
byte* c = (i == 0)? col:colSec;

oappendi(c[0]); oappend(",");
oappendi(c[1]); oappend(",");
oappendi(c[2]);
if (strip.isRgbw) {
oappend(","); oappendi(c[3]);
}
} else {
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
oappendi((seg.colors[i] >> 16) & 0xFF); oappend(",");
oappendi((seg.colors[i] >> 8) & 0xFF); oappend(",");
oappendi((seg.colors[i]) & 0xFF);
if (strip.isRgbw) {
oappend(","); oappendi((seg.colors[i] >> 24) & 0xFF);
}
}

char tmpcol[22];
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);

strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
oappend("]");
if (i < 2) oappend(",");
}
strcat(colstr,"]");
oappend("]");
root["col"] = serialized(colstr);

root[F("fx")] = seg.mode;
Expand Down
67 changes: 67 additions & 0 deletions wled00/overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,72 @@ void handleOverlays()
}


/*
* Support for the digital clock
*
* Segments are connected as following:
*
* A
* ---->
* | |
* F | | B
* | G |
* ---->
* | |
* E | | C
* | D |
* <----
*
* LEDs are connected in series: tens of hour ABCDEFG -> hour ABCDEFG -> colon (if enabled) -> tens of minute ABCDEFG -> minute ABCDEFG
* TODO: custom effects per digit, per number, ...
*/

void displayDigit(uint16_t start, uint8_t number)
{
// Mapping of the segments
// {A, B, C, D, E, F, G}
uint8_t ledMapping[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 1, 0, 1, 1}}; // 9

for (uint8_t i=0; i < 7; i++)
{
// If that segment needs to disable it, disable it
if(!ledMapping[number][i])
strip.setRange(start, start + digitalLedPerSegment - 1 , 0);
start += digitalLedPerSegment;
}
}

void _overlayDigitalClock()
{
uint8_t hour10 = hour(localTime)/10;
uint8_t hour1 = hour(localTime) - hour10 * 10;
uint8_t minute10 = minute(localTime)/10;
uint8_t minute1 = minute(localTime) - minute10 * 10;

uint16_t digitStart = 0;
displayDigit(digitStart, hour10);
digitStart += digitalLedPerSegment * 7;
displayDigit(digitStart, hour1);
digitStart += digitalLedPerSegment * 7;

digitStart += digitalColon;

displayDigit(digitStart, minute10);
digitStart += digitalLedPerSegment * 7;
displayDigit(digitStart, minute1);
}


void _overlayAnalogClock()
{
int overlaySize = overlayMax - overlayMin +1;
Expand Down Expand Up @@ -118,6 +184,7 @@ void handleOverlayDraw() {
{
case 1: _overlayAnalogClock(); break;
case 3: _drawOverlayCronixie(); break;
case 4: _overlayDigitalClock(); break;
}
}

Expand Down
3 changes: 3 additions & 0 deletions wled00/set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
analogClock5MinuteMarks = request->hasArg(F("O5"));
analogClockSecondsTrail = request->hasArg(F("OS"));

digitalLedPerSegment = request->arg(F("DL")).toInt();
digitalColon = request->arg(F("DC")).toInt();

#ifndef WLED_DISABLE_CRONIXIE
strcpy(cronixieDisplay,request->arg(F("CX")).c_str());
cronixieBacklight = request->hasArg(F("CB"));
Expand Down
5 changes: 4 additions & 1 deletion wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format
WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino
WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation

WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clock 3: cronixie
WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clocl 3: cronixie 4: digital clock
WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(ledCount - 1); // boundaries of overlay mode

WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
Expand All @@ -372,6 +372,9 @@ WLED_GLOBAL char cronixieDisplay[7] _INIT("HHMMSS"); // Cronixie Display
WLED_GLOBAL bool cronixieBacklight _INIT(true); // Allow digits to be back-illuminated
#endif

WLED_GLOBAL byte digitalLedPerSegment _INIT(7); // Amount of LEDs per segment
WLED_GLOBAL byte digitalColon _INIT(4); // Show a led digit between hours and minutes (default 4 leds)

WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date
WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits
WLED_GLOBAL byte countdownDay _INIT(1) , countdownHour _INIT(0);
Expand Down
2 changes: 2 additions & 0 deletions wled00/xml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("CH"),countdownHour);
sappend('v',SET_F("CM"),countdownMin);
sappend('v',SET_F("CS"),countdownSec);
sappend('v',SET_F("DL"),digitalLedPerSegment);
sappend('c',SET_F("DC"),digitalColon);

sappend('v',SET_F("A0"),macroAlexaOn);
sappend('v',SET_F("A1"),macroAlexaOff);
Expand Down