This commit is contained in:
cschwinne 2020-02-24 12:45:47 +01:00
commit 5ffd29e31a
10 changed files with 433 additions and 100 deletions

View File

@ -15,6 +15,36 @@ const char PAGE_msg[] PROGMEM = R"=====(<!DOCTYPE html>
<style>.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}</style></head> <style>.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}</style></head>
<body><h2>%MSG%</body></html>)====="; <body><h2>%MSG%</body></html>)=====";
//DMX channel map
const char PAGE_dmxmap[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'>
<title>DMX Map</title>
<script>function B(){window.history.back()};function RS(){window.location = "/settings";}function RP(){top.location.href="/";}function FM() {%DMXVARS%
var dmxlabels = ["SET 0","RED","GREEN","BLUE","WHITE","SHUTTER","SET 255", "DISABLED"];
var dmxchans = [];
for (i=0;i<512;i++) {
dmxchans.push(7); // set all to DISABLED
}
for (i=0;i<LC;i++) {
FS = CS + (CG * i);
for (j=0;j<CN;j++) {
DA=FS+j;
dmxchans[DA-1] = CH[j];
}
}
DMXMap = "";
for (i=0;i<512;i++) {
isstart = "";
if ((i+1) % 10 == 0) {
isstart="S"
}
DMXMap += "<div class=\"anytype " + isstart + " type" + dmxchans[i] + "\">" + String(i+1) + "<br />" + dmxlabels[dmxchans[i]] + "</div>";
}
document.getElementById("map").innerHTML = DMXMap;
}</script>
<style>.anytype{border: 1px solid white; margin: 1px; float: left; width: 100px; height: 100px;}.S { margin: 0px; border: 2px solid white;} .type7{color: #888; border: 1px dotted grey;}.type6{color: #FFF;}.type4{color: #FFF; font-weight: bold; }.type3{color: #00F; font-weight: bold; }.type2{color: #0F0; font-weight: bold; }.type1{color: #F00; font-weight: bold; } .bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}</style></head>
<body onload="FM();"><div id="map">...</div></body></html>)=====";
//firmware update page //firmware update page
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html> const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html>

View File

@ -1,23 +1,23 @@
/* /*
* Settings html Settings html
*/ */
//common CSS of settings pages //common CSS of settings pages
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}</style>)====="; const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}</style>)=====";
//settings menu //settings menu
const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html> const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><title>WLED Settings</title><style>body{text-align:center;background:#222;height:100%;margin:0}html{--h:11.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:8vmin;height:var(--h);width:95%;margin-top:2.4vh}</style> <html><head><title>WLED Settings</title><style>body{text-align:center;background:#222;height:100%%;margin:0}html{--h:11.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:8vmin;height:var(--h);width:95%%;margin-top:2.4vh}</style>
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script></head> <script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script></head>
<body onload=BB()> <body onload=BB()>
<form action=/><button type=submit id=b>Back</button></form> <form action=/><button type=submit id=b>Back</button></form>
<form action=/settings/wifi><button type=submit>WiFi Setup</button></form> <form action=/settings/wifi><button type=submit>WiFi Setup</button></form>
<form action=/settings/leds><button type=submit>LED Preferences</button></form> <form action=/settings/leds><button type=submit>LED Preferences</button></form>
<form action=/settings/ui><button type=submit>User Interface</button></form> <form action=/settings/ui><button type=submit>User Interface</button></form>%DMXMENU%
<form action=/settings/sync><button type=submit>Sync Interfaces</button></form> <form action=/settings/sync><button type=submit>Sync Interfaces</button></form>
<form action=/settings/time><button type=submit>Time & Macros</button></form> <form action=/settings/time><button type=submit>Time & Macros</button></form>
<form action=/settings/sec><button type=submit>Security & Updates</button></form> <form action=/settings/sec><button type=submit>Security & Updates</button></form>
</body></html>)====="; </body></html>)=====";
@ -172,6 +172,64 @@ Skip first LED: <input type=checkbox name=SL><hr>
</form></body></html>)====="; </form></body></html>)=====";
#ifdef WLED_ENABLE_DMX
//DMX Output settings
const char PAGE_settings_dmx[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>DMX Settings</title><script>
function GCH(num) {
d=document;
d.getElementById('dmxchannels').innerHTML += "";
for (i=0;i<num;i++) {
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
}
}
function mMap(){
d=document;
numCh=document.Sf.CN.value;
numGap=document.Sf.CG.value;
if (parseInt(numCh)>parseInt(numGap)) {
d.getElementById("gapwarning").style.display="block";
} else {
d.getElementById("gapwarning").style.display="none";
}
for (i=0;i<15;i++) {
if (i>=numCh) {
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
d.getElementById("CH"+(i+1)).disabled = true;
} else {
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
d.getElementById("CH"+(i+1)).disabled = false;
}
}
}
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}function GetV(){var d=document;
%CSS%%SCSS%</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
<i>Number of fixtures is taken from LED config page</i><br>
channels per fixture (15 max): <input type="number" min="1" max="15" name="CN" maxlength="2" onchange="mMap();"><br />
start channel: <input type="number" min="1" max="512" name="CS" maxlength="2"><br />
spacing between start channels: <input type="number" min="1" max="512" name="CG" maxlength="2" onchange="mMap();"> [ <a href="javascript:alert('if set to 10, first fixture will start at 10,\nsecond will start at 20 etc.\nRegardless of the channel count.\nMakes memorizing channel numbers easier.');">info</a> ]<br>
<div id="gapwarning" style="color: orange; display: none;">WARNING: Channel gap is lower than channels per fixture.<br />This will cause overlap.</div>
<button type="button" onclick="location.href='/dmxmap';">DMX Map</button>
<h3>channel functions</h3>
<div id="dmxchannels"></div>
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>)=====";
#else
const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
#endif
//User Interface settings //User Interface settings
const char PAGE_settings_ui[] PROGMEM = R"=====(<!DOCTYPE html> const char PAGE_settings_ui[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>UI Settings</title><script> <html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>UI Settings</title><script>
@ -190,6 +248,7 @@ Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
</html>)====="; </html>)=====";
//sync settings //sync settings
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html> const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Sync Settings</title> <html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Sync Settings</title>

