Merge pull request #37 from Aircoookie/master

Update
This commit is contained in:
srg74 2020-02-23 20:53:18 -05:00 committed by GitHub
commit 4e85566b88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 381 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>
<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
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html>

View File

@ -1,23 +1,23 @@
/*
* Settings html
Settings html
*/
//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>)=====";
//settings menu
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>
<body onload=BB()>
<form action=/><button type=submit id=b>Back</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/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/time><button type=submit>Time & Macros</button></form>
<form action=/settings/sec><button type=submit>Security & Updates</button></form>
</body></html>)=====";
@ -172,6 +172,64 @@ Skip first LED: <input type=checkbox name=SL><hr>
</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
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>
@ -190,6 +248,7 @@ Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
</html>)=====";
//sync settings
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>

View File

@ -1,5 +1,5 @@
/*
* Main sketch, global variable declarations
Main sketch, global variable declarations
*/
/*
* @title WLED project sketch
@ -24,6 +24,7 @@
//#define WLED_DISABLE_INFRARED //there is no pin left for this on ESP8266-01, saves 25kb (!)
#define WLED_ENABLE_MQTT //saves 12kb
#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_ENABLE_FS_SERVING //Enable sending html file from SPIFFS before serving progmem version
@ -34,6 +35,10 @@
//library inclusions
#include <Arduino.h>
#ifdef WLED_ENABLE_DMX
#include <ESPDMX.h>
DMXESPSerial dmx;
#endif
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
@ -107,7 +112,6 @@
//version code in format yymmddb (b = daily build)
#define VERSION 2002192
char versionString[] = "0.9.1";
@ -257,6 +261,14 @@ bool aOtaEnabled = true; //ArduinoOTA allows easy updates d
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
//wifi
@ -480,6 +492,8 @@ WS2812FX strip = WS2812FX();
#include "SPIFFSEditor.h"
#endif
//turns all LEDs off and restarts ESP
void reset()
{
@ -517,6 +531,8 @@ bool oappendi(int i)
//boot starts here
void setup() {
wledInit();
}
@ -528,6 +544,7 @@ void loop() {
handleSerial();
handleNotifications();
handleTransitions();
handleDMX();
userLoop();
yield();

View File

@ -6,7 +6,7 @@
#define EEPSIZE 2560 //Maximum is 4096
//eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 16
#define EEPVER 17
//0 -> old version, default
//1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up
@ -24,6 +24,7 @@
//14-> 0.9.0-b1
//15-> 0.9.0-b3
//16-> 0.9.1
//17-> 0.9.1-dmx
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.
}
/*
* Write configuration to flash
*/
@ -257,6 +257,17 @@ void saveSettingsToEEPROM()
EEPROM.write(2522, mqttPort & 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();
}
@ -525,6 +536,17 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(2220, blynkApiKey, 35);
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
//2944 - 3071 reserved

View File

@ -162,7 +162,7 @@ void getSettingsJS(byte subPage, char* dest)
obuf = dest;
olen = 0;
if (subPage <1 || subPage >6) return;
if (subPage <1 || subPage >7) return;
if (subPage == 1) {
sappends('s',"CS",clientSSID);
@ -391,5 +391,30 @@ void getSettingsJS(byte subPage, char* dest)
oappendi(VERSION);
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>");
}

View File

@ -27,8 +27,9 @@ bool isAsterisksOnly(const char* str, byte maxLen)
//called upon POST settings form submit
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
if (subPage == 1)
@ -293,6 +294,29 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
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 == 2) {
strip.init(useRGBW,ledCount,skipFirstLed);

View File

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

View File

@ -231,7 +231,7 @@ void handleNightlight()
nightlightDelayMs = (int)(nightlightDelayMins*60000);
nightlightActiveOld = true;
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);
if (nightlightFade)
@ -239,7 +239,7 @@ void handleNightlight()
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
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);
}

View File

@ -82,6 +82,11 @@ void initServer()
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){
handleSettingsSet(request, 4);
serveMessage(request, 200,"Sync settings saved.","Redirecting...",1);
@ -201,6 +206,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){
if (captivePortal(request)) return;
serveIndexOrWelcome(request);
@ -301,10 +316,38 @@ String settingsProcessor(const String& var)
getSettingsJS(optionType, 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));
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)
{
@ -318,6 +361,9 @@ void serveSettings(AsyncWebServerRequest* request)
else if (url.indexOf("sync") > 0) subPage = 4;
else if (url.indexOf("time") > 0) subPage = 5;
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
if (subPage == 1 && wifiLock && otaLock)
@ -339,7 +385,8 @@ void serveSettings(AsyncWebServerRequest* request)
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 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;
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