diff --git a/CHANGELOG.md b/CHANGELOG.md index 533c1ab6..4564e578 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ### Builds after release 0.12.0 +#### Build 2203060 + +- Dynamic hiding of unused color controls in UI (PR #2567) +- Removed native Cronixie support and added Cronixie usermod +- Fixed disabled timed preset expanding calendar +- Fixed Color Order setting shown for analog busses +- Fixed incorrect operator (#2566) + #### Build 2203011 - IR rewrite (PR #2561), supports CCT diff --git a/platformio.ini b/platformio.ini index 7d6b4290..c6b42150 100644 --- a/platformio.ini +++ b/platformio.ini @@ -335,10 +335,10 @@ build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} -# ESP32 ETH build that fits in old 1M app space (disables Blynk, Cronixie, and Hue sync) +# ESP32 ETH build that fits in old 1M app space (disables Blynk and Hue sync) [env:esp32_eth_ota1mapp] extends = env:esp32_eth -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet_OTA -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet_OTA -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK -D WLED_DISABLE_HUESYNC [env:esp32s2_saola] board = esp32-s2-saola-1 @@ -529,7 +529,6 @@ board = esp32dev platform = espressif32@3.2 upload_speed = 921600 build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED - #-D ELEKSTUBE_DIMMING # if enabled, scale display brightness (does not set backlight, only scales contents) -D USERMOD_RTC -D USERMOD_ELEKSTUBE_IPS -D LEDPIN=12 diff --git a/platformio_override.ini.sample b/platformio_override.ini.sample index 70ef9660..c8fb311f 100644 --- a/platformio_override.ini.sample +++ b/platformio_override.ini.sample @@ -22,7 +22,6 @@ build_flags = ${common.build_flags_esp8266} ; -D WLED_DISABLE_OTA ; -D WLED_DISABLE_ALEXA ; -D WLED_DISABLE_BLYNK -; -D WLED_DISABLE_CRONIXIE ; -D WLED_DISABLE_HUESYNC ; -D WLED_DISABLE_INFRARED ; -D WLED_DISABLE_WEBSOCKETS diff --git a/readme.md b/readme.md index 07166b01..2e7843c2 100644 --- a/readme.md +++ b/readme.md @@ -27,7 +27,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control - Presets can be used to automatically execute API calls - Nightlight function (gradually dims down) - Full OTA software updatability (HTTP + ArduinoOTA), password protectable -- Configurable analog clock + support for the Cronixie kit by Diamex +- Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods) - Configurable Auto Brightness limit for safer operation - Filesystem-based config for easier backup of presets and settings diff --git a/usermods/Cronixie/readme.md b/usermods/Cronixie/readme.md new file mode 100644 index 00000000..1eeac8ed --- /dev/null +++ b/usermods/Cronixie/readme.md @@ -0,0 +1,8 @@ +# Cronixie clock usermod + +This usermod supports driving the Cronixie M and L clock kits by Diamex. + +## Installation + +Compile and upload after adding `-D USERMOD_CRONIXIE` to `build_flags` of your PlatformIO environment. +Make sure the Auto Brightness Limiter is enabled at 420mA (!) and configure 60 WS281x LEDs. \ No newline at end of file diff --git a/usermods/Cronixie/usermod_cronixie.h b/usermods/Cronixie/usermod_cronixie.h new file mode 100644 index 00000000..5e4255f4 --- /dev/null +++ b/usermods/Cronixie/usermod_cronixie.h @@ -0,0 +1,301 @@ +#pragma once + +#include "wled.h" + +class UsermodCronixie : public Usermod { + private: + unsigned long lastTime = 0; + char cronixieDisplay[7] = "HHMMSS"; + byte _digitOut[6] = {10,10,10,10,10,10}; + byte dP[6] = {255, 255, 255, 255, 255, 255}; + + // set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer) + bool backlight = true; + + public: + void initCronixie() + { + if (dP[0] == 255) // if dP[0] is 255, cronixie is not yet init'ed + { + setCronixie(); + strip.getSegment(0).grouping = 10; // 10 LEDs per digit + } + } + + void setup() { + + } + + void loop() { + if (!toki.isTick()) return; + initCronixie(); + _overlayCronixie(); + strip.trigger(); + } + + byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) + { + byte counter = 0; + + for (int i = index+1; i < 6; i++) + { + if (cronixieDisplay[i] == code) + { + counter++; + } else { + return counter; + } + } + return counter; + } + + void setCronixie() + { + /* + * digit purpose index + * 0-9 | 0-9 (incl. random) + * 10 | blank + * 11 | blank, bg off + * 12 | test upw. + * 13 | test dnw. + * 14 | binary AM/PM + * 15 | BB upper +50 for no trailing 0 + * 16 | BBB + * 17 | BBBB + * 18 | BBBBB + * 19 | BBBBBB + * 20 | H + * 21 | HH + * 22 | HHH + * 23 | HHHH + * 24 | M + * 25 | MM + * 26 | MMM + * 27 | MMMM + * 28 | MMMMM + * 29 | MMMMMM + * 30 | S + * 31 | SS + * 32 | SSS + * 33 | SSSS + * 34 | SSSSS + * 35 | SSSSSS + * 36 | Y + * 37 | YY + * 38 | YYYY + * 39 | I + * 40 | II + * 41 | W + * 42 | WW + * 43 | D + * 44 | DD + * 45 | DDD + * 46 | V + * 47 | VV + * 48 | VVV + * 49 | VVVV + * 50 | VVVVV + * 51 | VVVVVV + * 52 | v + * 53 | vv + * 54 | vvv + * 55 | vvvv + * 56 | vvvvv + * 57 | vvvvvv + */ + + //H HourLower | HH - Hour 24. | AH - Hour 12. | HHH Hour of Month | HHHH Hour of Year + //M MinuteUpper | MM Minute of Hour | MMM Minute of 12h | MMMM Minute of Day | MMMMM Minute of Month | MMMMMM Minute of Year + //S SecondUpper | SS Second of Minute | SSS Second of 10 Minute | SSSS Second of Hour | SSSSS Second of Day | SSSSSS Second of Week + //B AM/PM | BB 0-6/6-12/12-18/18-24 | BBB 0-3... | BBBB 0-1.5... | BBBBB 0-1 | BBBBBB 0-0.5 + + //Y YearLower | YY - Year LU | YYYY - Std. + //I MonthLower | II - Month of Year + //W Week of Month | WW Week of Year + //D Day of Week | DD Day Of Month | DDD Day Of Year + + DEBUG_PRINT("cset "); + DEBUG_PRINTLN(cronixieDisplay); + + for (int i = 0; i < 6; i++) + { + dP[i] = 10; + switch (cronixieDisplay[i]) + { + case '_': dP[i] = 10; break; + case '-': dP[i] = 11; break; + case 'r': dP[i] = random(1,7); break; //random btw. 1-6 + case 'R': dP[i] = random(0,10); break; //random btw. 0-9 + //case 't': break; //Test upw. + //case 'T': break; //Test dnw. + case 'b': dP[i] = 14 + getSameCodeLength('b',i,cronixieDisplay); i = i+dP[i]-14; break; + case 'B': dP[i] = 14 + getSameCodeLength('B',i,cronixieDisplay); i = i+dP[i]-14; break; + case 'h': dP[i] = 70 + getSameCodeLength('h',i,cronixieDisplay); i = i+dP[i]-70; break; + case 'H': dP[i] = 20 + getSameCodeLength('H',i,cronixieDisplay); i = i+dP[i]-20; break; + case 'A': dP[i] = 108; i++; break; + case 'a': dP[i] = 58; i++; break; + case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break; + case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break; + case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; break; //refresh more often bc. of secs + case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; break; + case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break; + case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break; + case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M. + case 'i': dP[i] = 89 + getSameCodeLength('i',i,cronixieDisplay); i = i+dP[i]-89; break; + //case 'W': break; + //case 'w': break; + case 'D': dP[i] = 43 + getSameCodeLength('D',i,cronixieDisplay); i = i+dP[i]-43; break; + case 'd': dP[i] = 93 + getSameCodeLength('d',i,cronixieDisplay); i = i+dP[i]-93; break; + case '0': dP[i] = 0; break; + case '1': dP[i] = 1; break; + case '2': dP[i] = 2; break; + case '3': dP[i] = 3; break; + case '4': dP[i] = 4; break; + case '5': dP[i] = 5; break; + case '6': dP[i] = 6; break; + case '7': dP[i] = 7; break; + case '8': dP[i] = 8; break; + case '9': dP[i] = 9; break; + //case 'V': break; //user var0 + //case 'v': break; //user var1 + } + } + DEBUG_PRINT("result "); + for (int i = 0; i < 5; i++) + { + DEBUG_PRINT((int)dP[i]); + DEBUG_PRINT(" "); + } + DEBUG_PRINTLN((int)dP[5]); + + _overlayCronixie(); // refresh + } + + void _overlayCronixie() + { + byte h = hour(localTime); + byte h0 = h; + byte m = minute(localTime); + byte s = second(localTime); + byte d = day(localTime); + byte mi = month(localTime); + int y = year(localTime); + //this has to be changed in time for 22nd century + y -= 2000; if (y<0) y += 30; //makes countdown work + + if (useAMPM && !countdownMode) + { + if (h>12) h-=12; + else if (h==0) h+=12; + } + for (int i = 0; i < 6; i++) + { + if (dP[i] < 12) _digitOut[i] = dP[i]; + else { + if (dP[i] < 65) + { + switch(dP[i]) + { + case 21: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; i++; break; //HH + case 25: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; i++; break; //MM + case 31: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; i++; break; //SS + + case 20: _digitOut[i] = h- (h/10)*10; break; //H + case 24: _digitOut[i] = m/10; break; //M + case 30: _digitOut[i] = s/10; break; //S + + case 43: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D + case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD + case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II + case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY + case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY + + //case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI) + //case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB + case 14: _digitOut[i] = (h0>11)?1:0; break; //B + } + } else + { + switch(dP[i]) + { + case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh + case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm + case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss + //case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI) + //case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb + case 64: _digitOut[i] = (h0>11)?1:10; break; //b + + case 93: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d + case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd + case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii + case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy + case 89: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //yyyy + } + } + } + } + } + + void handleOverlayDraw() + { + byte offsets[] = {5, 0, 6, 1, 7, 2, 8, 3, 9, 4}; + + for (uint16_t i = 0; i < 6; i++) + { + byte o = 10*i; + byte excl = 10; + if(_digitOut[i] < 10) excl = offsets[_digitOut[i]]; + excl += o; + + if (backlight && _digitOut[i] <11) + { + uint32_t col = strip.gamma32(strip.getSegment(0).colors[1]); + for (uint16_t j=o; j< o+10; j++) { + if (j != excl) strip.setPixelColor(j, col); + } + } else + { + for (uint16_t j=o; j< o+10; j++) { + if (j != excl) strip.setPixelColor(j, 0); + } + } + } + } + + void addToJsonState(JsonObject& root) + { + root["nx"] = cronixieDisplay; + } + + void readFromJsonState(JsonObject& root) + { + if (root["nx"].is()) { + strncpy(cronixieDisplay, root["nx"], 6); + } + } + + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject(F("Cronixie")); + top["backlight"] = backlight; + } + + bool readFromConfig(JsonObject& root) + { + // default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor + // setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) + + JsonObject top = root[F("Cronixie")]; + + bool configComplete = !top.isNull(); + + configComplete &= getJsonValue(top["backlight"], backlight); + + return configComplete; + } + + uint16_t getId() + { + return USERMOD_ID_CRONIXIE; + } +}; \ No newline at end of file diff --git a/usermods/EleksTube_IPS/usermod_elekstube_ips.h b/usermods/EleksTube_IPS/usermod_elekstube_ips.h index 0fb5ac46..06c6ecc8 100644 --- a/usermods/EleksTube_IPS/usermod_elekstube_ips.h +++ b/usermods/EleksTube_IPS/usermod_elekstube_ips.h @@ -11,6 +11,8 @@ class ElekstubeIPSUsermod : public Usermod { static const char _tubeSeg[]; static const char _digitOffset[]; + char cronixieDisplay[7] = "HHMMSS"; + TFTs tfts; void updateClockDisplay(TFTs::show_t show=TFTs::yes) { bool set[6] = {false}; @@ -123,6 +125,7 @@ class ElekstubeIPSUsermod : public Usermod { */ void addToJsonState(JsonObject& root) { + root["nx"] = cronixieDisplay; root[FPSTR(_digitOffset)] = tfts.digitOffset; } @@ -133,6 +136,10 @@ class ElekstubeIPSUsermod : public Usermod { */ void readFromJsonState(JsonObject& root) { + if (root["nx"].is()) { + strncpy(cronixieDisplay, root["nx"], 6); + } + uint8_t digitOffsetPrev = tfts.digitOffset; tfts.digitOffset = root[FPSTR(_digitOffset)] | tfts.digitOffset; if (tfts.digitOffset > 240) tfts.digitOffset = 240; diff --git a/wled00/const.h b/wled00/const.h index d1e021e7..d961452f 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -71,6 +71,7 @@ #define USERMOD_RGB_ROTARY_ENCODER 22 //Usermod "rgb-rotary-encoder.h" #define USERMOD_ID_QUINLED_AN_PENTA 23 //Usermod "quinled-an-penta.h" #define USERMOD_ID_SSDR 24 //Usermod "usermod_v2_seven_segment_display_reloaded.h" +#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index e88bcbbe..c90a2e48 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -36,22 +36,7 @@ } function Cs() { - gId("cac").style.display="none"; - gId("coc").style.display="block"; - gId("ccc").style.display="none"; - if (gId("ca").selected) - { - gId("cac").style.display="block"; - } - if (gId("cc").selected) - { - gId("coc").style.display="none"; - gId("ccc").style.display="block"; - } - if (gId("cn").selected) - { - gId("coc").style.display="none"; - } + gId("cac").style.display=(gN("OL").checked)?"block":"none"; } function BTa() { @@ -199,24 +184,13 @@
(opens new tab, only works in browser)

Clock

- Clock Overlay: -
-
- First LED: Last LED:
-
+ Analog Clock overlay:
+
+ First LED: Last LED:
12h LED:
- Show 5min marks:
+ Show 5min marks:
Seconds (as trail):
-
- Cronixie Display:
- Cronixie Backlight:
-
Countdown Mode:
Countdown Goal:
Date: 20--
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index f1743c65..c0deaefa 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -177,17 +177,10 @@ void calculateSunriseAndSunset(); void setTimeFromAPI(uint32_t timein); //overlay.cpp -void initCronixie(); -void handleOverlays(); void handleOverlayDraw(); void _overlayAnalogCountdown(); void _overlayAnalogClock(); -byte getSameCodeLength(char code, int index, char const cronixieDisplay[]); -void setCronixie(); -void _overlayCronixie(); -void _drawOverlayCronixie(); - //playlist.cpp void shufflePlaylist(); void unloadPlaylist(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 02ee5d14..cec033ea 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -358,7 +358,7 @@ Keep at 115200 to use Improv. Some boards may not support high rates.
// Autogenerated from wled00/data/settings_time.htm, do not edit!! const char PAGE_settings_time[] PROGMEM = R"=====( Time Settings