View File

@ -1,6 +1,6 @@
/* /*
* Main sketch, global variable declarations Main sketch, global variable declarations
*/ */
/* /*
* @title WLED project sketch * @title WLED project sketch
* @version 0.9.1 * @version 0.9.1
@ -24,6 +24,7 @@
//#define WLED_DISABLE_INFRARED //there is no pin left for this on ESP8266-01, saves 12kb //#define WLED_DISABLE_INFRARED //there is no pin left for this on ESP8266-01, saves 12kb
#define WLED_ENABLE_MQTT //saves 12kb #define WLED_ENABLE_MQTT //saves 12kb
#define WLED_ENABLE_ADALIGHT //saves 500b only #define WLED_ENABLE_ADALIGHT //saves 500b only
//#define WLED_ENABLE_DMX //uses 3.5kb
#define WLED_DISABLE_FILESYSTEM //SPIFFS is not used by any WLED feature yet #define WLED_DISABLE_FILESYSTEM //SPIFFS is not used by any WLED feature yet
//#define WLED_ENABLE_FS_SERVING //Enable sending html file from SPIFFS before serving progmem version //#define WLED_ENABLE_FS_SERVING //Enable sending html file from SPIFFS before serving progmem version
@ -34,6 +35,10 @@
//library inclusions //library inclusions
#include <Arduino.h> #include <Arduino.h>
#ifdef WLED_ENABLE_DMX
#include <ESPDMX.h>
DMXESPSerial dmx;
#endif
#ifdef ESP8266 #ifdef ESP8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
@ -42,11 +47,11 @@
#include <user_interface.h> #include <user_interface.h>
} }
#else #else
#include <WiFi.h> #include <WiFi.h>
#include "esp_wifi.h" #include "esp_wifi.h"
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <AsyncTCP.h> #include <AsyncTCP.h>
#include "SPIFFS.h" #include "SPIFFS.h"
#endif #endif
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
@ -54,20 +59,20 @@
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <DNSServer.h> #include <DNSServer.h>
#ifndef WLED_DISABLE_OTA #ifndef WLED_DISABLE_OTA
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#endif #endif
#include <SPIFFSEditor.h> #include <SPIFFSEditor.h>
#include "src/dependencies/time/TimeLib.h" #include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h" #include "src/dependencies/timezone/Timezone.h"
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
#define ESPALEXA_ASYNC #define ESPALEXA_ASYNC
#define ESPALEXA_NO_SUBPAGE #define ESPALEXA_NO_SUBPAGE
#define ESPALEXA_MAXDEVICES 1 #define ESPALEXA_MAXDEVICES 1
//#define ESPALEXA_DEBUG //#define ESPALEXA_DEBUG
#include "src/dependencies/espalexa/Espalexa.h" #include "src/dependencies/espalexa/Espalexa.h"
#endif #endif
#ifndef WLED_DISABLE_BLYNK #ifndef WLED_DISABLE_BLYNK
#include "src/dependencies/blynk/BlynkSimpleEsp.h" #include "src/dependencies/blynk/BlynkSimpleEsp.h"
#endif #endif
#include "src/dependencies/e131/ESPAsyncE131.h" #include "src/dependencies/e131/ESPAsyncE131.h"
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h" #include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
@ -82,16 +87,16 @@
#if IR_PIN < 0 #if IR_PIN < 0
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
#define WLED_DISABLE_INFRARED #define WLED_DISABLE_INFRARED
#endif #endif
#endif #endif
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
#include <IRremoteESP8266.h> #include <IRremoteESP8266.h>
#include <IRrecv.h> #include <IRrecv.h>
#include <IRutils.h> #include <IRutils.h>
#endif #endif
// remove flicker because PWM signal of RGB channels can become out of phase // remove flicker because PWM signal of RGB channels can become out of phase
#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266) #if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
@ -106,7 +111,7 @@
#endif #endif
//version code in format yymmddb (b = daily build) //version code in format yymmddb (b = daily build)
#define VERSION 2002222 #define VERSION 2002241
char versionString[] = "0.9.1"; char versionString[] = "0.9.1";
@ -145,8 +150,8 @@ bool useRGBW = false; //SK6812 strips can contain an ext
bool turnOnAtBoot = true; //turn on LEDs at power-up bool turnOnAtBoot = true; //turn on LEDs at power-up
byte bootPreset = 0; //save preset to load after power-up byte bootPreset = 0; //save preset to load after power-up
byte col[]{255, 160, 0, 0}; //default RGB(W) color byte col[] {255, 160, 0, 0}; //default RGB(W) color
byte colSec[]{0, 0, 0, 0}; //default RGB(W) secondary color byte colSec[] {0, 0, 0, 0}; //default RGB(W) secondary color
byte briS = 128; //default brightness byte briS = 128; //default brightness
byte nightlightTargetBri = 0; //brightness after nightlight is over byte nightlightTargetBri = 0; //brightness after nightlight is over
@ -214,7 +219,7 @@ bool huePollingEnabled = false; //poll hue bridge for light state
uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response
char hueApiKey[47] = "api"; //key token will be obtained from bridge char hueApiKey[47] = "api"; //key token will be obtained from bridge
byte huePollLightId = 1; //ID of hue lamp to sync to. Find the ID in the hue app ("about" section) byte huePollLightId = 1; //ID of hue lamp to sync to. Find the ID in the hue app ("about" section)
IPAddress hueIP = (0,0,0,0); //IP address of the bridge IPAddress hueIP = (0, 0, 0, 0); //IP address of the bridge
bool hueApplyOnOff = true; bool hueApplyOnOff = true;
bool hueApplyBri = true; bool hueApplyBri = true;
bool hueApplyColor = true; bool hueApplyColor = true;
@ -227,7 +232,7 @@ byte currentTimezone = 0; //Timezone ID. Refer to timezones
int utcOffsetSecs = 0; //Seconds to offset from UTC before timzone calculation int utcOffsetSecs = 0; //Seconds to offset from UTC before timzone calculation
byte overlayDefault = 0; //0: no overlay 1: analog clock 2: single-digit clocl 3: cronixie byte overlayDefault = 0; //0: no overlay 1: analog clock 2: single-digit clocl 3: cronixie
byte overlayMin = 0, overlayMax = ledCount-1; //boundaries of overlay mode byte overlayMin = 0, overlayMax = ledCount - 1; //boundaries of overlay mode
byte analogClock12pixel = 0; //The pixel in your strip where "midnight" would be byte analogClock12pixel = 0; //The pixel in your strip where "midnight" would be
bool analogClockSecondsTrail = false; //Display seconds as trail of LEDs instead of a single pixel bool analogClockSecondsTrail = false; //Display seconds as trail of LEDs instead of a single pixel
@ -257,6 +262,14 @@ bool aOtaEnabled = true; //ArduinoOTA allows easy updates d
uint16_t userVar0 = 0, userVar1 = 0; uint16_t userVar0 = 0, userVar1 = 0;
//dmx CONFIG
uint16_t DMXChannels = 7; // number of channels per fixture
uint16_t DMXFixtureMap[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// assigns the different channels to different functions. See wled21_dmx.ino for more information.
uint16_t DMXGap = 10; // gap between the fixtures. makes addressing easier because you don't have to memorize odd numbers when climbing up onto a rig.
uint16_t DMXStart = 10; // start address of the first fixture
//internal global variable declarations //internal global variable declarations
//wifi //wifi
@ -267,12 +280,12 @@ bool interfacesInited = false;
bool wasConnected = false; bool wasConnected = false;
//color //color
byte colOld[]{0, 0, 0, 0}; //color before transition byte colOld[] {0, 0, 0, 0}; //color before transition
byte colT[]{0, 0, 0, 0}; //current color byte colT[] {0, 0, 0, 0}; //current color
byte colIT[]{0, 0, 0, 0}; //color that was last sent to LEDs byte colIT[] {0, 0, 0, 0}; //color that was last sent to LEDs
byte colSecT[]{0, 0, 0, 0}; byte colSecT[] {0, 0, 0, 0};
byte colSecOld[]{0, 0, 0, 0}; byte colSecOld[] {0, 0, 0, 0};
byte colSecIT[]{0, 0, 0, 0}; byte colSecIT[] {0, 0, 0, 0};
byte lastRandomIndex = 0; //used to save last random color so the new one is not the same byte lastRandomIndex = 0; //used to save last random color so the new one is not the same
@ -291,7 +304,7 @@ uint32_t nightlightDelayMs = 10;
uint8_t nightlightDelayMinsDefault = nightlightDelayMins; uint8_t nightlightDelayMinsDefault = nightlightDelayMins;
unsigned long nightlightStartTime; unsigned long nightlightStartTime;
byte briNlT = 0; //current nightlight brightness byte briNlT = 0; //current nightlight brightness
byte colNlT[]{0, 0, 0, 0}; //current nightlight color byte colNlT[] {0, 0, 0, 0}; //current nightlight color
//brightness //brightness
unsigned long lastOnTime = 0; unsigned long lastOnTime = 0;
@ -331,9 +344,9 @@ bool showWelcomePage = false;
//hue //hue
char hueError[25] = "Inactive"; char hueError[25] = "Inactive";
//uint16_t hueFailCount = 0; //uint16_t hueFailCount = 0;
float hueXLast=0, hueYLast=0; float hueXLast = 0, hueYLast = 0;
uint16_t hueHueLast=0, hueCtLast=0; uint16_t hueHueLast = 0, hueCtLast = 0;
byte hueSatLast=0, hueBriLast=0; byte hueSatLast = 0, hueBriLast = 0;
unsigned long hueLastRequestSent = 0; unsigned long hueLastRequestSent = 0;
bool hueAuthRequired = false; bool hueAuthRequired = false;
bool hueReceived = false; bool hueReceived = false;
@ -346,7 +359,7 @@ unsigned long overlayRefreshMs = 200;
unsigned long overlayRefreshedTime; unsigned long overlayRefreshedTime;
//cronixie //cronixie
byte dP[]{0,0,0,0,0,0}; byte dP[] {0, 0, 0, 0, 0, 0};
bool cronixieInit = false; bool cronixieInit = false;
//countdown //countdown
@ -355,10 +368,10 @@ bool countdownOverTriggered = true;
//timer //timer
byte lastTimerMinute = 0; byte lastTimerMinute = 0;
byte timerHours[] = {0,0,0,0,0,0,0,0}; byte timerHours[] = {0, 0, 0, 0, 0, 0, 0, 0};
byte timerMinutes[] = {0,0,0,0,0,0,0,0}; byte timerMinutes[] = {0, 0, 0, 0, 0, 0, 0, 0};
byte timerMacro[] = {0,0,0,0,0,0,0,0}; byte timerMacro[] = {0, 0, 0, 0, 0, 0, 0, 0};
byte timerWeekday[] = {255,255,255,255,255,255,255,255}; //weekdays to activate on byte timerWeekday[] = {255, 255, 255, 255, 255, 255, 255, 255}; //weekdays to activate on
//bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity //bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
//blynk //blynk
@ -436,8 +449,8 @@ AsyncClient* hueClient = NULL;
AsyncMqttClient* mqtt = NULL; AsyncMqttClient* mqtt = NULL;
//function prototypes //function prototypes
void colorFromUint32(uint32_t,bool=false); void colorFromUint32(uint32_t, bool = false);
void serveMessage(AsyncWebServerRequest*,uint16_t,String,String,byte); void serveMessage(AsyncWebServerRequest*, uint16_t, String, String, byte);
void handleE131Packet(e131_packet_t*, IPAddress); void handleE131Packet(e131_packet_t*, IPAddress);
void arlsLock(uint32_t,byte); void arlsLock(uint32_t,byte);
void handleOverlayDraw(); void handleOverlayDraw();
@ -458,34 +471,36 @@ WS2812FX strip = WS2812FX();
//debug macros //debug macros
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
#define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINT(x) Serial.print (x)
#define DEBUG_PRINTLN(x) Serial.println (x) #define DEBUG_PRINTLN(x) Serial.println (x)
#define DEBUG_PRINTF(x) Serial.printf (x) #define DEBUG_PRINTF(x) Serial.printf (x)
unsigned long debugTime = 0; unsigned long debugTime = 0;
int lastWifiState = 3; int lastWifiState = 3;
unsigned long wifiStateChangedTime = 0; unsigned long wifiStateChangedTime = 0;
int loops = 0; int loops = 0;
#else #else
#define DEBUG_PRINT(x) #define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x) #define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x) #define DEBUG_PRINTF(x)
#endif #endif
//filesystem //filesystem
#ifndef WLED_DISABLE_FILESYSTEM #ifndef WLED_DISABLE_FILESYSTEM
#include <FS.h> #include <FS.h>
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include "SPIFFS.h" #include "SPIFFS.h"
#endif
#include "SPIFFSEditor.h"
#endif #endif
#include "SPIFFSEditor.h"
#endif
//turns all LEDs off and restarts ESP //turns all LEDs off and restarts ESP
void reset() void reset()
{ {
briT = 0; briT = 0;
long dly = millis(); long dly = millis();
while(millis() - dly < 250) while (millis() - dly < 250)
{ {
yield(); //enough time to send response to client yield(); //enough time to send response to client
} }
@ -510,13 +525,15 @@ bool oappend(const char* txt)
bool oappendi(int i) bool oappendi(int i)
{ {
char s[11]; char s[11];
sprintf(s,"%ld", i); sprintf(s, "%ld", i);
return oappend(s); return oappend(s);
} }
//boot starts here //boot starts here
void setup() { void setup() {
wledInit(); wledInit();
} }
@ -528,6 +545,7 @@ void loop() {
handleSerial(); handleSerial();
handleNotifications(); handleNotifications();
handleTransitions(); handleTransitions();
handleDMX();
userLoop(); userLoop();
yield(); yield();
@ -547,9 +565,9 @@ void loop() {
if (!realtimeMode) //block stuff if WARLS/Adalight is enabled if (!realtimeMode) //block stuff if WARLS/Adalight is enabled
{ {
if (apActive) dnsServer.processNextRequest(); if (apActive) dnsServer.processNextRequest();
#ifndef WLED_DISABLE_OTA #ifndef WLED_DISABLE_OTA
if (WLED_CONNECTED && aOtaEnabled) ArduinoOTA.handle(); if (WLED_CONNECTED && aOtaEnabled) ArduinoOTA.handle();
#endif #endif
handleNightlight(); handleNightlight();
yield(); yield();
@ -566,26 +584,26 @@ void loop() {
if (millis() - lastMqttReconnectAttempt > 30000) initMqtt(); if (millis() - lastMqttReconnectAttempt > 30000) initMqtt();
//DEBUG serial logging //DEBUG serial logging
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if (millis() - debugTime > 9999) if (millis() - debugTime > 9999)
{ {
DEBUG_PRINTLN("---DEBUG INFO---"); DEBUG_PRINTLN("---DEBUG INFO---");
DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis()); DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now()); DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now());
DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status()); DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
if (WiFi.status() != lastWifiState) if (WiFi.status() != lastWifiState)
{ {
wifiStateChangedTime = millis(); wifiStateChangedTime = millis();
} }
lastWifiState = WiFi.status(); lastWifiState = WiFi.status();
DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime); DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime); DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP()); DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP());
DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops/10); DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops / 10);
loops = 0; loops = 0;
debugTime = millis(); debugTime = millis();
} }
loops++; loops++;
#endif #endif
} }

View File

@ -6,7 +6,7 @@
#define EEPSIZE 2560 //Maximum is 4096 #define EEPSIZE 2560 //Maximum is 4096
//eeprom Version code, enables default settings instead of 0 init on update //eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 16 #define EEPVER 17
//0 -> old version, default //0 -> old version, default
//1 -> 0.4p 1711272 and up //1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up //2 -> 0.4p 1711302 and up
@ -24,6 +24,7 @@
//14-> 0.9.0-b1 //14-> 0.9.0-b1
//15-> 0.9.0-b3 //15-> 0.9.0-b3
//16-> 0.9.1 //16-> 0.9.1
//17-> 0.9.1-dmx
void commit() void commit()
{ {
@ -63,7 +64,6 @@ void readStringFromEEPROM(uint16_t pos, char* str, uint16_t len)
str[len] = 0; //make sure every string is properly terminated. str must be at least len +1 big. str[len] = 0; //make sure every string is properly terminated. str must be at least len +1 big.
} }
/* /*
* Write configuration to flash * Write configuration to flash
*/ */
@ -257,6 +257,17 @@ void saveSettingsToEEPROM()
EEPROM.write(2522, mqttPort & 0xFF); EEPROM.write(2522, mqttPort & 0xFF);
EEPROM.write(2523, (mqttPort >> 8) & 0xFF); EEPROM.write(2523, (mqttPort >> 8) & 0xFF);
// DMX (2530 - 2549)
EEPROM.write(2530, DMXChannels);
EEPROM.write(2531, DMXGap & 0xFF);
EEPROM.write(2532, (DMXGap >> 8) & 0xFF);
EEPROM.write(2533, DMXStart & 0xFF);
EEPROM.write(2534, (DMXStart >> 8) & 0xFF);
for (int i=0;i<15;i++) {
EEPROM.write(2535+i, DMXFixtureMap[i]);
} // last used: 2549. maybe leave a few bytes for future expansion and go on with 2600 kthxbye.
commit(); commit();
} }
@ -525,6 +536,17 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(2220, blynkApiKey, 35); readStringFromEEPROM(2220, blynkApiKey, 35);
if (strlen(blynkApiKey) < 25) blynkApiKey[0] = 0; if (strlen(blynkApiKey) < 25) blynkApiKey[0] = 0;
// DMX (2530 - 2549)2535
DMXChannels = EEPROM.read(2530);
DMXGap = EEPROM.read(2531) + ((EEPROM.read(2532) << 8) & 0xFF00);
DMXStart = EEPROM.read(2533) + ((EEPROM.read(2534) << 8) & 0xFF00);
for (int i=0;i<15;i++) {
DMXFixtureMap[i] = EEPROM.read(2535+i);
} //last used: 2549. maybe leave a few bytes for future expansion and go on with 2600 kthxbye.
//user MOD memory //user MOD memory
//2944 - 3071 reserved //2944 - 3071 reserved

