Philips hue robustness improvements
* reduce JSON buffer from 1024 to 640 * ESP32: define buffer globally (reduces likelyhood of crashes due to low stack) * added some sanity checks after string ops * delete hueClient object after closing the connection * make functions static if not used outside of hue.cpp, re-shuffle order where needed * rename JSON buffer object: root -> jsonHUEroot
This commit is contained in:
@@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_HUESYNC
|
#ifndef WLED_DISABLE_HUESYNC
|
||||||
|
|
||||||
|
// WLEDMM moved out of wled.h
|
||||||
|
static AsyncClient* hueClient = nullptr;
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
StaticJsonDocument<640> jsonHUEroot; // (was 1024) - 640 bytes should be more than enough
|
||||||
|
#endif
|
||||||
|
|
||||||
void handleHue()
|
void handleHue()
|
||||||
{
|
{
|
||||||
if (hueReceived)
|
if (hueReceived)
|
||||||
@@ -27,37 +34,18 @@ void handleHue()
|
|||||||
reconnectHue();
|
reconnectHue();
|
||||||
} else {
|
} else {
|
||||||
hueClient->close();
|
hueClient->close();
|
||||||
|
delete hueClient; hueClient = nullptr;
|
||||||
if (hueError == HUE_ERROR_ACTIVE) hueError = HUE_ERROR_INACTIVE;
|
if (hueError == HUE_ERROR_ACTIVE) hueError = HUE_ERROR_INACTIVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconnectHue()
|
static void onHueError(void* arg, AsyncClient* client, int8_t error)
|
||||||
{
|
{
|
||||||
if (!WLED_CONNECTED || !huePollingEnabled) return;
|
USER_PRINTLN("Hue err " + String(error));
|
||||||
DEBUG_PRINTLN(F("Hue reconnect"));
|
|
||||||
if (hueClient == nullptr) {
|
|
||||||
hueClient = new AsyncClient();
|
|
||||||
hueClient->onConnect(&onHueConnect, hueClient);
|
|
||||||
hueClient->onData(&onHueData, hueClient);
|
|
||||||
hueClient->onError(&onHueError, hueClient);
|
|
||||||
hueAuthRequired = (strlen(hueApiKey)<20);
|
|
||||||
}
|
|
||||||
hueClient->connect(hueIP, 80);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onHueError(void* arg, AsyncClient* client, int8_t error)
|
|
||||||
{
|
|
||||||
DEBUG_PRINTLN(F("Hue err"));
|
|
||||||
hueError = HUE_ERROR_TIMEOUT;
|
hueError = HUE_ERROR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onHueConnect(void* arg, AsyncClient* client)
|
static void sendHuePoll()
|
||||||
{
|
|
||||||
DEBUG_PRINTLN(F("Hue connect"));
|
|
||||||
sendHuePoll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendHuePoll()
|
|
||||||
{
|
{
|
||||||
if (hueClient == nullptr || !hueClient->connected()) return;
|
if (hueClient == nullptr || !hueClient->connected()) return;
|
||||||
String req = "";
|
String req = "";
|
||||||
@@ -81,7 +69,13 @@ void sendHuePoll()
|
|||||||
hueLastRequestSent = millis();
|
hueLastRequestSent = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
static void onHueConnect(void* arg, AsyncClient* client)
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN(F("Hue connect"));
|
||||||
|
sendHuePoll();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||||
{
|
{
|
||||||
if (!len) return;
|
if (!len) return;
|
||||||
char* str = (char*)data;
|
char* str = (char*)data;
|
||||||
@@ -89,19 +83,22 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
DEBUG_PRINTLN(str);
|
DEBUG_PRINTLN(str);
|
||||||
//only get response body
|
//only get response body
|
||||||
str = strstr(str,"\r\n\r\n");
|
str = strstr(str,"\r\n\r\n");
|
||||||
if (str == nullptr) return;
|
if ((str == nullptr) || strlen(str) < 4) return;
|
||||||
str += 4;
|
str += 4;
|
||||||
|
|
||||||
StaticJsonDocument<1024> root;
|
#if !defined(ARDUINO_ARCH_ESP32)
|
||||||
|
StaticJsonDocument<640> jsonHUEroot; // was 1024 - completely ovrersized.
|
||||||
|
#endif
|
||||||
if (str[0] == '[') //is JSON array
|
if (str[0] == '[') //is JSON array
|
||||||
{
|
{
|
||||||
auto error = deserializeJson(root, str);
|
auto error = deserializeJson(jsonHUEroot, str);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
USER_PRINTF("Hue error: failed to parse (len =%d) \t: %s\n", strlen(str), str);
|
||||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hueErrorCode = root[0][F("error")]["type"];
|
int hueErrorCode = jsonHUEroot[0][F("error")]["type"];
|
||||||
if (hueErrorCode)//hue bridge returned error
|
if (hueErrorCode)//hue bridge returned error
|
||||||
{
|
{
|
||||||
hueError = hueErrorCode;
|
hueError = hueErrorCode;
|
||||||
@@ -116,7 +113,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
|
|
||||||
if (hueAuthRequired)
|
if (hueAuthRequired)
|
||||||
{
|
{
|
||||||
const char* apikey = root[0][F("success")][F("username")];
|
const char* apikey = jsonHUEroot[0][F("success")][F("username")];
|
||||||
if (apikey != nullptr && strlen(apikey) < sizeof(hueApiKey))
|
if (apikey != nullptr && strlen(apikey) < sizeof(hueApiKey))
|
||||||
{
|
{
|
||||||
strlcpy(hueApiKey, apikey, sizeof(hueApiKey));
|
strlcpy(hueApiKey, apikey, sizeof(hueApiKey));
|
||||||
@@ -131,10 +128,12 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
str = strstr(str,"state");
|
str = strstr(str,"state");
|
||||||
if (str == nullptr) return;
|
if (str == nullptr) return;
|
||||||
str = strstr(str,"{");
|
str = strstr(str,"{");
|
||||||
|
if (str == nullptr) return;
|
||||||
|
|
||||||
auto error = deserializeJson(root, str);
|
auto error = deserializeJson(jsonHUEroot, str);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
USER_PRINTF("Hue error: failed to parse (len =%d) \t: %s\n", strlen(str), str);
|
||||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,27 +141,27 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
uint16_t hueHue=0, hueCt=0;
|
uint16_t hueHue=0, hueCt=0;
|
||||||
byte hueBri=0, hueSat=0, hueColormode=0;
|
byte hueBri=0, hueSat=0, hueColormode=0;
|
||||||
|
|
||||||
if (root["on"]) {
|
if (jsonHUEroot["on"]) {
|
||||||
if (root.containsKey("bri")) //Dimmable device
|
if (jsonHUEroot.containsKey("bri")) //Dimmable device
|
||||||
{
|
{
|
||||||
hueBri = root["bri"];
|
hueBri = jsonHUEroot["bri"];
|
||||||
hueBri++;
|
hueBri++;
|
||||||
const char* cm =root[F("colormode")];
|
const char* cm =jsonHUEroot[F("colormode")];
|
||||||
if (cm != nullptr) //Color device
|
if (cm != nullptr) //Color device
|
||||||
{
|
{
|
||||||
if (strstr(cm,("ct")) != nullptr) //ct mode
|
if (strstr(cm,("ct")) != nullptr) //ct mode
|
||||||
{
|
{
|
||||||
hueCt = root["ct"];
|
hueCt = jsonHUEroot["ct"];
|
||||||
hueColormode = 3;
|
hueColormode = 3;
|
||||||
} else if (strstr(cm,"xy") != nullptr) //xy mode
|
} else if (strstr(cm,"xy") != nullptr) //xy mode
|
||||||
{
|
{
|
||||||
hueX = root["xy"][0]; // 0.5051
|
hueX = jsonHUEroot["xy"][0]; // 0.5051
|
||||||
hueY = root["xy"][1]; // 0.4151
|
hueY = jsonHUEroot["xy"][1]; // 0.4151
|
||||||
hueColormode = 1;
|
hueColormode = 1;
|
||||||
} else //hs mode
|
} else //hs mode
|
||||||
{
|
{
|
||||||
hueHue = root["hue"];
|
hueHue = jsonHUEroot["hue"];
|
||||||
hueSat = root[F("sat")];
|
hueSat = jsonHUEroot[F("sat")];
|
||||||
hueColormode = 2;
|
hueColormode = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,6 +201,21 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
|||||||
}
|
}
|
||||||
hueReceived = true;
|
hueReceived = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reconnectHue() // this is also called from async_tcp task handleSettingsSet()
|
||||||
|
{
|
||||||
|
if (!WLED_CONNECTED || !huePollingEnabled) return;
|
||||||
|
DEBUG_PRINTLN(F("Hue reconnect"));
|
||||||
|
if (hueClient == nullptr) {
|
||||||
|
hueClient = new AsyncClient();
|
||||||
|
hueClient->onConnect(&onHueConnect, hueClient);
|
||||||
|
hueClient->onData(&onHueData, hueClient);
|
||||||
|
hueClient->onError(&onHueError, hueClient);
|
||||||
|
hueAuthRequired = (strlen(hueApiKey)<20);
|
||||||
|
}
|
||||||
|
hueClient->connect(hueIP, 80);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void handleHue(){}
|
void handleHue(){}
|
||||||
void reconnectHue(){}
|
void reconnectHue(){}
|
||||||
|
|||||||
@@ -761,7 +761,7 @@ WLED_GLOBAL AsyncWebServer server _INIT_N(((80)));
|
|||||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws")));
|
WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws")));
|
||||||
#endif
|
#endif
|
||||||
WLED_GLOBAL AsyncClient *hueClient _INIT(NULL);
|
//WLED_GLOBAL AsyncClient *hueClient _INIT(NULL); // WLEDMM moved into hue.cpp
|
||||||
WLED_GLOBAL AsyncWebHandler *editHandler _INIT(nullptr);
|
WLED_GLOBAL AsyncWebHandler *editHandler _INIT(nullptr);
|
||||||
|
|
||||||
// udp interface objects
|
// udp interface objects
|
||||||
|
|||||||
Reference in New Issue
Block a user