Loxone support added (#1185)

* A separate socket for UDP api has been added. This uses the same API as HTML. Commands for Loxone were added to the API.

* html files for udp api newly generated

* codm pixel controller board configurations added to platformio.ini file

* Parser for LX/LY commands adapted. Calculation of the values corrected. Segment handling for LX/LY removed.

* Lox parser moved to own file. Lox parser added to the JSON api. Within a segment LX and LY are now supported.

* serial port removed

* F() macro added

Co-authored-by: Marius Groos <marius.groos@codm.de>
This commit is contained in:
m0fa 2020-09-27 11:37:16 +02:00 committed by GitHub
parent cac974b8e1
commit b10ab358da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1910 additions and 1660 deletions

View File

@ -375,3 +375,43 @@ build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build
extends = env:esp32dev extends = env:esp32dev
build_type = debug build_type = debug
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features} build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
# ------------------------------------------------------------------------------
# codm pixel controller board configurations
# ------------------------------------------------------------------------------
[env:codm-controller-0.4]
board = esp_wroom_02
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
[env:codm-controller-0.4-WS2801]
board = esp_wroom_02
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.4-APA102]
board = esp_wroom_02
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.5]
board = esp_wroom_02
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266}
[env:codm-controller-0.5-WS2801]
board = esp_wroom_02
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
[env:codm-controller-0.5-APA102]
board = esp_wroom_02
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_2m1m}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2

View File

@ -38,6 +38,10 @@ Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br> Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br> Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2"> Send notifications twice: <input type="checkbox" name="S2">
<h3>UDP Api</h3>
Enable UDP Api: <input type="checkbox" name="UAE"><br>
Port: <input name="UAP" type="number" min="1" max="65535" class="d5"><br>
<i>Reboot required to apply changes. </i>
<h3>Realtime</h3> <h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br> Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>Network DMX input</i><br> <i>Network DMX input</i><br>

View File

@ -223,4 +223,7 @@ void sappend(char stype, const char* key, int val);
void sappends(char stype, const char* key, char* val); void sappends(char stype, const char* key, char* val);
void getSettingsJS(byte subPage, char* dest); void getSettingsJS(byte subPage, char* dest);
//lx_parser.cpp
bool parseLx(int lxValue, int rgbw[4]);
#endif #endif

View File