View File

@ -99,6 +99,53 @@ char* XML_response(AsyncWebServerRequest *request, char* dest = nullptr)
if (request != nullptr) request->send(200, "text/xml", obuf); if (request != nullptr) request->send(200, "text/xml", obuf);
} }
char* URL_response(AsyncWebServerRequest *request)
{
char sbuf[256]; //allocate local buffer if none passed
char s2buf[100];
obuf = s2buf;
olen = 0;
char s[16];
oappend("http://");
IPAddress localIP = WiFi.localIP();
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
oappend(s);
oappend("/win&A=");
oappendi(bri);
oappend("&CL=h");
for (int i = 0; i < 3; i++)
{
sprintf(s,"%02X", col[i]);
oappend(s);
}
oappend("&C2=h");
for (int i = 0; i < 3; i++)
{
sprintf(s,"%02X", colSec[i]);
oappend(s);
}
oappend("&FX=");
oappendi(effectCurrent);
oappend("&SX=");
oappendi(effectSpeed);
oappend("&IX=");
oappendi(effectIntensity);
oappend("&FP=");
oappendi(effectPalette);
obuf = sbuf;
olen = 0;
oappend("<html><body><a href=\"");
oappend(s2buf);
oappend("\" target=\"_blank\">");
oappend(s2buf);
oappend("</a></body></html>");
if (request != nullptr) request->send(200, "text/html", obuf);
}
//append a numeric setting to string buffer //append a numeric setting to string buffer
void sappend(char stype, const char* key, int val) void sappend(char stype, const char* key, int val)
{ {
@ -162,7 +209,7 @@ void getSettingsJS(byte subPage, char* dest)
obuf = dest; obuf = dest;
olen = 0; olen = 0;
if (subPage <1 || subPage >6) return; if (subPage <1 || subPage >7) return;
if (subPage == 1) { if (subPage == 1) {
sappends('s',"CS",clientSSID); sappends('s',"CS",clientSSID);
@ -391,5 +438,30 @@ void getSettingsJS(byte subPage, char* dest)
oappendi(VERSION); oappendi(VERSION);
oappend(") OK\";"); oappend(") OK\";");
} }
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
if (subPage == 7)
{
sappend('v',"CN",DMXChannels);
sappend('v',"CG",DMXGap);
sappend('v',"CS",DMXStart);
sappend('i',"CH1",DMXFixtureMap[0]);
sappend('i',"CH2",DMXFixtureMap[1]);
sappend('i',"CH3",DMXFixtureMap[2]);
sappend('i',"CH4",DMXFixtureMap[3]);
sappend('i',"CH5",DMXFixtureMap[4]);
sappend('i',"CH6",DMXFixtureMap[5]);
sappend('i',"CH7",DMXFixtureMap[6]);
sappend('i',"CH8",DMXFixtureMap[7]);
sappend('i',"CH9",DMXFixtureMap[8]);
sappend('i',"CH10",DMXFixtureMap[9]);
sappend('i',"CH11",DMXFixtureMap[10]);
sappend('i',"CH12",DMXFixtureMap[11]);
sappend('i',"CH13",DMXFixtureMap[12]);
sappend('i',"CH14",DMXFixtureMap[13]);
sappend('i',"CH15",DMXFixtureMap[14]);
}
#endif
oappend("}</script>"); oappend("}</script>");
} }

