Interim commit

Added option to send UDP notifications twice to increase reliability
Added a C64 color theme
Added clock options
Added 12 timezones
Merged Cronixie and useoverlay build options
Removed abbrev char[] from Timezone lib to save memory
Added setting to reverse/flip LEDs
Added long press random color button function
This commit is contained in:
cschwinne 2018-03-06 23:47:08 +01:00
parent e7e11b8bd2
commit bbb27dd70b
24 changed files with 323 additions and 191 deletions

View File

@ -1816,6 +1816,11 @@ void WS2812FX::setFastUpdateMode(bool y)
if (_mode_index == 0) _mode_delay = 20;
}
void WS2812FX::setReverseMode(bool b)
{
_reverseMode = b;
}
void WS2812FX::driverModeCronixie(bool b)
{
_cronixieMode = b;
@ -1940,6 +1945,7 @@ void WS2812FX::setPixelColorRaw(uint16_t i, uint8_t r, uint8_t g, uint8_t b, uin
void WS2812FX::setPixelColor(uint16_t i, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
if (_reverseMode) i = _led_count - 1 -i;
if (!_cronixieMode)
{
#ifdef RGBW

View File

@ -213,6 +213,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_counter_mode_step = 0;
_counter_cc_step = 0;
_fastStandard = false;
_reverseMode = false;
_locked = new boolean[n];
_cronixieDigits = new uint8_t[6];
}
@ -247,6 +248,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
setBrightness(uint8_t b),
increaseBrightness(uint8_t s),
decreaseBrightness(uint8_t s),
setReverseMode(bool b),
driverModeCronixie(bool b),
setCronixieDigits(uint8_t* d),
setCronixieBacklight(bool b),
@ -360,6 +362,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
boolean
_triggered,
_fastStandard,
_reverseMode,
_cronixieMode,
_cronixieBacklightEnabled,
_cc_fs,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -116,7 +116,7 @@ Default Duration: <input name="TLDUR" type="number" min="1" max="255" required>
Default Target brightness: <input name="TLBRI" type="number" min="0" max="255" required><br>
Fade down: <input type="checkbox" name="TLFDE"><br>
<h3>Advanced</h3>
Default overlay ID: <input name="OLDEF" type="number" min="0" max="255" required> <br>
Reverse LED order (rotate 180): <input type="checkbox" name="LEDRV"><br>
WARLS offset: <input name="WOFFS" type="number" min="-255" max="255" required><hr>
<button type="button" onclick="B()">Back</button><button type="submit" name="SUBM">Save</button>
</form>
@ -154,7 +154,7 @@ Color Theme:
<option value="8">Air</option>
<option value="9">Nixie</option>
<option value="10">Terminal</option>
<option value="11">Placeholder</option>
<option value="11">C64</option>
<option value="12">Placeholder</option>
<option value="13">Placeholder</option>
<option value="14">The End</option>
@ -193,12 +193,13 @@ On/Off button enabled: <input type="checkbox" name="BTNON">
<h3>WLED Broadcast</h3>
UDP Port: <input name="NUDPP" maxlength="5" size="4"><br>
Receive <input type="checkbox" name="NRCBR">Brightness, <input type="checkbox" name="NRCCL">Color, and <input type="checkbox" name="NRCFX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="NSDIR"> <br>
Send notifications on button press: <input type="checkbox" name="NSBTN"> <br>
Send Alexa notifications: <input type="checkbox" name="NSALX"> <br>
Send notifications on direct change: <input type="checkbox" name="NSDIR"><br>
Send notifications on button press: <input type="checkbox" name="NSBTN"><br>
Send Alexa notifications: <input type="checkbox" name="NSALX"><br>
Send Philips Hue change notifications: <input type="checkbox" name="NSHUE">
Send notifications twice: <input type="checkbox" name="NS2XS">
<h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="ALEXA"> <br>
Emulate Alexa device: <input type="checkbox" name="ALEXA"><br>
Alexa invocation name: <input name="AINVN" maxlength="32"><br>
<h3>Philips Hue</h3>
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
@ -239,9 +240,9 @@ Get time from NTP server: <input type="checkbox" name="NTPON"><br>
Time zone:
<select name="TZONE">
<option value="1" selected>GMT(UTC)</option>
<option value="2">GMT/BST</option>
<!--<option value="2">GMT/BST</option>-->
<option value="3">CET/CEST</option>
<option value="4">EET/EEST</option>
<!--<option value="4">EET/EEST</option>
<option value="5">US-EST/EDT</option>
<option value="6">US-CST/CDT</option>
<option value="7">US-MST/MDT</option>
@ -250,7 +251,7 @@ Time zone:
<option value="10">CST(AWST)</option>
<option value="11">JST(KST)</option>
<option value="12">AEST/AEDT</option>
<option value="13">NZST/NZDT</option>
<option value="13">NZST/NZDT</option>-->
</select><br>
Hour/Min offset: <input name="TOFSH" type="number" min="-255" max="255" required> <input name="TOFSM" type="number" min="-255" max="255" required><br>-->
Current local time is <span class="times">unknown</span>.
@ -331,7 +332,7 @@ HTTP traffic is not encrypted. An attacker in the same network could intercept f
<button type="button" onclick="U()">Manual OTA Update</button><br>
Enable ArduinoOTA: <input type="checkbox" name="AROTA"><br>
<h3>About</h3>
<a href="https://github.com/Aircoookie/WLED">WLED</a> version 0.5.1<br>
<a href="https://github.com/Aircoookie/WLED">WLED</a> version 0.6.0_dev<br>
(c) 2016-2018 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
<i>Uses libraries:</i><br>

View File

@ -281,9 +281,9 @@ void setTime(time_t t) {
nextSyncTime = (uint32_t)t + syncInterval;
Status = timeSet;
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
}
}
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){
// year can be given as full four digit year or two digts (2010 or 10 for 2010);
//it is converted to years since 1970
if( yr > 99)
@ -296,7 +296,11 @@ void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
tm.Hour = hr;
tm.Minute = min;
tm.Second = sec;
setTime(makeTime(tm));
return makeTime(tm);
}
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
setTime(getUnixTime(hr,min,sec,dy,mnth,yr));
}
void adjustTime(long adjustment) {

View File

@ -120,6 +120,7 @@ int year(time_t t); // the year for the given time
time_t now(); // return the current time as seconds since Jan 1 1970
void setTime(time_t t);
void setTime(int hr,int min,int sec,int day, int month, int yr);
void getUnixTime(int hr,int min,int sec,int day, int month, int yr); //added by Aircoookie to get epoch time
void adjustTime(long adjustment);
/* date strings */

View File

@ -27,12 +27,11 @@ enum month_t {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
//or when standard time begins.
struct TimeChangeRule
{
char abbrev[6]; //five chars max
uint8_t week; //First, Second, Third, Fourth, or Last week of the month
uint8_t dow; //day of week, 1=Sun, 2=Mon, ... 7=Sat
uint8_t month; //1=Jan, 2=Feb, ... 12=Dec
uint8_t hour; //0-23
int offset; //offset from UTC in minutes
int16_t offset; //offset from UTC in minutes
};
class Timezone

View File

@ -3,7 +3,7 @@
*/
/*
* @title WLED project sketch
* @version 0.5.1
* @version 0.6.0_dev
* @author Christian Schwinne
*/
@ -32,8 +32,8 @@
#include "WS2812FX.h"
//version in format yymmddb (b = daily build)
#define VERSION 1802273
const String versionString = "0.5.1";
#define VERSION 1803061
const String versionString = "0.6.0_dev";
//AP and OTA default passwords (change them!)
String appass = "wled1234";
@ -42,16 +42,10 @@ String otapass = "wledota";
//If you have an RGBW strip, also uncomment first line in WS2812FX.h!
bool useRGBW = false;
//overlays, needed for clocks etc.
#define USEOVERLAYS
//support for the CRONIXIE clock by Diamex (disable overlays!)
//#define CRONIXIE
//spiffs FS only useful for debug (only ESP8266)
//#define USEFS
//to toggle usb serial debug (un)comment following line
//to toggle usb serial debug (un)comment following line(s)
//#define DEBUG
//Hardware-settings (only changeble via code)
@ -61,39 +55,14 @@ uint8_t auxPin = 15; //use e.g. for external relay
uint8_t auxDefaultState = 0; //0: input 1: high 2: low
uint8_t auxTriggeredState = 0; //0: input 1: high 2: low
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time
Timezone TZ(CEST, CET);
TimeChangeRule *tcr; //pointer to the time change rule, use to get the TZ abbrev
time_t local;
//cronixie defaults
#ifdef CRONIXIE
#undef LEDCOUNT
#define LEDCOUNT 60
uint8_t ledcount = 6;
String apssid = "CRONIXIE-AP";
String alexaInvocationName = "Clock";
char cronixieDefault[] = "HHMMSS";
long cronixieRefreshMs = 497;
unsigned long cronixieRefreshedTime;
byte dP[]{0,0,0,0,0,0};
bool cronixieUseAMPM = false;
bool cronixieBacklight = true;
bool cronixieCountdown = false;
bool ntpEnabled = true;
#endif
//Default CONFIG
String serverDescription = versionString;
uint8_t currentTheme = 0;
String clientssid = "Your_Network_Here";
String clientpass = "Dummy_Pass";
String cmdns = "led";
#ifndef CRONIXIE
uint8_t ledcount = 100;
String apssid = "WLED-AP";
#endif
uint8_t ledcount = 10; //lowered to prevent accidental overcurrent
String apssid = ""; //AP off by default (unless setup)
uint8_t apchannel = 1;
uint8_t aphide = 0;
uint8_t apWaitTimeSecs = 32;
@ -114,11 +83,12 @@ uint8_t nightlightTargetBri = 0, bri_nl_t;
bool fadeTransition = true;
bool sweepTransition = false, sweepDirection = true;
uint16_t transitionDelay = 1200;
bool reverseMode = false;
bool otaLock = false, wifiLock = false;
bool aOtaEnabled = true;
bool onlyAP = false;
bool buttonEnabled = true;
bool notifyDirect = true, notifyButton = true, notifyDirectDefault = true, alexaNotify = false, macroNotify = false;
bool notifyDirect = true, notifyButton = true, notifyDirectDefault = true, alexaNotify = false, macroNotify = false, notifyTwice = false;
bool receiveNotifications = true, receiveNotificationBrightness = true, receiveNotificationColor = true, receiveNotificationEffects = true;
uint8_t briMultiplier = 100;
uint8_t nightlightDelayMins = 60;
@ -128,9 +98,7 @@ uint8_t effectDefault = 0;
uint8_t effectSpeedDefault = 75;
uint8_t effectIntensityDefault = 128;
//NTP stuff
#ifndef CRONIXIE
boolean ntpEnabled = false;
#endif
IPAddress ntpServerIP;
const char* ntpServerName = "pool.ntp.org";
//custom chase
@ -144,11 +112,10 @@ uint8_t cc_start = 0;
//alexa
boolean alexaEnabled = true;
#ifndef CRONIXIE
String alexaInvocationName = "Light";
#endif
uint8_t alexaOnMacro = 255, alexaOffMacro = 255;
uint8_t buttonMacro = 255, countdownMacro = 255;
uint8_t alexaOnMacro = 0, alexaOffMacro = 0;
uint8_t buttonMacro = 0, countdownMacro = 0;
uint8_t bootMacro = 0;
unsigned long countdownTime = 1514764800L;
@ -191,6 +158,9 @@ byte bri_last = 127;
boolean transitionActive = false;
boolean buttonPressedBefore = false;
long buttonPressedTime = 0;
long notificationSentTime = 0;
uint8_t notificationSentCallMode = 0;
bool notificationTwoRequired = false;
boolean nightlightActive = false;
boolean nightlightActive_old = false;
int nightlightDelayMs;
@ -209,30 +179,34 @@ const int NTP_PACKET_SIZE = 48;
byte ntpPacketBuffer[NTP_PACKET_SIZE];
unsigned long ntpLastSyncTime = 999000000L;
unsigned long ntpPacketSentTime = 999000000L;
const unsigned long seventyYears = 2208988800UL;
uint8_t currentTimezone = 0;
time_t local;
int utcOffsetSecs = 0;
//overlay stuff
uint8_t overlayDefault = 0;
uint8_t overlayCurrent = 0;
#ifdef USEOVERLAYS
int overlayMin = 0, overlayMax = 79; //bb: 35, 46, t: 0, 79
int analogClock12pixel = 25; //bb: 41, t: 25
bool overlayDimBg = true;
boolean analogClockSecondsTrail = false;
boolean analogClock5MinuteMarks = false;
boolean nixieClockDisplaySeconds = false;
boolean nixieClock12HourFormat = false;
boolean overlayReverse = true;
uint8_t overlaySpeed = 200;
long overlayRefreshMs = 200;
unsigned long overlayRefreshedTime;
int overlayArr[6];
int overlayDur[6];
int overlayPauseDur[6];
uint16_t overlayDur[6];
uint16_t overlayPauseDur[6];
int nixieClockI = -1;
boolean nixiePause;
#endif
uint8_t countdownYear=19, countdownMonth=1, countdownDay=1, countdownHour=0, countdownMin=0, countdownSec=0; //year is actual year -2000
bool countdownOverTriggered = true;
//cronixie
String cronixieDisplay = "HHMMSS";
byte dP[]{0,0,0,0,0,0};
bool useAMPM = false;
bool cronixieBacklight = true;
bool overlayCountdown = false;
bool cronixieInit = false;
int arlsTimeoutMillis = 2500;
boolean arlsTimeout = false;
@ -338,17 +312,12 @@ void loop() {
handleButton();
handleNetworkTime();
if (!otaLock && aOtaEnabled) ArduinoOTA.handle();
#ifdef CRONIXIE
handleCronixie();
#endif
handleAlexa();
handleOverlays();
if (!arlsTimeout) //block stuff if WARLS is enabled
{
handleHue();
handleNightlight();
#ifdef USEOVERLAYS
handleOverlays();
#endif
if (bri_t) strip.service(); //do not update strip if off, prevents flicker on ESP32
}

View File

@ -12,7 +12,7 @@
//2 -> 0.4p 1711302 and up
//3 -> 0.4 1712121 and up
//4 -> 0.5.0 and up
//5 -> 0.5.1 and up
//5 -> 0.6.0_dev and up
void clearEEPROM()
{
@ -61,7 +61,7 @@ void saveSettingsToEEPROM()
EEPROM.write(228, aphide);
EEPROM.write(229, ledcount);
EEPROM.write(230, notifyButton);
//231 was notifyNightlight
EEPROM.write(231, notifyTwice);
EEPROM.write(232, buttonEnabled);
//233 reserved for first boot flag
EEPROM.write(234, staticip[0]);
@ -82,6 +82,7 @@ void saveSettingsToEEPROM()
EEPROM.write(249, bri_s);
EEPROM.write(250, receiveNotificationBrightness);
EEPROM.write(251, fadeTransition);
EEPROM.write(252, reverseMode);
EEPROM.write(253, (transitionDelay >> 0) & 0xFF);
EEPROM.write(254, (transitionDelay >> 8) & 0xFF);
EEPROM.write(255, briMultiplier);
@ -102,8 +103,8 @@ void saveSettingsToEEPROM()
EEPROM.write(325, effectSpeedDefault);
EEPROM.write(326, effectIntensityDefault);
EEPROM.write(327, ntpEnabled);
//328 reserved for timezone setting
//329 reserved for dst setting
EEPROM.write(328, currentTimezone);
EEPROM.write(329, useAMPM);
EEPROM.write(330, useGammaCorrectionBri);
EEPROM.write(331, useGammaCorrectionRGB);
EEPROM.write(332, overlayDefault);
@ -140,6 +141,9 @@ void saveSettingsToEEPROM()
EEPROM.write(391, receiveNotificationColor);
EEPROM.write(392, receiveNotificationEffects);
EEPROM.write(393, wifiLock);
EEPROM.write(394, (abs(utcOffsetSecs) >> 0) & 0xFF);
EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF);
EEPROM.write(396, (utcOffsetSecs<0)); //is negative
for (int k=0;k<6;k++){
int in = 900+k*8;
@ -225,7 +229,7 @@ void loadSettingsFromEEPROM(bool first)
if (aphide > 1) aphide = 1;
ledcount = EEPROM.read(229); if (ledcount > LEDCOUNT) ledcount = LEDCOUNT;
notifyButton = EEPROM.read(230);
//231 was notifyNightlight
notifyTwice = EEPROM.read(231);
buttonEnabled = EEPROM.read(232);
staticip[0] = EEPROM.read(234);
staticip[1] = EEPROM.read(235);
@ -249,6 +253,7 @@ void loadSettingsFromEEPROM(bool first)
}
receiveNotificationBrightness = EEPROM.read(250);
fadeTransition = EEPROM.read(251);
reverseMode = EEPROM.read(252);
transitionDelay = ((EEPROM.read(253) << 0) & 0xFF) + ((EEPROM.read(254) << 8) & 0xFF00);
briMultiplier = EEPROM.read(255);
otapass = "";
@ -269,6 +274,8 @@ void loadSettingsFromEEPROM(bool first)
effectDefault = EEPROM.read(324); effectCurrent = effectDefault;
effectSpeedDefault = EEPROM.read(325); effectSpeed = effectSpeedDefault;
ntpEnabled = EEPROM.read(327);
currentTimezone = EEPROM.read(328);
useAMPM = EEPROM.read(329);
useGammaCorrectionBri = EEPROM.read(330);
useGammaCorrectionRGB = EEPROM.read(331);
overlayDefault = EEPROM.read(332);
@ -348,6 +355,8 @@ void loadSettingsFromEEPROM(bool first)
bootPreset = EEPROM.read(389);
wifiLock = EEPROM.read(393);
utcOffsetSecs = ((EEPROM.read(394) << 0) & 0xFF) + ((EEPROM.read(395) << 8) & 0xFF00);
if (EEPROM.read(396)) utcOffsetSecs = -utcOffsetSecs; //negative
//favorite setting memory (25 slots/ each 20byte)
//400 - 899 reserved
@ -442,15 +451,25 @@ void savePreset(uint8_t index)
EEPROM.commit();
}
void applyMacro(uint8_t index)
String loadMacro(uint8_t index)
{
if (index > 15) return;
String mc="win&";
index-=1;
String m="";
if (index > 15) return m;
for (int i = 1024+64*index; i < 1088+64*index; i++)
{
if (EEPROM.read(i) == 0) break;
mc += char(EEPROM.read(i));
m += char(EEPROM.read(i));
}
return m;
}
void applyMacro(uint8_t index)
{
index-=1;
if (index > 15) return;
String mc="win&";
mc += loadMacro(index+1);
mc += "&IN"; //internal, no XML response
if (!macroNotify) mc += "&NN";
String forbidden = "&M="; //dont apply if called by the macro itself to prevent loop
@ -465,6 +484,7 @@ void applyMacro(uint8_t index)
void saveMacro(uint8_t index, String mc)
{
index-=1;
if (index > 15) return;
int s = 1024+index*64;
for (int i = s; i < s+64; i++)

View File

@ -70,6 +70,7 @@ String getSettings(uint8_t subPage)
String v = ".value=";
String c = ".checked=";
String ih = ".innerHTML=";
String si = ".selectedIndex=";
if (subPage == 1) {
resp += ds + "CSSID" + v + "\"" + clientssid + "\";";
@ -164,7 +165,7 @@ String getSettings(uint8_t subPage)
resp += ds + "TLBRI" + v + nightlightTargetBri +";";
resp += ds + "TLDUR" + v + nightlightDelayMins +";";
resp += ds + "TLFDE" + c + nightlightFade +";";
resp += ds + "OLDEF" + v + overlayDefault +";";
resp += ds + "LEDRV" + c + reverseMode +";";
resp += ds + "WOFFS" + v + arlsOffset +";";
}
@ -172,7 +173,7 @@ String getSettings(uint8_t subPage)
{
resp += ds + "DESC" + v + "\"" + serverDescription + "\";";
resp += ds + "COLMD" + c + useHSBDefault + ";";
resp += ds + "THEME.selectedIndex=" + String(currentTheme) + ";";
resp += ds + "THEME" + si + String(currentTheme) + ";";
for(int i=0;i<6;i++)
resp += ds + "CCOL" + i + v + "\"" + cssCol[i] + "\";";
resp += ds + "CFONT" + v + "\"" + cssFont + "\";";
@ -188,6 +189,7 @@ String getSettings(uint8_t subPage)
resp += ds + "NSDIR" + c + notifyDirectDefault +";";
resp += ds + "NSBTN" + c + notifyButton +";";
resp += ds + "NSHUE" + c + notifyHue +";";
resp += ds + "NS2XS" + c + notifyTwice +";";
resp += ds + "ALEXA" + c + alexaEnabled +";";
resp += ds + "AINVN" + v + "\"" + alexaInvocationName + "\";";
resp += ds + "NSALX" + c + alexaNotify +";";
@ -207,7 +209,36 @@ String getSettings(uint8_t subPage)
if (subPage == 5)
{
resp += ds + "NTPON" + c + ntpEnabled +";";
resp += ds + "CL24H" + c + !useAMPM +";";
resp += ds + "TZONE" + si + String(currentTimezone) + ";";
resp += ds + "UTCOS" + v + utcOffsetSecs +";";
resp += dg + "(\"times\")[0]" + ih + "\"" + getTimeString() + "\";";
resp += ds + "OLMDE" + si + String(currentOverlay) + ";";
resp += ds + "OLIN1" + v + overlayMin +";";
resp += ds + "OLIN2" + v + overlayMax +";";
resp += ds + "OLINM" + v + analogClock12pixel +";";
resp += ds + "OLSTR" + c + analogClockSecondsTrail +";";
resp += ds + "OL5MI" + c + analogClock5MinuteMarks +";";
resp += ds + "CRONX" + v + "\"" + cronixieDisplay + "\";";
resp += ds + "CROBL" + c + cronixieBacklight +";";
resp += ds + "CLCND" + c + overlayCountdown +";";
resp += ds + "CDGYR" + v + countdownYear +";";
resp += ds + "CDGMN" + v + countdownMonth +";";
resp += ds + "CDGDY" + v + countdownDay +";";
resp += ds + "CDGHR" + v + countdownHours +";";
resp += ds + "CDGMI" + v + countdownMin +";";
resp += ds + "CDGSC" + v + countdownSec +";";
for (int i=1;i<17;i++)
{
resp += ds + "MC" + String(i) + v + "\"" + loadMacro(i) + "\";";
}
resp += ds + "MCRBT" + v + macroBoot +";";
resp += ds + "MCA0I" + v + macroAlexaOn +";";
resp += ds + "MCA0O" + v + macroAlexaOff +";";
resp += ds + "MCB0D" + v + macroButton +";";
resp += ds + "MCB0L" + v + macroLongPress +";";
resp += ds + "MCNTD" + v + macroCountdown +";";
resp += ds + "MCLNO" + v + macroNightlight +";";
}
if (subPage == 6)

View File

@ -230,11 +230,7 @@ void handleSettingsSet(uint8_t subPage)
if (i > 0) nightlightDelayMins = i;
}
nightlightFade = server.hasArg("TLFDE");
if (server.hasArg("OLDEF"))
{
int i = server.arg("OLDEF").toInt();
if (i >= 0 && i <= 255) overlayDefault = i;
}
reverseMode = server.hasArg("LEDRV");
if (server.hasArg("WOFFS"))
{
int i = server.arg("WOFFS").toInt();
@ -278,6 +274,7 @@ void handleSettingsSet(uint8_t subPage)
notifyDirectDefault = server.hasArg("NSDIR");
notifyDirect = notifyDirectDefault;
notifyButton = server.hasArg("NSBTN");
notifyTwice = server.hasArg("NS2XS");
alexaEnabled = server.hasArg("ALEXA");
if (server.hasArg("AINVN")) alexaInvocationName = server.arg("AINVN");
alexaNotify = server.hasArg("NSALX");
@ -319,6 +316,11 @@ void handleSettingsSet(uint8_t subPage)
{
ntpEnabled = server.hasArg("NTPON");
if (ntpEnabled && WiFi.status() == WL_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); //start if not already connected
if (server.hasArg("OLDEF"))
{
int i = server.arg("OLDEF").toInt();
if (i >= 0 && i <= 255) overlayDefault = i;
}
}
//SECURITY
@ -712,17 +714,19 @@ boolean handleSet(String req)
applyPreset(req.substring(pos + 3).toInt(), false, false, true);
effectUpdated = true;
}
#ifdef CRONIXIE
//cronixie
pos = req.indexOf("NX="); //sets digits to code
if (pos > 0) {
setCronixie(req.substring(pos + 3, pos + 9).c_str());
cronixieDisplay = req.substring(pos + 3, pos + 9);
setCronixie();
}
pos = req.indexOf("NM="); //mode, 1 countdown
if (pos > 0) {
cronixieCountdown = true;
overlayCountdown = true;
if (req.indexOf("NM=0") > 0)
{
cronixieCountdown = false;
overlayCountdown = false;
}
}
if (req.indexOf("NB=") > 0) //sets backlight
@ -732,10 +736,10 @@ boolean handleSet(String req)
{
cronixieBacklight = false;
}
strip.setCronixieBacklight(cronixieBacklight);
cronixieRefreshedTime = 0;
if (overlayCurrent == 4) strip.setCronixieBacklight(cronixieBacklight);
overlayRefreshedTime = 0;
}
#endif
//internal call, does not send XML response
pos = req.indexOf("IN");
if (pos < 1) XML_response();

View File

@ -212,16 +212,6 @@ void wledInit()
info += "rgbw: false\r\n";
#endif
info += "max-leds: " + (String)LEDCOUNT + "\r\n";
#ifdef USEOVERLAYS
info += "overlays: true\r\n";
#else
info += "overlays: false\r\n";
#endif
#ifdef CRONIXIE
info += "cronixie: true\r\n";
#else
info += "cronixie: false\r\n";
#endif
#ifdef USEFS
info += "spiffs: true\r\n";
#else
@ -308,16 +298,13 @@ void wledInit()
// Initialize NeoPixel Strip
strip.init();
strip.setLedCount(ledcount);
strip.setReverseMode(reverseMode);
strip.setColor(0);
strip.setBrightness(255);
strip.start();
pinMode(buttonPin, INPUT_PULLUP);
#ifdef CRONIXIE
strip.driverModeCronixie(true);
strip.setCronixieBacklight(cronixieBacklight);
setCronixie(cronixieDefault);
#endif
if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true);
colorUpdated(0);
if(digitalRead(buttonPin) == LOW) buttonEnabled = false; //disable button if it is "pressed" unintentionally
@ -325,11 +312,7 @@ void wledInit()
void initAP(){
String save = apssid;
#ifdef CRONIXIE
if (apssid.length() <1) apssid = "CRONIXIE-AP";
#else
if (apssid.length() <1) apssid = "WLED-AP";
#endif
if (apssid.length() <1) apssid = "WLED-AP";
WiFi.softAP(apssid.c_str(), appass.c_str(), apchannel, aphide);
apssid = save;
}
@ -370,6 +353,7 @@ void buildCssColorString()
case 8: cs[0]="0ac"; cs[1]="124"; cs[2]="224"; cs[3]="003eff"; cs[4]="003eff"; cs[5]="003eff"; break;//air
case 9: cs[0]="f70"; cs[1]="421"; cs[2]="221"; cs[3]="a50"; cs[4]="f70"; cs[5]="f70"; break;//nixie
case 10: cs[0]="2d2"; cs[1]="010"; cs[2]="121"; cs[3]="060"; cs[4]="040"; cs[5]="3f3"; break; //terminal
case 11: cs[0]="867ADE"; cs[1]="4033A3"; cs[2]="483AAA"; cs[3]="483AAA"; cs[4]=""; cs[5]="867ADE"; break; //c64
case 14: cs[0]="fc7"; cs[1]="49274a"; cs[2]="94618e"; cs[3]="f4decb"; cs[4]="0008"; cs[5]="f4decb"; break; //end
case 15: for (int i=0;i<6;i++)cs[i]=cssCol[i];//custom
}

View File

@ -4,7 +4,7 @@
#define WLEDPACKETSIZE 24
void notify(uint8_t callMode)
void notify(uint8_t callMode, bool followUp=false)
{
if (!udpConnected) return;
switch (callMode)
@ -41,10 +41,17 @@ void notify(uint8_t callMode)
notifierUdp.beginPacket(broadcastIp, udpPort);
notifierUdp.write(udpOut, WLEDPACKETSIZE);
notifierUdp.endPacket();
notificationSentCallMode = callMode;
notificationSentTime = millis();
notificationTwoRequired = (followUp)? false:notifyTwice;
}
void handleNotifications()
{
if(udpConnected && notificationTwoRequired && millis()-notificationSentTime > 250){
notify(notificationSentCallMode,true);
}
if(udpConnected && receiveNotifications){
int packetSize = notifierUdp.parsePacket();
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves

View File

@ -10,27 +10,34 @@ void handleButton()
{
buttonPressedTime = millis();
buttonPressedBefore = true;
if (buttonMacro == 255)
{
if (bri == 0)
{
bri = bri_last;
} else
{
bri_last = bri;
bri = 0;
}
colorUpdated(2);
} else {
applyMacro(buttonMacro);
}
}
else if (digitalRead(buttonPin) == HIGH && buttonPressedBefore)
{
delay(15); //debounce
if (digitalRead(buttonPin) == HIGH)
{
if (millis() - buttonPressedTime > 7000) initAP();
if (millis() - buttonPressedTime > 7000) {initAP();}
else if (millis() - buttonPressedTime > 700)
{
if (buttonLongPressMacro != 0) {applyMacro(buttonLongPressMacro);}
else _setRandomColor(false);
}
else {
if (buttonMacro == 0)
{
if (bri == 0)
{
bri = bri_last;
} else
{
bri_last = bri;
bri = 0;
}
colorUpdated(2);
} else {
applyMacro(buttonMacro);
}
}
buttonPressedBefore = false;
}
}

View File

@ -2,6 +2,55 @@
* Acquires time from NTP server
*/
TimeChangeRule UTCr = {Last, Sun, Mar, 1, 0}; // UTC
Timezone tzUTC(UTCr, UTCr);
TimeChangeRule BST = {Last, Sun, Mar, 1, 60}; // British Summer Time
TimeChangeRule GMT = {Last, Sun, Oct, 2, 0}; // Standard Time
Timezone tzUK(BST, GMT);
TimeChangeRule CEST = {Last, Sun, Mar, 2, 120}; //Central European Summer Time
TimeChangeRule CET = {Last, Sun, Oct, 3, 60}; //Central European Standard Time
Timezone tzEUCentral(CEST, CET);
TimeChangeRule EEST = {Last, Sun, Mar, 3, 180}; //Central European Summer Time
TimeChangeRule EET = {Last, Sun, Oct, 4, 120}; //Central European Standard Time
Timezone tzEUEastern(EEST, EET);
TimeChangeRule EDT = {Second, Sun, Mar, 2, -240 }; //Daylight time = UTC - 4 hours
TimeChangeRule EST = {First, Sun, Nov, 2, -300 }; //Standard time = UTC - 5 hours
Timezone tzUSEastern(EDT, EST);
TimeChangeRule CDT = {Second, Sun, Mar, 2, -300 }; //Daylight time = UTC - 5 hours
TimeChangeRule CST = {First, Sun, Nov, 2, -360 }; //Standard time = UTC - 6 hours
Timezone tzUSCentral(CDT, CST);
TimeChangeRule MDT = {Second, Sun, Mar, 2, -360 }; //Daylight time = UTC - 6 hours
TimeChangeRule MST = {First, Sun, Nov, 2, -420 }; //Standard time = UTC - 7 hours
Timezone tzUSMountain(MDT, MST);
Timezone tzUSArizona(MST, MST); //Mountain without DST
TimeChangeRule PDT = {Second, Sun, Mar, 2, -420 }; //Daylight time = UTC - 7 hours
TimeChangeRule PST = {First, Sun, Nov, 2, -480 }; //Standard time = UTC - 8 hours
Timezone tzUSPacific(PDT, PST);
TimeChangeRule ChST = {Last, Sun, Mar, 1, 480}; // China Standard Time = UTC + 8 hours
Timezone tzChina(ChST, ChST);
TimeChangeRule JST = {Last, Sun, Mar, 1, 540}; // Japan Standard Time = UTC + 9 hours
Timezone tzJapan(JST, JST);
TimeChangeRule AEDT = {Second, Sun, Oct, 2, 660 }; //Daylight time = UTC + 11 hours
TimeChangeRule AEST = {First, Sun, Apr, 3, 600 }; //Standard time = UTC + 10 hours
Timezone tzAUEastern(AEDT, AEST);
TimeChangeRule NZDT = {Second, Sun, Sep, 2, 780 }; //Daylight time = UTC + 13 hours
TimeChangeRule NZST = {First, Sun, Apr, 3, 720 }; //Standard time = UTC + 12 hours
Timezone tzNZ(NZDT, NZST);
Timezone* timezones[] = { &tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ};
void handleNetworkTime()
{
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WiFi.status() == WL_CONNECTED)
@ -56,7 +105,7 @@ boolean checkNTPResponse()
unsigned long secsSince1900 = highWord << 16 | lowWord;
DEBUG_PRINT("Unix time = ");
unsigned long epoch = secsSince1900 - seventyYears;
unsigned long epoch = secsSince1900 - 2208988800UL; //subtract 70 years
setTime(epoch);
DEBUG_PRINTLN(epoch);
if (countdownTime - now() > 0) countdownOverTriggered = false;
@ -65,25 +114,41 @@ boolean checkNTPResponse()
return false;
}
void updateLocalTime()
{
unsigned long tmc = now()+ (utcOffsetSign)? -utcOffsetSecs:utcOffsetSecs;
local = timezones[currentTimezone]->toLocal(tmc);
}
String getTimeString()
{
local = TZ.toLocal(now(), &tcr);
updateLocalTime();
String ret = monthStr(month(local));
ret = ret + " ";
ret = ret + day(local);
ret = ret + " ";
ret = ret + year(local);
ret = ret + ", ";
ret = ret + hour(local);
ret += (useAMPM)? hour(local)%12:hour(local);
ret = ret + ":";
if (minute(local) < 10) ret = ret + "0";
ret = ret + minute(local);
ret = ret + ":";
if (second(local) < 10) ret = ret + "0";
ret = ret + second(local);
if (useAMPM)
{
ret += (hour(local) > 11)? " PM":" AM";
}
return ret;
}
void setCountdown()
{
countdownTime = timezones[currentTimezone]->toUTC(getUnixTime(countdownHour, countdownMin, countdownSec, countdownDay, countdownMonth, countdownYear));
if (countdownTime - now() > 0) countdownOverTriggered = false;
}
//returns true if countdown just over
bool checkCountdown()
{
@ -91,7 +156,7 @@ bool checkCountdown()
local = abs(diff);
if (diff <0 && !countdownOverTriggered)
{
applyMacro(countdownMacro);
if (countdownMacro != 0) applyMacro(countdownMacro);
countdownOverTriggered = true;
return true;
}

View File

@ -1,7 +1,21 @@
/*
* The Overlay function is over a year old, largely untested and not configurable during runtime. Consider it as deprecated for now, it might get either removed/simplified/reworked.
* Used to draw clock overlays over the strip
*/
#ifdef USEOVERLAYS
void initCronixie()
{
if (overlayCurrent == 7 && !cronixieInit)
{
strip.driverModeCronixie(true);
strip.setCronixieBacklight(cronixieBacklight);
setCronixie(cronixieDefault);
cronixieInit = true;
} else if (cronixieInit && overlayCurrent != 7)
{
strip.driverModeCronixie(false);
cronixieInit = false;
}
}
void _nixieDisplay(int num[], int dur[], int pausedur[], int cnt)
{
strip.setRange(overlayMin, overlayMax, 0);
@ -84,8 +98,6 @@ void _nixieNumber(int number, int dur)
if (overlayArr[i] != -1)
{
overlayArr[i] = overlayArr[i] + overlayMin;
if (overlayReverse)
overlayArr[i] = overlayMax - overlayArr[i];
}
}
for (int i = 0; i <6; i++)
@ -106,38 +118,39 @@ void _nixieNumber(int number, int dur)
void handleOverlays()
{
//properties: range, (color)
//0 no overlay
//1 solid color (NI)
//2 analog clock
//3 digital nixie-style clock one digit
//4 just static hour (NI)
//5 analog countdown
//6 digital one digit countdown
if (overlayCurrent == 0) return;
if (millis() - overlayRefreshedTime > overlayRefreshMs)
{
overlayRefreshedTime = millis();
initCronixie();
updateLocalTime();
switch (overlayCurrent)
{
case 1: _overlaySolid(); break;//solid secondary color
case 2: _overlayAnalogClock(); break;//2 analog clock
case 3: _overlayNixieClock(); break;//nixie 1-digit
case 5: _overlayAnalogCountdown(); break;//a.countdown
case 6: _overlayNixieCountdown(); break;//d.
case 4: _overlayCronixie();//Diamex cronixie clock kit
}
overlayRefreshedTime = millis();
}
}
void _overlaySolid()
{
uint32_t cls = (useGammaCorrectionRGB)? gamma8[white*16777216] + gamma8[col[0]]*65536 + gamma8[col[1]]*256 + gamma8[col[2]]:white*16777216 + col[0]*65536 + col[1]*256 + col[2];
strip.setRange(overlayMin,overlayMax,cls);
overlayRefreshMs = 1902;
}
void _overlayAnalogClock()
{
int overlaySize = overlayMax - overlayMin +1;
strip.unlockAll();
if (overlayDimBg)
if (overlayCountdown)
{
uint32_t ct = (white>>1)*16777216 + (col[0]>>1)*65536 + (col[1]>>1)*256 + (col[2]>>1);
if (useGammaCorrectionRGB) ct = (gamma8[white]>>1)*16777216 + (gamma8[col[0]]>>1)*65536 + (gamma8[col[1]]>>1)*256 + (gamma8[col[2]]>>1);
strip.setRange(overlayMin, overlayMax, ct);
_overlayAnalogCountdown(); return;
}
local = TZ.toLocal(now(), &tcr);
_overlaySolid();
double hourP = ((double)(hour(local)%12))/12;
double minuteP = ((double)minute(local))/60;
hourP = hourP + minuteP/12;
@ -160,7 +173,14 @@ void _overlayAnalogClock()
}
if (analogClockSecondsTrail)
{
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
if (secondPixel < analogClock12pixel)
{
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
strip.setRange(secondPixel, overlayMax, 0xFF0000);
} else
{
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
}
} else
{
strip.setIndividual(secondPixel, 0xFF0000);
@ -172,14 +192,14 @@ void _overlayAnalogClock()
void _overlayNixieClock()
{
if (overlayCountdown)
{
_overlayNixieCountdown(); return;
}
if (nixieClockI < 0)
{
local = TZ.toLocal(now(), &tcr);
overlayArr[0] = hour(local);
if (nixieClock12HourFormat && overlayArr[0] > 12)
{
overlayArr[0] = overlayArr[0]%12;
}
if (useAMPM) overlayArr[0] = overlayArr[0]%12;
overlayArr[1] = -1;
if (overlayArr[0] > 9)
{
@ -191,7 +211,7 @@ void _overlayNixieClock()
overlayArr[2] = overlayArr[2]/10;
overlayArr[4] = -1;
overlayArr[5] = -1;
if (nixieClockDisplaySeconds)
if (analogClockSecondsTrail)
{
overlayArr[4] = second(local);
overlayArr[5] = overlayArr[4]%10;
@ -202,8 +222,6 @@ void _overlayNixieClock()
if (overlayArr[i] != -1)
{
overlayArr[i] = overlayArr[i] + overlayMin;
if (overlayReverse)
overlayArr[i] = overlayMax - overlayArr[i];
}
}
overlayDur[0] = 12 + 12*(255 - overlaySpeed);
@ -331,5 +349,5 @@ void _overlayNixieCountdown()
}
_nixieNumber(diff, 800);
}
overlayRefreshMs = 998;
}
#endif

View File

@ -46,7 +46,7 @@ void handleAlexa()
void alexaOn()
{
if (alexaOnMacro == 255)
if (alexaOnMacro == 0)
{
handleSet((alexaNotify)?"win&T=1&IN":"win&T=1&NN&IN");
} else
@ -64,7 +64,7 @@ void alexaOn()
void alexaOff()
{
if (alexaOffMacro == 255)
if (alexaOffMacro == 0)
{
handleSet((alexaNotify)?"win&T=0&IN":"win&T=0&NN&IN");
} else

View File

@ -1,7 +1,6 @@
/*
* Support for the Cronixie clock
*/
#ifdef CRONIXIE
uint8_t getSameCodeLength(char code, int index, char const digits[])
{
uint8_t counter = 0;
@ -18,8 +17,9 @@ uint8_t getSameCodeLength(char code, int index, char const digits[])
return counter;
}
void setCronixie(char const digits[])
void setCronixie()
{
char digits[] = cronixieDisplay.substring(0,6);
/*
* digit purpose index
* 0-9 | 0-9 (incl. random)
@ -86,7 +86,7 @@ void setCronixie(char const digits[])
DEBUG_PRINT("cset ");
DEBUG_PRINTLN(digits);
cronixieRefreshMs = 1997; //Only refresh every 2secs if no seconds are displayed
overlayRefreshMs = 1997; //Only refresh every 2secs if no seconds are displayed
for (int i = 0; i < 6; i++)
{
@ -107,8 +107,8 @@ void setCronixie(char const digits[])
case 'a': dP[i] = 58; i++; break;
case 'm': dP[i] = 74 + getSameCodeLength('m',i,digits); i = i+dP[i]-74; break;
case 'M': dP[i] = 24 + getSameCodeLength('M',i,digits); i = i+dP[i]-24; break;
case 's': dP[i] = 80 + getSameCodeLength('s',i,digits); i = i+dP[i]-80; cronixieRefreshMs = 497; break; //refresh more often bc. of secs
case 'S': dP[i] = 30 + getSameCodeLength('S',i,digits); i = i+dP[i]-30; cronixieRefreshMs = 497; break;
case 's': dP[i] = 80 + getSameCodeLength('s',i,digits); i = i+dP[i]-80; overlayRefreshMs = 497; break; //refresh more often bc. of secs
case 'S': dP[i] = 30 + getSameCodeLength('S',i,digits); i = i+dP[i]-30; overlayRefreshMs = 497; break;
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,digits); i = i+dP[i]-36; break;
case 'y': dP[i] = 86 + getSameCodeLength('y',i,digits); i = i+dP[i]-86; break;
case 'I': dP[i] = 39 + getSameCodeLength('I',i,digits); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
@ -139,16 +139,12 @@ void setCronixie(char const digits[])
}
DEBUG_PRINTLN((int)dP[5]);
cronixieRefreshedTime = 0; //refresh immediately
_overlayCronixie(); //refresh
}
void handleCronixie()
void _overlayCronixie()
{
if (millis() - cronixieRefreshedTime > cronixieRefreshMs)
{
cronixieRefreshedTime = millis();
local = TZ.toLocal(now(), &tcr);
if (cronixieCountdown) checkCountdown();
if (overlayCountdown) checkCountdown();
uint8_t h = hour(local);
uint8_t h0 = h;
uint8_t m = minute(local);
@ -159,7 +155,7 @@ void handleCronixie()
//this has to be changed in time for 22nd century
y -= 2000; if (y<0) y += 30; //makes countdown work
if (cronixieUseAMPM && !cronixieCountdown)
if (useAMPM && !overlayCountdown)
{
if (h>12) h-=12;
else if (h==0) h+=12;
@ -213,6 +209,4 @@ void handleCronixie()
}
strip.setCronixieDigits(_digitOut);
//strip.trigger(); //this has a drawback, no effects slower than RefreshMs. advantage: Quick update, not dependant on effect time
}
}
#endif

View File

@ -86,16 +86,14 @@ void colorXYtoRGB(float x, float y, uint8_t* rgb) //coordinates to rgb (https://
b = b / r;
r = 1.0f;
}
}
else if (g > b && g > r) {
} else if (g > b && g > r) {
// green is biggest
if (g > 1.0f) {
r = r / g;
b = b / g;
g = 1.0f;
}
}
else if (b > r && b > g) {
} else if (b > r && b > g) {
// blue is biggest
if (b > 1.0f) {
r = r / b;
@ -117,4 +115,25 @@ void colorRGBtoXY(uint8_t* rgb, float* xy) //rgb to coordinates (https://www.dev
xy[1] = Y / (X + Y + Z);
}
void colorRGBtoRGBW(uint8_t* rgb, uint8_t* rgbw){} //rgb to rgbw, not imlemented yet
/*//For some reason min and max are not declared here
float minf (float v, float w)
{
if (w > v) return v;
return w;
}
float maxf (float v, float w)
{
if (w > v) return w;
return v;
}
void colorRGBtoRGBW(uint8_t* rgb, uint8_t* wht) //rgb to rgbw, untested and currently unused
{
*wht = (float)minf(rgb[0],minf(rgb[1],rgb[2]))*0.95;
rgb[0]-=wht;
rgb[1]-=wht;
rgb[2]-=wht;
}*/

View File

@ -45,7 +45,7 @@ bool sendHuePoll(bool sAuth)
{
bool st;
hueClient.setReuse(true);
hueClient.setTimeout(250);
hueClient.setTimeout(450);
String hueURL = "http://";
hueURL += hueIP.toString();
hueURL += "/api/";