@ -377,21 +377,24 @@ type="checkbox" name="RX">Effects<br>Send notifications on direct change: <input
type="checkbox" name="SB"><br>Send Alexa notifications: <input type="checkbox" type="checkbox" name="SB"><br>Send Alexa notifications: <input type="checkbox"
name="SA"><br>Send Philips Hue change notifications: <input type="checkbox" name="SA"><br>Send Philips Hue change notifications: <input type="checkbox"
name="SH"><br>Send Macro notifications: <input type="checkbox" name="SM"><br> name="SH"><br>Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2"><h3>Realtime</h3> Send notifications twice: <input type="checkbox" name="S2"><h3>UDP Api</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i> Enable UDP Api: <input type="checkbox" name="UAE"><br>Port: <input name="UAP"
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option type="number" min="1" max="65535" class="d5"><br><i>
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option Reboot required to apply changes.</i><h3>Realtime</h3>Receive UDP realtime:
value="0" selected="selected">Custom port</option></select><br><div id="xp"> <input type="checkbox" name="RD"><br><br><i>Network DMX input</i><br>Type:
Port: <input name="EP" type="number" min="1" max="65535" value="5568" <select name="DI" onchange="SP(),adj()"><option value="5568">E1.31 (sACN)
class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br> </option><option value="6454">Art-Net</option><option value="0"
Start universe: <input name="EU" type="number" min="0" max="63999" required><br> selected="selected">Custom port</option></select><br><div id="xp">Port: <input
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" name="EP" type="number" min="1" max="65535" value="5568" class="d5" required>
target="_blank">LedFx</a>!<br>Skip out-of-sequence packets: <input <br></div>Multicast: <input type="checkbox" name="EM"><br>Start universe: <input
type="checkbox" name="ES"><br>DMX start address: <input name="DA" type="number" name="EU" type="number" min="0" max="63999" required><br><i>Reboot required.
min="0" max="510" required><br>DMX mode: <select name="DM"><option value="0"> </i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx
Disabled</option><option value="1">Single RGB</option><option value="2"> </a>!<br>Skip out-of-sequence packets: <input type="checkbox" name="ES"><br>
Single DRGB</option><option value="3">Effect</option><option value="4">Multi RGB DMX start address: <input name="DA" type="number" min="0" max="510" required>
</option><option value="5">Dimmer + Multi RGB</option></select><br><a <br>DMX mode: <select name="DM"><option value="0">Disabled</option><option
value="1">Single RGB</option><option value="2">Single DRGB</option><option
value="3">Effect</option><option value="4">Multi RGB</option><option value="5">
Dimmer + Multi RGB</option></select><br><a
href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank"> href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">
E1.31 info</a><br>Timeout: <input name="ET" type="number" min="1" max="65000" E1.31 info</a><br>Timeout: <input name="ET" type="number" min="1" max="65000"
required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br> required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br>

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,58 @@ void deserializeSegment(JsonObject elem, byte it)
} }
} }
// lx parser
int lx = elem[F("lx")] | -1;
if (lx > 0) {
DEBUG_PRINT(F("LX: Lox primary = "));
DEBUG_PRINTLN(lx);
int rgbw[] = {0,0,0,0};
if (parseLx(lx, rgbw)) {
if (bri == 0) {
DEBUG_PRINTLN(F("LX: turn on"));
toggleOnOff();
}
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
if (id == strip.getMainSegmentId()) {
DEBUG_PRINTLN(F("LX: main segment"));
col[0] = rgbw[0];
col[1] = rgbw[1];
col[2] = rgbw[2];
col[3] = rgbw[3];
} else {
DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(id);
seg.colors[0] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
}
}
}
int ly = elem[F("ly")] | -1;
if (ly > 0) {
DEBUG_PRINT(F("LY: Lox secondary = "));
Serial.println(ly);
int rgbw[] = {0,0,0,0};
if (parseLx(ly, rgbw)) {
if (bri == 0) {
DEBUG_PRINTLN(F("LY: turn on"));
toggleOnOff();
}
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
if (id == strip.getMainSegmentId()) {
DEBUG_PRINTLN(F("LY: main segment"));
colSec[0] = rgbw[0];
colSec[1] = rgbw[1];
colSec[2] = rgbw[2];
colSec[3] = rgbw[3];
} else {
DEBUG_PRINT(F("LY: segment "));
DEBUG_PRINTLN(id);
seg.colors[1] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
}
}
}
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal); //if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED)); seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
seg.setOption(SEG_OPTION_REVERSED, elem[F("rev")] | seg.getOption(SEG_OPTION_REVERSED)); seg.setOption(SEG_OPTION_REVERSED, elem[F("rev")] | seg.getOption(SEG_OPTION_REVERSED));

78
wled00/lx_parser.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "wled.h"
bool parseLx(int lxValue, int rgbw[4])
{
bool ok = false;
float lxRed = 0;
float lxGreen = 0;
float lxBlue = 0;
if (lxValue < 200000000) {
// Loxone RGB
ok = true;
lxRed = round((lxValue % 1000) * 2.55);
lxGreen = round(((lxValue / 1000) % 1000) * 2.55);
lxBlue = round(((lxValue / 1000000) % 1000) * 2.55);
} else if ((lxValue >= 200000000) && (lxValue <= 201006500)) {
// Loxone Lumitech
ok = true;
float tmpBri = floor((lxValue - 200000000) / 10000); ;
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
float temp = 0;
tmpBri *= 2.55;
if (tmpBri < 0) {
tmpBri = 0;
} else if (tmpBri > 255) {
tmpBri = 255;
}
if (ct < 2700) {
ct = 2700;
} else if (ct > 6500) {
ct = 6500;
}
temp = ct / 100;
if (temp <= 66) {
lxRed = 255;
lxGreen = round(99.4708025861 * log(temp) - 161.1195681661);
if (temp <= 19) {
lxBlue = 0;
} else {
lxBlue = round(138.5177312231 * log((temp - 10)) - 305.0447927307);
}
} else {
lxRed = round(329.698727446 * pow((temp - 60), -0.1332047592));
lxGreen = round(288.1221695283 * pow((temp - 60), -0.0755148492));
lxBlue = 255;
}
lxRed *= (tmpBri/255);
lxGreen *= (tmpBri/255);
lxBlue *= (tmpBri/255);
}
if (ok) {
if (lxRed > 255) {
lxRed = 255;
} else if (lxRed < 0) {
lxRed = 0;
}
if (lxGreen > 255) {
lxGreen = 255;
} else if (lxGreen < 0) {
lxGreen = 0;
}
if (lxBlue > 255) {
lxBlue = 255;
} else if (lxBlue < 0) {
lxBlue = 0;
}
rgbw[0] = (uint8_t)lxRed;
rgbw[1] = (uint8_t)lxGreen;
rgbw[2] = (uint8_t)lxBlue;
rgbw[3] = 0;
return true;
}
return false;
}