View File

@ -27,8 +27,9 @@ bool isAsterisksOnly(const char* str, byte maxLen)
//called upon POST settings form submit //called upon POST settings form submit
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{ {
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec
if (subPage <1 || subPage >6) return; //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX
if (subPage <1 || subPage >7) return;
//WIFI SETTINGS //WIFI SETTINGS
if (subPage == 1) if (subPage == 1)
@ -293,6 +294,29 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
aOtaEnabled = request->hasArg("AO"); aOtaEnabled = request->hasArg("AO");
} }
} }
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
if (subPage == 7)
{
int t = request->arg("CN").toInt();
if (t>0 && t<16) {
DMXChannels = t;
}
t = request->arg("CS").toInt();
if (t>0 && t<513) {
DMXStart = t;
}
t = request->arg("CG").toInt();
if (t>0 && t<513) {
DMXGap = t;
}
for (int i=0; i<15; i++) {
String argname = "CH" + String((i+1));
t = request->arg(argname).toInt();
DMXFixtureMap[i] = t;
}
}
#endif
if (subPage != 6 || !doReboot) saveSettingsToEEPROM(); //do not save if factory reset if (subPage != 6 || !doReboot) saveSettingsToEEPROM(); //do not save if factory reset
if (subPage == 2) { if (subPage == 2) {
strip.init(useRGBW,ledCount,skipFirstLed); strip.init(useRGBW,ledCount,skipFirstLed);

View File

@ -83,7 +83,9 @@ void wledInit()
if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS);
} }
#endif #endif
#ifdef WLED_ENABLE_DMX
dmx.init(512); // initialize with bus length
#endif
//HTTP server page init //HTTP server page init
initServer(); initServer();
} }

