WebSockets
Better TwinkleFox speed regulation
This commit is contained in:
parent
2d4d7bf937
commit
3b3f8e6f43
@ -165,7 +165,7 @@ lib_deps =
|
|||||||
ESPAsyncTCP@1.2.0
|
ESPAsyncTCP@1.2.0
|
||||||
ESPAsyncUDP@697c75a025
|
ESPAsyncUDP@697c75a025
|
||||||
AsyncTCP@1.0.3
|
AsyncTCP@1.0.3
|
||||||
Esp Async WebServer@1.2.0
|
https://github.com/Aircoookie/ESPAsyncWebServer
|
||||||
IRremoteESP8266@2.7.3
|
IRremoteESP8266@2.7.3
|
||||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||||
#TFT_eSPI
|
#TFT_eSPI
|
||||||
|
@ -2247,7 +2247,7 @@ uint16_t WS2812FX::mode_ripple_rainbow(void) {
|
|||||||
CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
|
CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
|
||||||
{
|
{
|
||||||
// Overall twinkle speed (changed)
|
// Overall twinkle speed (changed)
|
||||||
uint16_t ticks = ms / (32 - (SEGMENT.speed >> 3));
|
uint16_t ticks = ms / SEGENV.aux0;
|
||||||
uint8_t fastcycle8 = ticks;
|
uint8_t fastcycle8 = ticks;
|
||||||
uint16_t slowcycle16 = (ticks >> 8) + salt;
|
uint16_t slowcycle16 = (ticks >> 8) + salt;
|
||||||
slowcycle16 += sin8(slowcycle16);
|
slowcycle16 += sin8(slowcycle16);
|
||||||
@ -2312,10 +2312,11 @@ uint16_t WS2812FX::twinklefox_base(bool cat)
|
|||||||
// numbers that it generates is (paradoxically) stable.
|
// numbers that it generates is (paradoxically) stable.
|
||||||
uint16_t PRNG16 = 11337;
|
uint16_t PRNG16 = 11337;
|
||||||
|
|
||||||
|
// Calculate speed
|
||||||
|
if (SEGMENT.speed > 100) SEGENV.aux0 = 3 + ((255 - SEGMENT.speed) >> 3);
|
||||||
|
else SEGENV.aux0 = 22 + ((100 - SEGMENT.speed) >> 1);
|
||||||
|
|
||||||
// Set up the background color, "bg".
|
// Set up the background color, "bg".
|
||||||
// if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of
|
|
||||||
// the current palette are identical, then a deeply faded version of
|
|
||||||
// that color is used for the background color
|
|
||||||
CRGB bg;
|
CRGB bg;
|
||||||
bg = col_to_crgb(SEGCOLOR(1));
|
bg = col_to_crgb(SEGCOLOR(1));
|
||||||
uint8_t bglight = bg.getAverageLight();
|
uint8_t bglight = bg.getAverageLight();
|
||||||
|
@ -87,7 +87,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id);
|
|||||||
void serializeState(JsonObject root);
|
void serializeState(JsonObject root);
|
||||||
void serializeInfo(JsonObject root);
|
void serializeInfo(JsonObject root);
|
||||||
void serveJson(AsyncWebServerRequest* request);
|
void serveJson(AsyncWebServerRequest* request);
|
||||||
void serveLiveLeds(AsyncWebServerRequest* request);
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||||
|
|
||||||
//led.cpp
|
//led.cpp
|
||||||
void setValuesFromMainSeg();
|
void setValuesFromMainSeg();
|
||||||
@ -210,6 +210,11 @@ String settingsProcessor(const String& var);
|
|||||||
String dmxProcessor(const String& var);
|
String dmxProcessor(const String& var);
|
||||||
void serveSettings(AsyncWebServerRequest* request);
|
void serveSettings(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
|
//ws.cpp
|
||||||
|
void handleWs();
|
||||||
|
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||||
|
void sendDataWs(AsyncWebSocketClient * client = nullptr);
|
||||||
|
|
||||||
//xml.cpp
|
//xml.cpp
|
||||||
void XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
void XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
||||||
void URL_response(AsyncWebServerRequest *request);
|
void URL_response(AsyncWebServerRequest *request);
|
||||||
|
@ -333,6 +333,12 @@ void serializeInfo(JsonObject root)
|
|||||||
root["lip"] = realtimeIP.toString();
|
root["lip"] = realtimeIP.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
root["ws"] = ws.count();
|
||||||
|
#else
|
||||||
|
root["ws"] = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
root["fxcount"] = strip.getModeCount();
|
root["fxcount"] = strip.getModeCount();
|
||||||
root["palcount"] = strip.getPaletteCount();
|
root["palcount"] = strip.getPaletteCount();
|
||||||
|
|
||||||
@ -454,21 +460,37 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
#define MAX_LIVE_LEDS 180
|
#define MAX_LIVE_LEDS 180
|
||||||
|
|
||||||
void serveLiveLeds(AsyncWebServerRequest* request)
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||||
{
|
{
|
||||||
|
AsyncWebSocketClient * wsc;
|
||||||
|
if (!request) { //not HTTP, use Websockets
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
wsc = ws.client(wsClient);
|
||||||
|
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t used = ledCount;
|
uint16_t used = ledCount;
|
||||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||||
char buffer[2000] = "{\"leds\":[";
|
char buffer[2000] = "{\"leds\":[";
|
||||||
olen = 9;
|
|
||||||
obuf = buffer;
|
obuf = buffer;
|
||||||
|
olen = 9;
|
||||||
|
|
||||||
for (uint16_t i= 0; i < used; i += n)
|
for (uint16_t i= 0; i < used; i += n)
|
||||||
{
|
{
|
||||||
olen += sprintf(buffer + olen, "\"%06X\",", strip.getPixelColor(i));
|
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i));
|
||||||
}
|
}
|
||||||
olen -= 1;
|
olen -= 1;
|
||||||
oappend("],\"n\":");
|
oappend("],\"n\":");
|
||||||
oappendi(n);
|
oappendi(n);
|
||||||
oappend("}");
|
oappend("}");
|
||||||
request->send(200, "application/json", buffer);
|
if (request) {
|
||||||
|
request->send(200, "application/json", buffer);
|
||||||
|
}
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
else {
|
||||||
|
wsc->text(obuf, olen);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
/*
|
/*
|
||||||
* LED methods
|
* LED methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void setValuesFromMainSeg()
|
void setValuesFromMainSeg()
|
||||||
{
|
{
|
||||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||||
@ -167,6 +166,7 @@ void colorUpdated(int callMode)
|
|||||||
|
|
||||||
void updateInterfaces(uint8_t callMode)
|
void updateInterfaces(uint8_t callMode)
|
||||||
{
|
{
|
||||||
|
sendDataWs();
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) {
|
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) {
|
||||||
espalexaDevice->setValue(bri);
|
espalexaDevice->setValue(bri);
|
||||||
|
@ -14,8 +14,11 @@ WLED::WLED()
|
|||||||
void WLED::reset()
|
void WLED::reset()
|
||||||
{
|
{
|
||||||
briT = 0;
|
briT = 0;
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
ws.closeAll(1012);
|
||||||
|
#endif
|
||||||
long dly = millis();
|
long dly = millis();
|
||||||
while (millis() - dly < 250) {
|
while (millis() - dly < 450) {
|
||||||
yield(); // enough time to send response to client
|
yield(); // enough time to send response to client
|
||||||
}
|
}
|
||||||
setAllLeds();
|
setAllLeds();
|
||||||
@ -94,7 +97,8 @@ void WLED::loop()
|
|||||||
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
||||||
initMqtt();
|
initMqtt();
|
||||||
}
|
}
|
||||||
|
yield();
|
||||||
|
handleWs();
|
||||||
|
|
||||||
// DEBUG serial logging
|
// DEBUG serial logging
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
@ -283,6 +287,10 @@ void WLED::initAP(bool resetAP)
|
|||||||
|
|
||||||
void WLED::initConnection()
|
void WLED::initConnection()
|
||||||
{
|
{
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
ws.onEvent(wsEvent);
|
||||||
|
#endif
|
||||||
|
|
||||||
WiFi.disconnect(true); // close old connections
|
WiFi.disconnect(true); // close old connections
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2006220
|
#define VERSION 2006260
|
||||||
|
|
||||||
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
|
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
|
||||||
|
|
||||||
@ -30,6 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
||||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||||
|
#define WLED_ENABLE_WEBSOCKETS
|
||||||
|
|
||||||
#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
|
||||||
@ -480,6 +481,9 @@ WLED_GLOBAL bool doPublishMqtt _INIT(false);
|
|||||||
|
|
||||||
// server library objects
|
// server library objects
|
||||||
WLED_GLOBAL AsyncWebServer server _INIT_N(((80)));
|
WLED_GLOBAL AsyncWebServer server _INIT_N(((80)));
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws")));
|
||||||
|
#endif
|
||||||
WLED_GLOBAL AsyncClient* hueClient _INIT(NULL);
|
WLED_GLOBAL AsyncClient* hueClient _INIT(NULL);
|
||||||
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
|
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
|
||||||
|
|
||||||
|
@ -205,10 +205,10 @@ void initServer()
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254);
|
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254);
|
||||||
});
|
});
|
||||||
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254);
|
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +226,10 @@ void initServer()
|
|||||||
if (captivePortal(request)) return;
|
if (captivePortal(request)) return;
|
||||||
serveIndexOrWelcome(request);
|
serveIndexOrWelcome(request);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
server.addHandler(&ws);
|
||||||
|
#endif
|
||||||
|
|
||||||
//called when the url is not defined here, ajax-in; get-settings
|
//called when the url is not defined here, ajax-in; get-settings
|
||||||
server.onNotFound([](AsyncWebServerRequest *request){
|
server.onNotFound([](AsyncWebServerRequest *request){
|
||||||
@ -374,7 +378,7 @@ void serveSettings(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
if (subPage == 1 && wifiLock && otaLock)
|
if (subPage == 1 && wifiLock && otaLock)
|
||||||
{
|
{
|
||||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); return;
|
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage
|
#ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage
|
||||||
|
114
wled00/ws.cpp
Normal file
114
wled00/ws.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WebSockets server for bidirectional communication
|
||||||
|
*/
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
|
|
||||||
|
uint16_t wsLiveClientId = 0;
|
||||||
|
unsigned long wsLastLiveTime = 0;
|
||||||
|
//uint8_t* wsFrameBuffer = nullptr;
|
||||||
|
|
||||||
|
#define WS_LIVE_INTERVAL 40
|
||||||
|
|
||||||
|
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
if(type == WS_EVT_CONNECT){
|
||||||
|
//client connected
|
||||||
|
sendDataWs(client);
|
||||||
|
//client->ping();
|
||||||
|
} else if(type == WS_EVT_DISCONNECT){
|
||||||
|
//client disconnected
|
||||||
|
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||||
|
} else if(type == WS_EVT_DATA){
|
||||||
|
//data packet
|
||||||
|
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||||
|
if(info->final && info->index == 0 && info->len == len){
|
||||||
|
//the whole message is in a single frame and we got all of it's data (max. 1450byte)
|
||||||
|
if(info->opcode == WS_TEXT)
|
||||||
|
{
|
||||||
|
bool verboseResponse = false;
|
||||||
|
{ //scope JsonDocument so it releases its buffer
|
||||||
|
DynamicJsonDocument jsonBuffer(8192);
|
||||||
|
DeserializationError error = deserializeJson(jsonBuffer, data, len);
|
||||||
|
JsonObject root = jsonBuffer.as<JsonObject>();
|
||||||
|
if (error || root.isNull()) return;
|
||||||
|
|
||||||
|
if (root.containsKey("lv"))
|
||||||
|
{
|
||||||
|
wsLiveClientId = root["lv"] ? client->id() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
verboseResponse = deserializeState(root);
|
||||||
|
}
|
||||||
|
if (verboseResponse || millis() - lastInterfaceUpdate < 1900) sendDataWs(client); //update if it takes longer than 100ms until next "broadcast"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//message is comprised of multiple frames or the frame is split into multiple packets
|
||||||
|
//if(info->index == 0){
|
||||||
|
//if (!wsFrameBuffer && len < 4096) wsFrameBuffer = new uint8_t[4096];
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (wsFrameBuffer && len < 4096 && info->index + info->)
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
if((info->index + len) == info->len){
|
||||||
|
if(info->final){
|
||||||
|
if(info->message_opcode == WS_TEXT) {
|
||||||
|
client->text("{\"error\":10}"); //we do not handle split packets right now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(type == WS_EVT_ERROR){
|
||||||
|
//error was received from the other end
|
||||||
|
|
||||||
|
} else if(type == WS_EVT_PONG){
|
||||||
|
//pong message was received (in response to a ping request maybe)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendDataWs(AsyncWebSocketClient * client)
|
||||||
|
{
|
||||||
|
if (!ws.count()) return;
|
||||||
|
AsyncWebSocketMessageBuffer * buffer;
|
||||||
|
|
||||||
|
{ //scope JsonDocument so it releases its buffer
|
||||||
|
DynamicJsonDocument doc(8192);
|
||||||
|
JsonObject state = doc.createNestedObject("state");
|
||||||
|
serializeState(state);
|
||||||
|
JsonObject info = doc.createNestedObject("info");
|
||||||
|
serializeInfo(info);
|
||||||
|
size_t len = measureJson(doc);
|
||||||
|
buffer = ws.makeBuffer(len);
|
||||||
|
if (!buffer) return; //out of memory
|
||||||
|
|
||||||
|
serializeJson(doc, (char *)buffer->get(), len +1);
|
||||||
|
}
|
||||||
|
if (client) {
|
||||||
|
client->text(buffer);
|
||||||
|
} else {
|
||||||
|
ws.textAll(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleWs()
|
||||||
|
{
|
||||||
|
if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL)
|
||||||
|
{
|
||||||
|
ws.cleanupClients();
|
||||||
|
bool success = true;
|
||||||
|
if (wsLiveClientId)
|
||||||
|
success = serveLiveLeds(nullptr, wsLiveClientId);
|
||||||
|
wsLastLiveTime = millis();
|
||||||
|
if (!success) wsLastLiveTime -= 20; //try again in 20ms if failed due to non-empty WS queue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void handleWs() {}
|
||||||
|
void sendDataWs(AsyncWebSocketClient * client) {}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user