View File

@ -1,5 +1,6 @@
#include "wled.h" #include "wled.h"
/* /*
* Receives client input * Receives client input
*/ */
@ -196,6 +197,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
hueStoreAllowed = true; hueStoreAllowed = true;
reconnectHue(); reconnectHue();
#endif #endif
// UDP Api
udpApiEnabled = request->hasArg("UAE");
t = request->arg("UAP").toInt();
if (t > 0) udpApiPort = t;
} }
//TIME //TIME
@ -416,6 +422,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
byte main = strip.getMainSegmentId(); byte main = strip.getMainSegmentId();
if (main != prevMain) setValuesFromMainSeg(); if (main != prevMain) setValuesFromMainSeg();
bool segGiven = false;
pos = req.indexOf(F("SS=")); pos = req.indexOf(F("SS="));
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
@ -507,6 +514,35 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
updateVal(&req, "B2=", &colSec[2]); updateVal(&req, "B2=", &colSec[2]);
updateVal(&req, "W2=", &colSec[3]); updateVal(&req, "W2=", &colSec[3]);
//lox parser
int rgbw[4] = {0,0,0,0};
pos = req.indexOf(F("LX=")); // Lox primary color
if (pos > 0) {
int lxValue = getNumVal(&req, pos);
if (parseLx(lxValue, rgbw)) {
col[0] = rgbw[0];
col[1] = rgbw[1];
col[2] = rgbw[2];
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
DEBUG_PRINT(F("LX: Lox primary = "));
DEBUG_PRINTLN(lxValue);
}
}
pos = req.indexOf(F("LY")); // Lox secondary color
if (pos > 0) {
int lxValue = getNumVal(&req, pos);
if(parseLx(lxValue, rgbw)) {
colSec[0] = rgbw[0];
colSec[1] = rgbw[1];
colSec[2] = rgbw[2];
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
DEBUG_PRINT(F("LY: Lox secondary = "));
DEBUG_PRINTLN(lxValue);
}
}
//set hue //set hue
pos = req.indexOf(F("HU=")); pos = req.indexOf(F("HU="));
if (pos > 0) { if (pos > 0) {

View File

@ -129,6 +129,7 @@ void handleNotifications()
//hyperion / raw RGB //hyperion / raw RGB
if (!packetSize && udpRgbConnected) { if (!packetSize && udpRgbConnected) {
packetSize = rgbUdp.parsePacket(); packetSize = rgbUdp.parsePacket();
if (packetSize) {
if (!receiveDirect) return; if (!receiveDirect) return;
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return; if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
realtimeIP = rgbUdp.remoteIP(); realtimeIP = rgbUdp.remoteIP();
@ -147,6 +148,23 @@ void handleNotifications()
strip.show(); strip.show();
return; return;
} }
}
// udp api
if (udpApiEnabled && !packetSize && udpApiConnected) {
packetSize = apiUdp.parsePacket();
if (packetSize) {
if (!receiveDirect) return;
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
uint8_t lbuf[packetSize];
apiUdp.read(lbuf, packetSize);
lbuf[packetSize] = '\0';
String apireq = "win&";
apireq += (char*)lbuf;
handleSet(nullptr, apireq);
return;
}
}
//notifier and UDP realtime //notifier and UDP realtime
if (!packetSize || packetSize > UDP_IN_MAXSIZE) return; if (!packetSize || packetSize > UDP_IN_MAXSIZE) return;

View File

@ -282,6 +282,9 @@ void WLED::initAP(bool resetAP)
if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) { if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) {
udpRgbConnected = rgbUdp.begin(udpRgbPort); udpRgbConnected = rgbUdp.begin(udpRgbPort);
} }
if (udpApiEnabled && udpApiPort > 0 && udpApiPort != ntpLocalPort && udpApiPort != udpPort && udpApiPort != udpRgbPort) {
udpApiConnected = apiUdp.begin(udpApiPort);
}
dnsServer.setErrorReplyCode(DNSReplyCode::NoError); dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", WiFi.softAPIP()); dnsServer.start(53, "*", WiFi.softAPIP());
@ -408,6 +411,8 @@ void WLED::initInterfaces()
udpConnected = notifierUdp.begin(udpPort); udpConnected = notifierUdp.begin(udpPort);
if (udpConnected && udpRgbPort != udpPort) if (udpConnected && udpRgbPort != udpPort)
udpRgbConnected = rgbUdp.begin(udpRgbPort); udpRgbConnected = rgbUdp.begin(udpRgbPort);
if (udpApiEnabled && udpConnected && udpApiPort != udpPort && udpApiPort != udpRgbPort)
udpApiConnected = apiUdp.begin(udpApiPort);
} }
if (ntpEnabled) if (ntpEnabled)
ntpConnected = ntpUdp.begin(ntpLocalPort); ntpConnected = ntpUdp.begin(ntpLocalPort);