View File

@ -231,15 +231,15 @@ void handleNightlight()
nightlightDelayMs = (int)(nightlightDelayMins*60000); nightlightDelayMs = (int)(nightlightDelayMins*60000);
nightlightActiveOld = true; nightlightActiveOld = true;
briNlT = bri; briNlT = bri;
for (byte i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color for (byte i=0; i<4; i++) colNlT[i] = colT[i]; // remember starting color
} }
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs); float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
if (nightlightFade) if (nightlightFade)
{ {
bri = briNlT + ((nightlightTargetBri - briNlT)*nper); bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
if (nightlightColorFade) // color fading only is enabled with "NF=2" if (nightlightColorFade) // color fading only is enabled with "NF=2"
{ {
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color for (byte i=0; i<4; i++) colT[i] = colNlT[i]+ ((colSecT[i] - colNlT[i])*nper); // fading from actual color to secondary color
} }
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY); colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
} }

View File

@ -82,6 +82,11 @@ void initServer()
serveMessage(request, 200,"UI settings saved.","Redirecting...",1); serveMessage(request, 200,"UI settings saved.","Redirecting...",1);
}); });
server.on("/settings/dmx", HTTP_POST, [](AsyncWebServerRequest *request){
handleSettingsSet(request, 7);
serveMessage(request, 200,"UI settings saved.","Redirecting...",1);
});
server.on("/settings/sync", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/settings/sync", HTTP_POST, [](AsyncWebServerRequest *request){
handleSettingsSet(request, 4); handleSettingsSet(request, 4);
serveMessage(request, 200,"Sync settings saved.","Redirecting...",1); serveMessage(request, 200,"Sync settings saved.","Redirecting...",1);
@ -138,6 +143,10 @@ void initServer()
request->send_P(200, "text/html", PAGE_usermod); request->send_P(200, "text/html", PAGE_usermod);
}); });
server.on("/url", HTTP_GET, [](AsyncWebServerRequest *request){
URL_response(request);
});
server.on("/teapot", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/teapot", HTTP_GET, [](AsyncWebServerRequest *request){
serveMessage(request, 418, "418. I'm a teapot.", "(Tangible Embedded Advanced Project Of Twinkling)", 254); serveMessage(request, 418, "418. I'm a teapot.", "(Tangible Embedded Advanced Project Of Twinkling)", 254);
}); });
@ -201,6 +210,16 @@ void initServer()
}); });
} }
#ifdef WLED_ENABLE_DMX
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", PAGE_dmxmap , dmxProcessor);
});
#else
server.on("/dmxmap", HTTP_GET, [](AsyncWebServerRequest *request){
serveMessage(request, 501, "Not implemented", "DMX support is not enabled in this build.", 254);
});
#endif
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if (captivePortal(request)) return; if (captivePortal(request)) return;
serveIndexOrWelcome(request); serveIndexOrWelcome(request);
@ -301,10 +320,38 @@ String settingsProcessor(const String& var)
getSettingsJS(optionType, buf); getSettingsJS(optionType, buf);
return String(buf); return String(buf);
} }
#ifdef WLED_ENABLE_DMX
if (var == "DMXMENU") {
return String("<form action=/settings/dmx><button type=submit>DMX Output</button></form>");
}
#endif
if (var == "SCSS") return String(FPSTR(PAGE_settingsCss)); if (var == "SCSS") return String(FPSTR(PAGE_settingsCss));
return String(); return String();
} }
String dmxProcessor(const String& var)
{
String mapJS;
#ifdef WLED_ENABLE_DMX
if (var == "DMXVARS") {
mapJS += "\nCN=" + String(DMXChannels) + ";\n";
mapJS += "CS=" + String(DMXStart) + ";\n";
mapJS += "CG=" + String(DMXGap) + ";\n";
mapJS += "LC=" + String(ledCount) + ";\n";
mapJS += "var CH=[";
for (int i=0;i<15;i++) {
mapJS += String(DMXFixtureMap[i]) + ",";
}
mapJS += "0];";
}
#endif
return mapJS;
}
void serveSettings(AsyncWebServerRequest* request) void serveSettings(AsyncWebServerRequest* request)
{ {
@ -318,6 +365,9 @@ void serveSettings(AsyncWebServerRequest* request)
else if (url.indexOf("sync") > 0) subPage = 4; else if (url.indexOf("sync") > 0) subPage = 4;
else if (url.indexOf("time") > 0) subPage = 5; else if (url.indexOf("time") > 0) subPage = 5;
else if (url.indexOf("sec") > 0) subPage = 6; else if (url.indexOf("sec") > 0) subPage = 6;
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
else if (url.indexOf("dmx") > 0) subPage = 7;
#endif
} else subPage = 255; //welcome page } else subPage = 255; //welcome page
if (subPage == 1 && wifiLock && otaLock) if (subPage == 1 && wifiLock && otaLock)
@ -339,7 +389,8 @@ void serveSettings(AsyncWebServerRequest* request)
case 4: request->send_P(200, "text/html", PAGE_settings_sync, settingsProcessor); break; case 4: request->send_P(200, "text/html", PAGE_settings_sync, settingsProcessor); break;
case 5: request->send_P(200, "text/html", PAGE_settings_time, settingsProcessor); break; case 5: request->send_P(200, "text/html", PAGE_settings_time, settingsProcessor); break;
case 6: request->send_P(200, "text/html", PAGE_settings_sec , settingsProcessor); break; case 6: request->send_P(200, "text/html", PAGE_settings_sec , settingsProcessor); break;
case 7: request->send_P(200, "text/html", PAGE_settings_dmx , settingsProcessor); break;
case 255: request->send_P(200, "text/html", PAGE_welcome); break; case 255: request->send_P(200, "text/html", PAGE_welcome); break;
default: request->send_P(200, "text/html", PAGE_settings); default: request->send_P(200, "text/html", PAGE_settings , settingsProcessor);
} }
} }

55
wled00/wled21_dmx.ino Normal file
View File

@ -0,0 +1,55 @@
/*
* Support for DMX via MAX485.
* Needs the espdmx library. You might have to change the output pin within the library. Sketchy, i know.
* https://github.com/Rickgg/ESP-Dmx
*/
#ifdef WLED_ENABLE_DMX
void handleDMX() {
// TODO: calculate brightness manually if no shutter channel is set
uint8_t brightness = strip.getBrightness();
for (int i = 0; i < ledCount; i++) { // uses the amount of LEDs as fixture count
uint32_t in = strip.getPixelColor(i); // time to get the colors for the individual fixtures as suggested by AirCookie at issue #462
byte w = in >> 24 & 0xFF;
byte r = in >> 16 & 0xFF;
byte g = in >> 8 & 0xFF;
byte b = in & 0xFF;
int DMXFixtureStart = DMXStart + (DMXGap * i);
for (int j = 0; j < DMXChannels; j++) {
int DMXAddr = DMXFixtureStart + j;
switch (DMXFixtureMap[j]) {
case 0: // Set this channel to 0. Good way to tell strobe- and fade-functions to fuck right off.
dmx.write(DMXAddr, 0);
break;
case 1: // Red
dmx.write(DMXAddr, r);
break;
case 2: // Green
dmx.write(DMXAddr, g);
break;
case 3: // Blue
dmx.write(DMXAddr, b);
break;
case 4: // White
dmx.write(DMXAddr, w);
break;
case 5: // Shutter channel. Controls the brightness.
dmx.write(DMXAddr, brightness);
break;
case 6:// Sets this channel to 255. Like 0, but more wholesome.
dmx.write(DMXAddr, 255);
break;
}
}
}
dmx.update(); // update the DMX bus
}
#else
void handleDMX() {}
#endif