View File

@ -215,6 +215,7 @@ WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
WLED_GLOBAL uint16_t udpApiPort _INIT(7000); // Udp api port
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
@ -259,6 +260,8 @@ WLED_GLOBAL char mqttPass[41] _INIT(""); // optional: password
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
WLED_GLOBAL uint16_t mqttPort _INIT(1883); WLED_GLOBAL uint16_t mqttPort _INIT(1883);
WLED_GLOBAL bool udpApiEnabled _INIT(true);
WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state
WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response
WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge
@ -377,7 +380,7 @@ WLED_GLOBAL byte effectIntensity _INIT(128);
WLED_GLOBAL byte effectPalette _INIT(0); WLED_GLOBAL byte effectPalette _INIT(0);
// network // network
WLED_GLOBAL bool udpConnected _INIT(false), udpRgbConnected _INIT(false); WLED_GLOBAL bool udpConnected _INIT(false), udpRgbConnected _INIT(false), udpApiConnected _INIT(false);;
// ui style // ui style
WLED_GLOBAL bool showWelcomePage _INIT(false); WLED_GLOBAL bool showWelcomePage _INIT(false);
@ -493,7 +496,7 @@ WLED_GLOBAL AsyncClient* hueClient _INIT(NULL);
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL); WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
// udp interface objects // udp interface objects
WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp; WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp, apiUdp;
WLED_GLOBAL WiFiUDP ntpUdp; WLED_GLOBAL WiFiUDP ntpUdp;
WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet))); WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet)));
WLED_GLOBAL bool e131NewData _INIT(false); WLED_GLOBAL bool e131NewData _INIT(false);

View File

@ -284,6 +284,10 @@ void saveSettingsToEEPROM()
} // last used: 2549. maybe leave a few bytes for future expansion and go on with 2600 kthxbye. } // last used: 2549. maybe leave a few bytes for future expansion and go on with 2600 kthxbye.
#endif #endif
EEPROM.write(2550, udpApiEnabled);
EEPROM.write(2551, udpApiPort & 0xFF);
EEPROM.write(2552, (udpApiPort >> 8) & 0xFF);
commit(); commit();
} }
@ -538,6 +542,11 @@ void loadSettingsFromEEPROM(bool first)
} }
#endif #endif
if (lastEEPROMversion > 19) {
udpApiEnabled = EEPROM.read(2550);
udpApiPort = EEPROM.read(2551) + ((EEPROM.read(2552) << 8) & 0xFF00);
}
receiveDirect = !EEPROM.read(2200); receiveDirect = !EEPROM.read(2200);
notifyMacro = EEPROM.read(2201); notifyMacro = EEPROM.read(2201);

View File

@ -316,6 +316,10 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("SA"),notifyAlexa); sappend('c',SET_F("SA"),notifyAlexa);
sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):"")); sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):""));
// UDP Api
sappend('c',"UAE",udpApiEnabled);
sappend('v',"UAP",udpApiPort);
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
sappend('c',SET_F("MQ"),mqttEnabled); sappend('c',SET_F("MQ"),mqttEnabled);
sappends('s',SET_F("MS"),mqttServer); sappends('s',SET_F("MS"),mqttServer);