From c6ee7da74fc916220b0af699baab61b5fc13ecd6 Mon Sep 17 00:00:00 2001 From: JacobK5 Date: Tue, 17 Sep 2024 11:34:39 -0600 Subject: [PATCH 1/3] Made Relevant Changes From My Own Codebase I can't show my full codebase, but these should be all the relevant changes for my OTA issue --- platformio.ini | 5 +- wled00/fcn_declare.h | 447 +++++----- wled00/mqtt.cpp | 366 ++++++-- .../async-mqtt-client/AsyncMqttClient.cpp | 666 ++++++++------ .../async-mqtt-client/AsyncMqttClient.hpp | 84 +- wled00/util.cpp | 758 +++++++++------- wled00/wled.cpp | 812 +++++++++++------- wled00/wled.h | 727 ++++++++-------- 8 files changed, 2349 insertions(+), 1516 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2ef4ae01bf..f14c00d1c4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ # CI binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi +; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi # Release binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB @@ -30,7 +30,7 @@ default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2 ; default_envs = h803wf ; default_envs = d1_mini_debug ; default_envs = d1_mini_ota -; default_envs = esp32dev +default_envs = esp32dev ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_H801 ; default_envs = d1_mini_5CH_Shojo_PCB @@ -257,6 +257,7 @@ build_flags = -g -D CONFIG_ASYNC_TCP_USE_WDT=0 #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS + -D WLED_DEBUG # for full debugging ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv lib_deps = diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index c65f7a90b4..665ee808bd 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -5,32 +5,34 @@ * All globally accessible functions are declared here */ -//alexa.cpp +// alexa.cpp #ifndef WLED_DISABLE_ALEXA -void onAlexaChange(EspalexaDevice* dev); +void onAlexaChange(EspalexaDevice *dev); void alexaInit(); void handleAlexa(); -void onAlexaChange(EspalexaDevice* dev); +void onAlexaChange(EspalexaDevice *dev); #endif -//button.cpp -void shortPressAction(uint8_t b=0); -void longPressAction(uint8_t b=0); -void doublePressAction(uint8_t b=0); -bool isButtonPressed(uint8_t b=0); +// button.cpp +void shortPressAction(uint8_t b = 0); +void longPressAction(uint8_t b = 0); +void doublePressAction(uint8_t b = 0); +bool isButtonPressed(uint8_t b = 0); void handleButton(); void handleIO(); -//cfg.cpp +// cfg.cpp bool deserializeConfig(JsonObject doc, bool fromFS = false); void deserializeConfigFromFS(); bool deserializeConfigSec(); void serializeConfig(); void serializeConfigSec(); -template -bool getJsonValue(const JsonVariant& element, DestType& destination) { - if (element.isNull()) { +template +bool getJsonValue(const JsonVariant &element, DestType &destination) +{ + if (element.isNull()) + { return false; } @@ -38,9 +40,11 @@ bool getJsonValue(const JsonVariant& element, DestType& destination) { return true; } -template -bool getJsonValue(const JsonVariant& element, DestType& destination, const DefaultType defaultValue) { - if(!getJsonValue(element, destination)) { +template +bool getJsonValue(const JsonVariant &element, DestType &destination, const DefaultType defaultValue) +{ + if (!getJsonValue(element, destination)) + { destination = defaultValue; return false; } @@ -48,64 +52,65 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau return true; } - -//colors.cpp -// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) -class NeoGammaWLEDMethod { - public: - static uint8_t Correct(uint8_t value); // apply Gamma to single channel - static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) - static void calcGammaTable(float gamma); // re-calculates & fills gamma table - static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) - private: - static uint8_t gammaT[]; +// colors.cpp +// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) +class NeoGammaWLEDMethod +{ +public: + static uint8_t Correct(uint8_t value); // apply Gamma to single channel + static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) + static void calcGammaTable(float gamma); // re-calculates & fills gamma table + static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) +private: + static uint8_t gammaT[]; }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) -#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); -uint32_t color_add(uint32_t,uint32_t, bool fast=false); -uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb -void colorKtoRGB(uint16_t kelvin, byte* rgb); -void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb -void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO -void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO -void colorFromDecOrHexString(byte* rgb, char* in); -bool colorFromHexString(byte* rgb, const char* in); +#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) +uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16 = false); +uint32_t color_add(uint32_t, uint32_t, bool fast = false); +uint32_t color_fade(uint32_t c1, uint8_t amount, bool video = false); +inline uint32_t colorFromRgbw(byte *rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } +void colorHStoRGB(uint16_t hue, byte sat, byte *rgb); // hue, sat to rgb +void colorKtoRGB(uint16_t kelvin, byte *rgb); +void colorCTtoRGB(uint16_t mired, byte *rgb); // white spectrum to rgb +void colorXYtoRGB(float x, float y, byte *rgb); // only defined if huesync disabled TODO +void colorRGBtoXY(byte *rgb, float *xy); // only defined if huesync disabled TODO +void colorFromDecOrHexString(byte *rgb, char *in); +bool colorFromHexString(byte *rgb, const char *in); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); -void setRandomColor(byte* rgb); +void setRandomColor(byte *rgb); -//dmx.cpp +// dmx.cpp void initDMX(); void handleDMX(); -//e131.cpp -void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); +// e131.cpp +void handleE131Packet(e131_packet_t *p, IPAddress clientIP, byte protocol); void handleArtnetPollReply(IPAddress ipAddress); -void prepareArtnetPollReply(ArtPollReply* reply); -void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress); - -//file.cpp -bool handleFileRead(AsyncWebServerRequest*, String path); -bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content); -bool writeObjectToFile(const char* file, const char* key, JsonDocument* content); -bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); -bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); +void prepareArtnetPollReply(ArtPollReply *reply); +void sendArtnetPollReply(ArtPollReply *reply, IPAddress ipAddress, uint16_t portAddress); + +// file.cpp +bool handleFileRead(AsyncWebServerRequest *, String path); +bool writeObjectToFileUsingId(const char *file, uint16_t id, JsonDocument *content); +bool writeObjectToFile(const char *file, const char *key, JsonDocument *content); +bool readObjectFromFileUsingId(const char *file, uint16_t id, JsonDocument *dest); +bool readObjectFromFile(const char *file, const char *key, JsonDocument *dest); void updateFSInfo(); void closeFile(); -//hue.cpp +// hue.cpp void handleHue(); void reconnectHue(); -void onHueError(void* arg, AsyncClient* client, int8_t error); -void onHueConnect(void* arg, AsyncClient* client); +void onHueError(void *arg, AsyncClient *client, int8_t error); +void onHueConnect(void *arg, AsyncClient *client); void sendHuePoll(); -void onHueData(void* arg, AsyncClient* client, void *data, size_t len); +void onHueData(void *arg, AsyncClient *client, void *data, size_t len); -//improv.cpp -enum ImprovRPCType { +// improv.cpp +enum ImprovRPCType +{ Command_Wifi = 0x01, Request_State = 0x02, Request_Info = 0x03, @@ -120,7 +125,7 @@ void startImprovWifiScan(); void handleImprovWifiScan(); void sendImprovIPRPCResult(ImprovRPCType type); -//ir.cpp +// ir.cpp void applyRepeatActions(); byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); void decodeIR(uint32_t code); @@ -137,7 +142,7 @@ void decodeIRJson(uint32_t code); void initIR(); void handleIR(); -//json.cpp +// json.cpp #include "ESPAsyncWebServer.h" #include "src/dependencies/json/ArduinoJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h" @@ -145,17 +150,17 @@ void handleIR(); bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0); bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0); -void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); +void serializeSegment(JsonObject &root, Segment &seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false); void serializeInfo(JsonObject root); void serializeModeNames(JsonArray root); void serializeModeData(JsonArray root); -void serveJson(AsyncWebServerRequest* request); +void serveJson(AsyncWebServerRequest *request); #ifdef WLED_ENABLE_JSONLIVE -bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); +bool serveLiveLeds(AsyncWebServerRequest *request, uint32_t wsClient = 0); #endif -//led.cpp +// led.cpp void setValuesFromSegment(uint8_t s); void setValuesFromMainSeg(); void setValuesFromFirstSelectedSeg(); @@ -172,22 +177,22 @@ void handleNightlight(); byte scaledBri(byte in); #ifdef WLED_ENABLE_LOXONE -//lx_parser.cpp -bool parseLx(int lxValue, byte* rgbw); +// lx_parser.cpp +bool parseLx(int lxValue, byte *rgbw); void parseLxJson(int lxValue, byte segId, bool secondary); #endif -//mqtt.cpp +// mqtt.cpp bool initMqtt(); void publishMqtt(); -//ntp.cpp +// ntp.cpp void handleTime(); void handleNetworkTime(); void sendNTPPacket(); bool checkNTPResponse(); void updateLocalTime(); -void getTimeString(char* out); +void getTimeString(char *out); bool checkCountdown(); void setCountdown(); byte weekdayMondayFirst(); @@ -195,40 +200,40 @@ void checkTimers(); void calculateSunriseAndSunset(); void setTimeFromAPI(uint32_t timein); -//overlay.cpp +// overlay.cpp void handleOverlayDraw(); void _overlayAnalogCountdown(); void _overlayAnalogClock(); -//playlist.cpp +// playlist.cpp void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); void handlePlaylist(); void serializePlaylist(JsonObject obj); -//presets.cpp +// presets.cpp void initPresetsFile(); void handlePresets(); bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE); void applyPresetWithFallback(uint8_t presetID, uint8_t callMode, uint8_t effectID = 0, uint8_t paletteID = 0); -inline bool applyTemporaryPreset() {return applyPreset(255);}; -void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject()); -inline void saveTemporaryPreset() {savePreset(255);}; +inline bool applyTemporaryPreset() { return applyPreset(255); }; +void savePreset(byte index, const char *pname = nullptr, JsonObject saveobj = JsonObject()); +inline void saveTemporaryPreset() { savePreset(255); }; void deletePreset(byte index); -bool getPresetName(byte index, String& name); +bool getPresetName(byte index, String &name); -//remote.cpp +// remote.cpp void handleRemote(); -//set.cpp -bool isAsterisksOnly(const char* str, byte maxLen); +// set.cpp +bool isAsterisksOnly(const char *str, byte maxLen); void handleSettingsSet(AsyncWebServerRequest *request, byte subPage); -bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true); +bool handleSet(AsyncWebServerRequest *request, const String &req, bool apply = true); -//udp.cpp -void notify(byte callMode, bool followUp=false); -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false); +// udp.cpp +void notify(byte callMode, bool followUp = false); +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri = 255, bool isRGBW = false); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void exitRealtime(); void handleNotifications(); @@ -236,12 +241,13 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); void refreshNodeList(); void sendSysInfoUDP(); -//network.cpp +// network.cpp int getSignalQuality(int rssi); void WiFiEvent(WiFiEvent_t event); -//um_manager.cpp -typedef enum UM_Data_Types { +// um_manager.cpp +typedef enum UM_Data_Types +{ UMT_BYTE = 0, UMT_UINT16, UMT_INT16, @@ -257,176 +263,211 @@ typedef enum UM_Data_Types { UMT_FLOAT_ARR, UMT_DOUBLE_ARR } um_types_t; -typedef struct UM_Exchange_Data { +typedef struct UM_Exchange_Data +{ // should just use: size_t arr_size, void **arr_ptr, byte *ptr_type - size_t u_size; // size of u_data array - um_types_t *u_type; // array of data types - void **u_data; // array of pointers to data - UM_Exchange_Data() { + size_t u_size; // size of u_data array + um_types_t *u_type; // array of data types + void **u_data; // array of pointers to data + UM_Exchange_Data() + { u_size = 0; u_type = nullptr; u_data = nullptr; } - ~UM_Exchange_Data() { - if (u_type) delete[] u_type; - if (u_data) delete[] u_data; + ~UM_Exchange_Data() + { + if (u_type) + delete[] u_type; + if (u_data) + delete[] u_data; } } um_data_t; -const unsigned int um_data_size = sizeof(um_data_t); // 12 bytes - -class Usermod { - protected: - um_data_t *um_data; // um_data should be allocated using new in (derived) Usermod's setup() or constructor - public: - Usermod() { um_data = nullptr; } - virtual ~Usermod() { if (um_data) delete um_data; } - virtual void setup() = 0; // pure virtual, has to be overriden - virtual void loop() = 0; // pure virtual, has to be overriden - virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show() - virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here - virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] - virtual void connected() {} // called when WiFi is (re)connected - virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields - virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state - virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page - virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server - virtual void addToConfig(JsonObject& obj) {} // add JSON entries that go to cfg.json - virtual bool readFromConfig(JsonObject& obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h - virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe) - virtual bool onMqttMessage(char* topic, char* payload) { return false; } // fired upon MQTT message received (wled topic) - virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update - virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change - virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} +const unsigned int um_data_size = sizeof(um_data_t); // 12 bytes + +class Usermod +{ +protected: + um_data_t *um_data; // um_data should be allocated using new in (derived) Usermod's setup() or constructor +public: + Usermod() { um_data = nullptr; } + virtual ~Usermod() + { + if (um_data) + delete um_data; + } + virtual void setup() = 0; // pure virtual, has to be overriden + virtual void loop() = 0; // pure virtual, has to be overriden + virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show() + virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here + virtual bool getUMData(um_data_t **data) + { + if (data) + *data = nullptr; + return false; + }; // usermod data exchange [see examples for audio effects] + virtual void connected() {} // called when WiFi is (re)connected + virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields + virtual void addToJsonState(JsonObject &obj) {} // add JSON objects for WLED state + virtual void addToJsonInfo(JsonObject &obj) {} // add JSON objects for UI Info page + virtual void readFromJsonState(JsonObject &obj) {} // process JSON messages received from web server + virtual void addToConfig(JsonObject &obj) {} // add JSON entries that go to cfg.json + virtual bool readFromConfig(JsonObject &obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h + virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe) + virtual bool onMqttMessage(char *topic, char *payload) { return false; } // fired upon MQTT message received (wled topic) + virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update + virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change + virtual uint16_t getId() { return USERMOD_ID_UNSPECIFIED; } }; -class UsermodManager { - private: - Usermod* ums[WLED_MAX_USERMODS]; - byte numMods = 0; - - public: - void loop(); - void handleOverlayDraw(); - bool handleButton(uint8_t b); - bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods - void setup(); - void connected(); - void appendConfigData(); - void addToJsonState(JsonObject& obj); - void addToJsonInfo(JsonObject& obj); - void readFromJsonState(JsonObject& obj); - void addToConfig(JsonObject& obj); - bool readFromConfig(JsonObject& obj); - void onMqttConnect(bool sessionPresent); - bool onMqttMessage(char* topic, char* payload); - void onUpdateBegin(bool); - void onStateChange(uint8_t); - bool add(Usermod* um); - Usermod* lookup(uint16_t mod_id); - byte getModCount() {return numMods;}; +class UsermodManager +{ +private: + Usermod *ums[WLED_MAX_USERMODS]; + byte numMods = 0; + +public: + void loop(); + void handleOverlayDraw(); + bool handleButton(uint8_t b); + bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods + void setup(); + void connected(); + void appendConfigData(); + void addToJsonState(JsonObject &obj); + void addToJsonInfo(JsonObject &obj); + void readFromJsonState(JsonObject &obj); + void addToConfig(JsonObject &obj); + bool readFromConfig(JsonObject &obj); + void onMqttConnect(bool sessionPresent); + bool onMqttMessage(char *topic, char *payload); + void onUpdateBegin(bool); + void onStateChange(uint8_t); + bool add(Usermod *um); + Usermod *lookup(uint16_t mod_id); + byte getModCount() { return numMods; }; }; -//usermods_list.cpp +// usermods_list.cpp void registerUsermods(); -//usermod.cpp +// usermod.cpp void userSetup(); void userConnected(); void userLoop(); -//util.cpp -int getNumVal(const String* req, uint16_t pos); -void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); -bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); -bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); -bool oappend(const char* txt); // append new c string to temp buffer efficiently +// util.cpp +int getNumVal(const String *req, uint16_t pos); +void parseNumber(const char *str, byte *val, byte minv = 0, byte maxv = 255); +bool getVal(JsonVariant elem, byte *val, byte minv = 0, byte maxv = 255); +bool updateVal(const char *req, const char *key, byte *val, byte minv = 0, byte maxv = 255); +bool oappend(const char *txt); // append new c string to temp buffer efficiently bool oappendi(int i); // append new number to temp buffer efficiently -void sappend(char stype, const char* key, int val); -void sappends(char stype, const char* key, char* val); -void prepareHostname(char* hostname); -bool isAsterisksOnly(const char* str, byte maxLen); -bool requestJSONBufferLock(uint8_t module=255); +void sappend(char stype, const char *key, int val); +void sappends(char stype, const char *key, char *val); +void prepareHostname(char *hostname); +bool isAsterisksOnly(const char *str, byte maxLen); +bool requestJSONBufferLock(uint8_t module = 255); void releaseJSONBufferLock(); +bool requestResponseBufferLock(uint8_t module = 255); +void releaseResponseBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr); int16_t extractModeDefaults(uint8_t mode, const char *segVar); void checkSettingsPIN(const char *pin); -uint16_t crc16(const unsigned char* data_p, size_t length); -um_data_t* simulateSound(uint8_t simulationId); +uint16_t crc16(const unsigned char *data_p, size_t length); +um_data_t *simulateSound(uint8_t simulationId); void enumerateLedmaps(); uint8_t get_random_wheel_index(uint8_t pos); // RAII guard class for the JSON Buffer lock // Modeled after std::lock_guard -class JSONBufferGuard { +class JSONBufferGuard +{ bool holding_lock; - public: - inline JSONBufferGuard(uint8_t module=255) : holding_lock(requestJSONBufferLock(module)) {}; - inline ~JSONBufferGuard() { if (holding_lock) releaseJSONBufferLock(); }; - inline JSONBufferGuard(const JSONBufferGuard&) = delete; // Noncopyable - inline JSONBufferGuard& operator=(const JSONBufferGuard&) = delete; - inline JSONBufferGuard(JSONBufferGuard&& r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable - inline JSONBufferGuard& operator=(JSONBufferGuard&& r) { holding_lock |= r.holding_lock; r.holding_lock = false; return *this; }; - inline bool owns_lock() const { return holding_lock; } - explicit inline operator bool() const { return owns_lock(); }; - inline void release() { if (holding_lock) releaseJSONBufferLock(); holding_lock = false; } + +public: + inline JSONBufferGuard(uint8_t module = 255) : holding_lock(requestJSONBufferLock(module)) {}; + inline ~JSONBufferGuard() + { + if (holding_lock) + releaseJSONBufferLock(); + }; + inline JSONBufferGuard(const JSONBufferGuard &) = delete; // Noncopyable + inline JSONBufferGuard &operator=(const JSONBufferGuard &) = delete; + inline JSONBufferGuard(JSONBufferGuard &&r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable + inline JSONBufferGuard &operator=(JSONBufferGuard &&r) + { + holding_lock |= r.holding_lock; + r.holding_lock = false; + return *this; + }; + inline bool owns_lock() const { return holding_lock; } + explicit inline operator bool() const { return owns_lock(); }; + inline void release() + { + if (holding_lock) + releaseJSONBufferLock(); + holding_lock = false; + } }; #ifdef WLED_ADD_EEPROM_SUPPORT -//wled_eeprom.cpp +// wled_eeprom.cpp void applyMacro(byte index); void deEEP(); void deEEPSettings(); void clearEEPROM(); #endif -//wled_math.cpp +// wled_math.cpp #ifndef WLED_USE_REAL_MATH - template T atan_t(T x); - float cos_t(float phi); - float sin_t(float x); - float tan_t(float x); - float acos_t(float x); - float asin_t(float x); - float floor_t(float x); - float fmod_t(float num, float denom); +template +T atan_t(T x); +float cos_t(float phi); +float sin_t(float x); +float tan_t(float x); +float acos_t(float x); +float asin_t(float x); +float floor_t(float x); +float fmod_t(float num, float denom); #else - #include - #define sin_t sin - #define cos_t cos - #define tan_t tan - #define asin_t asin - #define acos_t acos - #define atan_t atan - #define fmod_t fmod - #define floor_t floor +#include +#define sin_t sin +#define cos_t cos +#define tan_t tan +#define asin_t asin +#define acos_t acos +#define atan_t atan +#define fmod_t fmod +#define floor_t floor #endif -//wled_serial.cpp +// wled_serial.cpp void handleSerial(); void updateBaudRate(uint32_t rate); -//wled_server.cpp +// wled_server.cpp bool isIp(String str); void createEditHandler(bool enable); bool captivePortal(AsyncWebServerRequest *request); void initServer(); void serveIndexOrWelcome(AsyncWebServerRequest *request); -void serveIndex(AsyncWebServerRequest* request); -String msgProcessor(const String& var); -void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255); -String dmxProcessor(const String& var); -void serveSettings(AsyncWebServerRequest* request, bool post = false); -void serveSettingsJS(AsyncWebServerRequest* request); - -//ws.cpp +void serveIndex(AsyncWebServerRequest *request); +String msgProcessor(const String &var); +void serveMessage(AsyncWebServerRequest *request, uint16_t code, const String &headl, const String &subl = "", byte optionT = 255); +String dmxProcessor(const String &var); +void serveSettings(AsyncWebServerRequest *request, bool post = false); +void serveSettingsJS(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); +void wsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len); +void sendDataWs(AsyncWebSocketClient *client = nullptr); -//xml.cpp -void XML_response(AsyncWebServerRequest *request, char* dest = nullptr); +// xml.cpp +void XML_response(AsyncWebServerRequest *request, char *dest = nullptr); void URL_response(AsyncWebServerRequest *request); -void getSettingsJS(byte subPage, char* dest); +void getSettingsJS(byte subPage, char *dest); #endif diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a5caaf472e..328cbec07b 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -1,31 +1,45 @@ #include "wled.h" +#include /* * MQTT communication protocol for home automation */ #ifdef WLED_ENABLE_MQTT -#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds +#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds -void parseMQTTBriPayload(char* payload) +// declaring this function up here +void otaUpdate(String url); + +void parseMQTTBriPayload(char *payload) { - if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} - else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);} - else { + if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) + { + bri = briLast; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + else if (strstr(payload, "T") || strstr(payload, "t")) + { + toggleOnOff(); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + else + { uint8_t in = strtoul(payload, NULL, 10); - if (in == 0 && bri > 0) briLast = bri; + if (in == 0 && bri > 0) + briLast = bri; bri = in; stateUpdated(CALL_MODE_DIRECT_CHANGE); } } - void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics char subuf[38]; - if (mqttDeviceTopic[0] != 0) { + if (mqttDeviceTopic[0] != 0) + { strlcpy(subuf, mqttDeviceTopic, 33); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); @@ -33,9 +47,13 @@ void onMqttConnect(bool sessionPresent) strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/update")); + mqtt->subscribe(subuf, 0); } - if (mqttGroupTopic[0] != 0) { + if (mqttGroupTopic[0] != 0) + { strlcpy(subuf, mqttGroupTopic, 33); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); @@ -51,44 +69,60 @@ void onMqttConnect(bool sessionPresent) DEBUG_PRINTLN(F("MQTT ready")); } - -void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { +void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) +{ static char *payloadStr; DEBUG_PRINT(F("MQTT msg: ")); DEBUG_PRINTLN(topic); + // set connected to true. If we got a message, we must be connected (this fixes a lot of issues with AsyncMqttClient) + mqtt->setConnected(true); // note that setConnected is a function that I added to AsyncMqttClient + // paranoia check to avoid npe if no payload - if (payload==nullptr) { + if (payload == nullptr) + { DEBUG_PRINTLN(F("no payload -> leave")); return; } - if (index == 0) { // start (1st partial packet or the only packet) - if (payloadStr) delete[] payloadStr; // fail-safe: release buffer - payloadStr = new char[total+1]; // allocate new buffer + if (index == 0) + { // start (1st partial packet or the only packet) + if (payloadStr) + delete[] payloadStr; // fail-safe: release buffer + payloadStr = new char[total + 1]; // allocate new buffer } - if (payloadStr == nullptr) return; // buffer not allocated + if (payloadStr == nullptr) + return; // buffer not allocated // copy (partial) packet to buffer and 0-terminate it if it is last packet - char* buff = payloadStr + index; + char *buff = payloadStr + index; memcpy(buff, payload, len); - if (index + len >= total) { // at end + if (index + len >= total) + { // at end payloadStr[total] = '\0'; // terminate c style string - } else { + } + else + { DEBUG_PRINTLN(F("Partial packet received.")); return; // process next packet } DEBUG_PRINTLN(payloadStr); size_t topicPrefixLen = strlen(mqttDeviceTopic); - if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) { + if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) + { topic += topicPrefixLen; - } else { + } + else + { topicPrefixLen = strlen(mqttGroupTopic); - if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) { + if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) + { topic += topicPrefixLen; - } else { + } + else + { // Non-Wled Topic used here. Probably a usermod subscribed to this topic. usermods.onMqttMessage(topic, payloadStr); delete[] payloadStr; @@ -97,30 +131,100 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties } } - //Prefix is stripped from the topic at this point + // Prefix is stripped from the topic at this point - if (strcmp_P(topic, PSTR("/col")) == 0) { + if (strcmp_P(topic, PSTR("/col")) == 0) + { colorFromDecOrHexString(col, payloadStr); colorUpdated(CALL_MODE_DIRECT_CHANGE); - } else if (strcmp_P(topic, PSTR("/api")) == 0) { - if (!requestJSONBufferLock(15)) { + } + else if (strcmp_P(topic, PSTR("/api")) == 0) + { + if (!requestJSONBufferLock(15)) + { delete[] payloadStr; payloadStr = nullptr; return; } - if (payloadStr[0] == '{') { //JSON API + if (payloadStr[0] == '{') + { // JSON API deserializeJson(doc, payloadStr); deserializeState(doc.as()); - } else { //HTTP API - String apireq = "win"; apireq += '&'; // reduce flash string usage + } + else + { // HTTP API + String apireq = "win"; + apireq += '&'; // reduce flash string usage apireq += payloadStr; handleSet(nullptr, apireq); } releaseJSONBufferLock(); - } else if (strlen(topic) != 0) { + } + else if (strcmp_P(topic, PSTR("/update")) == 0) + { + // get the json buffer lock + if (!requestJSONBufferLock(15)) + { + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // deserialize the request + deserializeJson(doc, payloadStr); + JsonObject obj = doc.as(); + + // make sure the request has a url + if (!obj.containsKey("url") || !obj["url"].is()) + { + DEBUG_PRINTLN("No url in request, won't update. Returning."); + // release the json buffer lock + releaseJSONBufferLock(); + // clear out the payload string + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // get the url + String url = obj["url"].as(); + + // request the response buffer lock + if (!requestResponseBufferLock()) + { + DEBUG_PRINTLN("Failed to get response buffer lock, returning."); + // release the json buffer lock + releaseJSONBufferLock(); + // clear out the payload string + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // make the response + mqttResponseDoc["id"] = obj["id"]; + mqttResponseDoc["update"] = "Starting update, do not power off the device."; + serializeJson(mqttResponseDoc, mqttResponseBuffer); + + // release the json buffer lock + releaseJSONBufferLock(); + + // send the response + mqtt->publish(mqttResponseTopic, 1, false, mqttResponseBuffer); + + // release the response buffer lock + releaseResponseBufferLock(); + + // do the update + return otaUpdate(url); + } + else if (strlen(topic) != 0) + { // non standard topic, check with usermods usermods.onMqttMessage(topic, payloadStr); - } else { + } + else + { // topmost topic (just wled/MAC) parseMQTTBriPayload(payloadStr); } @@ -128,71 +232,229 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties payloadStr = nullptr; } - void publishMqtt() { doPublishMqtt = false; - if (!WLED_MQTT_CONNECTED) return; + if (!WLED_MQTT_CONNECTED) + return; DEBUG_PRINTLN(F("Publish MQTT")); - #ifndef USERMOD_SMARTNEST +#ifndef USERMOD_SMARTNEST char s[10]; char subuf[38]; sprintf_P(s, PSTR("%u"), bri); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/g")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/c")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/status")); - mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT - char apires[1024]; // allocating 1024 bytes from stack can be risky + char apires[1024]; // allocating 1024 bytes from stack can be risky XML_response(nullptr, apires); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/v")); - mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) - #endif + mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) +#endif } - -//HA autodiscovery was removed in favor of the native integration in HA v0.102.0 +// HA autodiscovery was removed in favor of the native integration in HA v0.102.0 bool initMqtt() { - if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; + DEBUG_PRINTLN(F("Initializing MQTT")); + // set the important variables + mqttEnabled = true; + strlcpy(mqttServer, "my-server-name-here", MQTT_MAX_SERVER_LEN + 1); // put actual mqtt server here, I use emqx + mqttPort = 0; // put actual port here + strlcpy(mqttUser, "username", 41); // put actual username here + strlcpy(mqttPass, "password", 65); // put actual password here + + if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) + return false; - if (mqtt == nullptr) { + if (mqtt == nullptr) + { mqtt = new AsyncMqttClient(); mqtt->onMessage(onMqttMessage); mqtt->onConnect(onMqttConnect); } - if (mqtt->connected()) return true; + if (mqtt->connected()) + return true; - DEBUG_PRINTLN(F("Reconnecting MQTT")); + DEBUG_PRINTLN(F("Reconnecting MQTT with info:")); + DEBUG_PRINTLN(mqttServer); + DEBUG_PRINTLN(mqttPort); + DEBUG_PRINTLN(mqttUser); + DEBUG_PRINTLN(mqttPass); IPAddress mqttIP; - if (mqttIP.fromString(mqttServer)) //see if server is IP or domain + if (mqttIP.fromString(mqttServer)) // see if server is IP or domain { mqtt->setServer(mqttIP, mqttPort); - } else { + } + else + { mqtt->setServer(mqttServer, mqttPort); } mqtt->setClientId(mqttClientID); - if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); + if (mqttUser[0] && mqttPass[0]) + mqtt->setCredentials(mqttUser, mqttPass); - #ifndef USERMOD_SMARTNEST +#ifndef USERMOD_SMARTNEST strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); strcat_P(mqttStatusTopic, PSTR("/status")); mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message - #endif +#endif mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); mqtt->connect(); return true; } + +void otaUpdate(String url) +{ + DEBUG_PRINT(F("OTA update from URL: ")); + DEBUG_PRINTLN(url); + + // make client for HTTP request + HTTPClient http; + http.begin(url); + http.setTimeout(3000000); // 5 minute timeout, may change + + // do a get request to get the update binary + int httpCode = http.GET(); + // make sure the request was successful + if (httpCode != HTTP_CODE_OK) + { + DEBUG_PRINT(F("HTTP GET failed, code: ")); + DEBUG_PRINTLN(httpCode); + http.end(); + return; + } + + // disable the watchdog + WLED::instance().disableWatchdog(); + otaInProgress = true; // I've tried both with and without this and neither works + + // get the size of the update + int len = http.getSize(); + DEBUG_PRINT(F("Update size: ")); + DEBUG_PRINTLN(len); + + // make a buffer for reading + WiFiClient *stream = http.getStreamPtr(); + + DEBUG_PRINTLN("Got stream"); + + // Initialize Update + if (!Update.begin(len)) + { + DEBUG_PRINTLN(F("Update.begin failed, most likely not enough space")); + http.end(); + WLED::instance().enableWatchdog(); + otaInProgress = false; + return; + } + + DEBUG_PRINTLN("Update.begin succeeded"); + DEBUG_PRINTLN("Is the stream null?"); + DEBUG_PRINTLN(stream == nullptr); + DEBUG_PRINT(F("Free Heap: ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); + + // write the update to the device + size_t written = 0; + int bufferSize = 512; + uint8_t buffer[bufferSize]; + // size_t written = Update.writeStream(*stream); + while (http.connected() && written < len) + { + if (stream->available()) + { + int bytesRead = stream->readBytes(buffer, bufferSize); + if (bytesRead == 0) + { + DEBUG_PRINTLN("No bytes read"); + } + written += Update.write(buffer, bytesRead); + DEBUG_PRINT("Bytes written: "); + DEBUG_PRINTLN(written); + if (ESP.getFreeHeap() < 80000) + { + DEBUG_PRINT(F("Free Heap below 80000: ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); + } + if (http.connected() != 1) + { + DEBUG_PRINT("http Connection status: "); + DEBUG_PRINTLN(http.connected()); + } + if (WiFi.status() != 3) + { + DEBUG_PRINT("Wifi status: "); + DEBUG_PRINTLN(WiFi.status()); + } + } + else + { + DEBUG_PRINTLN("No bytes available"); + } + delay(10); + } + + DEBUG_PRINTLN("Wrote stream"); + + // check if the update was successful + if (written == len) + { + DEBUG_PRINTLN(F("Written to flash successfully")); + } + else + { + DEBUG_PRINT(F("Update failed, only wrote : ")); + DEBUG_PRINT(written); + DEBUG_PRINTLN(F(" bytes")); + http.end(); + WLED::instance().enableWatchdog(); + otaInProgress = false; + return; + } + + // End the update process + if (Update.end()) + { + if (Update.isFinished()) + { + DEBUG_PRINTLN(F("Update finished successfully, restarting now")); + http.end(); + delay(1000); + ESP.restart(); + } + else + { + DEBUG_PRINTLN(F("Update not finished, something went wrong!")); + } + } + else + { + DEBUG_PRINT(F("OTA Error Occurred. Error: ")); + DEBUG_PRINT(Update.errorString()); + DEBUG_PRINT(" Code: "); + DEBUG_PRINTLN(Update.getError()); + } + + // reenable the watchdog + WLED::instance().enableWatchdog(); + // end the http request + http.end(); + // set ota in progress to false + otaInProgress = false; +} + #endif diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp index d0c44cb6ba..def0b52ab9 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp @@ -1,40 +1,28 @@ #include "AsyncMqttClient.hpp" AsyncMqttClient::AsyncMqttClient() -: _connected(false) -, _connectPacketNotEnoughSpace(false) -, _disconnectFlagged(false) -, _tlsBadFingerprint(false) -, _lastClientActivity(0) -, _lastServerActivity(0) -, _lastPingRequestTime(0) -, _host(nullptr) -, _useIp(false) + : _connected(false), _connectPacketNotEnoughSpace(false), _disconnectFlagged(false), _tlsBadFingerprint(false), _lastClientActivity(0), _lastServerActivity(0), _lastPingRequestTime(0), _host(nullptr), _useIp(false) #if ASYNC_TCP_SSL_ENABLED -, _secure(false) + , + _secure(false) #endif -, _port(0) -, _keepAlive(15) -, _cleanSession(true) -, _clientId(nullptr) -, _username(nullptr) -, _password(nullptr) -, _willTopic(nullptr) -, _willPayload(nullptr) -, _willPayloadLength(0) -, _willQos(0) -, _willRetain(false) -, _parsingInformation { .bufferState = AsyncMqttClientInternals::BufferState::NONE } -, _currentParsedPacket(nullptr) -, _remainingLengthBufferPosition(0) -, _nextPacketId(1) { - _client.onConnect([](void* obj, AsyncClient* c) { (static_cast(obj))->_onConnect(c); }, this); - _client.onDisconnect([](void* obj, AsyncClient* c) { (static_cast(obj))->_onDisconnect(c); }, this); - _client.onError([](void* obj, AsyncClient* c, int8_t error) { (static_cast(obj))->_onError(c, error); }, this); - _client.onTimeout([](void* obj, AsyncClient* c, uint32_t time) { (static_cast(obj))->_onTimeout(c, time); }, this); - _client.onAck([](void* obj, AsyncClient* c, size_t len, uint32_t time) { (static_cast(obj))->_onAck(c, len, time); }, this); - _client.onData([](void* obj, AsyncClient* c, void* data, size_t len) { (static_cast(obj))->_onData(c, static_cast(data), len); }, this); - _client.onPoll([](void* obj, AsyncClient* c) { (static_cast(obj))->_onPoll(c); }, this); + , + _port(0), _keepAlive(15), _cleanSession(true), _clientId(nullptr), _username(nullptr), _password(nullptr), _willTopic(nullptr), _willPayload(nullptr), _willPayloadLength(0), _willQos(0), _willRetain(false), _parsingInformation{.bufferState = AsyncMqttClientInternals::BufferState::NONE}, _currentParsedPacket(nullptr), _remainingLengthBufferPosition(0), _nextPacketId(1) +{ + _client.onConnect([](void *obj, AsyncClient *c) + { (static_cast(obj))->_onConnect(c); }, this); + _client.onDisconnect([](void *obj, AsyncClient *c) + { (static_cast(obj))->_onDisconnect(c); }, this); + _client.onError([](void *obj, AsyncClient *c, int8_t error) + { (static_cast(obj))->_onError(c, error); }, this); + _client.onTimeout([](void *obj, AsyncClient *c, uint32_t time) + { (static_cast(obj))->_onTimeout(c, time); }, this); + _client.onAck([](void *obj, AsyncClient *c, size_t len, uint32_t time) + { (static_cast(obj))->_onAck(c, len, time); }, this); + _client.onData([](void *obj, AsyncClient *c, void *data, size_t len) + { (static_cast(obj))->_onData(c, static_cast(data), len); }, this); + _client.onPoll([](void *obj, AsyncClient *c) + { (static_cast(obj))->_onPoll(c); }, this); #ifdef ESP32 sprintf(_generatedClientId, "esp32%06x", (uint32_t)ESP.getEfuseMac()); @@ -47,7 +35,8 @@ AsyncMqttClient::AsyncMqttClient() setMaxTopicLength(128); } -AsyncMqttClient::~AsyncMqttClient() { +AsyncMqttClient::~AsyncMqttClient() +{ delete _currentParsedPacket; delete[] _parsingInformation.topicBuffer; #ifdef ESP32 @@ -55,35 +44,41 @@ AsyncMqttClient::~AsyncMqttClient() { #endif } -AsyncMqttClient& AsyncMqttClient::setKeepAlive(uint16_t keepAlive) { +AsyncMqttClient &AsyncMqttClient::setKeepAlive(uint16_t keepAlive) +{ _keepAlive = keepAlive; return *this; } -AsyncMqttClient& AsyncMqttClient::setClientId(const char* clientId) { +AsyncMqttClient &AsyncMqttClient::setClientId(const char *clientId) +{ _clientId = clientId; return *this; } -AsyncMqttClient& AsyncMqttClient::setCleanSession(bool cleanSession) { +AsyncMqttClient &AsyncMqttClient::setCleanSession(bool cleanSession) +{ _cleanSession = cleanSession; return *this; } -AsyncMqttClient& AsyncMqttClient::setMaxTopicLength(uint16_t maxTopicLength) { +AsyncMqttClient &AsyncMqttClient::setMaxTopicLength(uint16_t maxTopicLength) +{ _parsingInformation.maxTopicLength = maxTopicLength; delete[] _parsingInformation.topicBuffer; _parsingInformation.topicBuffer = new char[maxTopicLength + 1]; return *this; } -AsyncMqttClient& AsyncMqttClient::setCredentials(const char* username, const char* password) { +AsyncMqttClient &AsyncMqttClient::setCredentials(const char *username, const char *password) +{ _username = username; _password = password; return *this; } -AsyncMqttClient& AsyncMqttClient::setWill(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length) { +AsyncMqttClient &AsyncMqttClient::setWill(const char *topic, uint8_t qos, bool retain, const char *payload, size_t length) +{ _willTopic = topic; _willQos = qos; _willRetain = retain; @@ -92,14 +87,16 @@ AsyncMqttClient& AsyncMqttClient::setWill(const char* topic, uint8_t qos, bool r return *this; } -AsyncMqttClient& AsyncMqttClient::setServer(IPAddress ip, uint16_t port) { +AsyncMqttClient &AsyncMqttClient::setServer(IPAddress ip, uint16_t port) +{ _useIp = true; _ip = ip; _port = port; return *this; } -AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) { +AsyncMqttClient &AsyncMqttClient::setServer(const char *host, uint16_t port) +{ _useIp = false; _host = host; _port = port; @@ -107,12 +104,14 @@ AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) { } #if ASYNC_TCP_SSL_ENABLED -AsyncMqttClient& AsyncMqttClient::setSecure(bool secure) { +AsyncMqttClient &AsyncMqttClient::setSecure(bool secure) +{ _secure = secure; return *this; } -AsyncMqttClient& AsyncMqttClient::addServerFingerprint(const uint8_t* fingerprint) { +AsyncMqttClient &AsyncMqttClient::addServerFingerprint(const uint8_t *fingerprint) +{ std::array newFingerprint; memcpy(newFingerprint.data(), fingerprint, SHA1_SIZE); _secureServerFingerprints.push_back(newFingerprint); @@ -120,43 +119,52 @@ AsyncMqttClient& AsyncMqttClient::addServerFingerprint(const uint8_t* fingerprin } #endif -AsyncMqttClient& AsyncMqttClient::onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback) +{ _onConnectUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient& AsyncMqttClient::onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback) +{ _onDisconnectUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient& AsyncMqttClient::onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback) +{ _onSubscribeUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient& AsyncMqttClient::onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback) +{ _onUnsubscribeUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient& AsyncMqttClient::onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback) +{ _onMessageUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient& AsyncMqttClient::onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback) { +AsyncMqttClient &AsyncMqttClient::onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback) +{ _onPublishUserCallbacks.push_back(callback); return *this; } -void AsyncMqttClient::_freeCurrentParsedPacket() { +void AsyncMqttClient::_freeCurrentParsedPacket() +{ delete _currentParsedPacket; _currentParsedPacket = nullptr; } -void AsyncMqttClient::_clear() { +void AsyncMqttClient::_clear() +{ _lastPingRequestTime = 0; + Serial.println("SETTING CONNECTED TO FALSE"); _connected = false; _disconnectFlagged = false; _connectPacketNotEnoughSpace = false; @@ -174,22 +182,27 @@ void AsyncMqttClient::_clear() { } /* TCP */ -void AsyncMqttClient::_onConnect(AsyncClient* client) { +void AsyncMqttClient::_onConnect(AsyncClient *client) +{ (void)client; #if ASYNC_TCP_SSL_ENABLED - if (_secure && _secureServerFingerprints.size() > 0) { - SSL* clientSsl = _client.getSSL(); + if (_secure && _secureServerFingerprints.size() > 0) + { + SSL *clientSsl = _client.getSSL(); bool sslFoundFingerprint = false; - for (std::array fingerprint : _secureServerFingerprints) { - if (ssl_match_fingerprint(clientSsl, fingerprint.data()) == SSL_OK) { + for (std::array fingerprint : _secureServerFingerprints) + { + if (ssl_match_fingerprint(clientSsl, fingerprint.data()) == SSL_OK) + { sslFoundFingerprint = true; break; } } - if (!sslFoundFingerprint) { + if (!sslFoundFingerprint) + { _tlsBadFingerprint = true; _client.close(true); return; @@ -198,6 +211,7 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { #endif char fixedHeader[5]; + Serial.println("CONNECTED CALLBACK"); fixedHeader[0] = AsyncMqttClientInternals::PacketType.CONNECT; fixedHeader[0] = fixedHeader[0] << 4; fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.CONNECT_RESERVED; @@ -212,22 +226,28 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { char connectFlags[1]; connectFlags[0] = 0; - if (_cleanSession) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION; - if (_username != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME; - if (_password != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD; - if (_willTopic != nullptr) { + if (_cleanSession) + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION; + if (_username != nullptr) + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME; + if (_password != nullptr) + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD; + if (_willTopic != nullptr) + { connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL; - if (_willRetain) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN; - switch (_willQos) { - case 0: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0; - break; - case 1: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1; - break; - case 2: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2; - break; + if (_willRetain) + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN; + switch (_willQos) + { + case 0: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0; + break; + case 1: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1; + break; + case 2: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2; + break; } } @@ -245,12 +265,14 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { char willTopicLengthBytes[2]; uint16_t willPayloadLength = _willPayloadLength; char willPayloadLengthBytes[2]; - if (_willTopic != nullptr) { + if (_willTopic != nullptr) + { willTopicLength = strlen(_willTopic); willTopicLengthBytes[0] = willTopicLength >> 8; willTopicLengthBytes[1] = willTopicLength & 0xFF; - if (_willPayload != nullptr && willPayloadLength == 0) willPayloadLength = strlen(_willPayload); + if (_willPayload != nullptr && willPayloadLength == 0) + willPayloadLength = strlen(_willPayload); willPayloadLengthBytes[0] = willPayloadLength >> 8; willPayloadLengthBytes[1] = willPayloadLength & 0xFF; @@ -258,7 +280,8 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { uint16_t usernameLength = 0; char usernameLengthBytes[2]; - if (_username != nullptr) { + if (_username != nullptr) + { usernameLength = strlen(_username); usernameLengthBytes[0] = usernameLength >> 8; usernameLengthBytes[1] = usernameLength & 0xFF; @@ -266,16 +289,20 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { uint16_t passwordLength = 0; char passwordLengthBytes[2]; - if (_password != nullptr) { + if (_password != nullptr) + { passwordLength = strlen(_password); passwordLengthBytes[0] = passwordLength >> 8; passwordLengthBytes[1] = passwordLength & 0xFF; } - uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present - if (_willTopic != nullptr) remainingLength += 2 + willTopicLength + 2 + willPayloadLength; - if (_username != nullptr) remainingLength += 2 + usernameLength; - if (_password != nullptr) remainingLength += 2 + passwordLength; + uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present + if (_willTopic != nullptr) + remainingLength += 2 + willTopicLength + 2 + willPayloadLength; + if (_username != nullptr) + remainingLength += 2 + usernameLength; + if (_password != nullptr) + remainingLength += 2 + passwordLength; uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1); uint32_t neededSpace = 1 + remainingLengthLength; @@ -286,24 +313,29 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { neededSpace += 2; neededSpace += 2; neededSpace += clientIdLength; - if (_willTopic != nullptr) { + if (_willTopic != nullptr) + { neededSpace += 2; neededSpace += willTopicLength; neededSpace += 2; - if (_willPayload != nullptr) neededSpace += willPayloadLength; + if (_willPayload != nullptr) + neededSpace += willPayloadLength; } - if (_username != nullptr) { + if (_username != nullptr) + { neededSpace += 2; neededSpace += usernameLength; } - if (_password != nullptr) { + if (_password != nullptr) + { neededSpace += 2; neededSpace += passwordLength; } SEMAPHORE_TAKE(); - if (_client.space() < neededSpace) { + if (_client.space() < neededSpace) + { _connectPacketNotEnoughSpace = true; _client.close(true); SEMAPHORE_GIVE(); @@ -318,18 +350,22 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { _client.add(keepAliveBytes, 2); _client.add(clientIdLengthBytes, 2); _client.add(_clientId, clientIdLength); - if (_willTopic != nullptr) { + if (_willTopic != nullptr) + { _client.add(willTopicLengthBytes, 2); _client.add(_willTopic, willTopicLength); _client.add(willPayloadLengthBytes, 2); - if (_willPayload != nullptr) _client.add(_willPayload, willPayloadLength); + if (_willPayload != nullptr) + _client.add(_willPayload, willPayloadLength); } - if (_username != nullptr) { + if (_username != nullptr) + { _client.add(usernameLengthBytes, 2); _client.add(_username, usernameLength); } - if (_password != nullptr) { + if (_password != nullptr) + { _client.add(passwordLengthBytes, 2); _client.add(_password, passwordLength); } @@ -338,125 +374,152 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) { SEMAPHORE_GIVE(); } -void AsyncMqttClient::_onDisconnect(AsyncClient* client) { +void AsyncMqttClient::_onDisconnect(AsyncClient *client) +{ + Serial.println("DISCONNECTED CALLBACK, Will set connected to false"); (void)client; - if (!_disconnectFlagged) { + if (!_disconnectFlagged) + { AsyncMqttClientDisconnectReason reason; - if (_connectPacketNotEnoughSpace) { + if (_connectPacketNotEnoughSpace) + { reason = AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE; - } else if (_tlsBadFingerprint) { + } + else if (_tlsBadFingerprint) + { reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT; - } else { + } + else + { reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED; } - for (auto callback : _onDisconnectUserCallbacks) callback(reason); + for (auto callback : _onDisconnectUserCallbacks) + callback(reason); } _clear(); } -void AsyncMqttClient::_onError(AsyncClient* client, int8_t error) { +void AsyncMqttClient::_onError(AsyncClient *client, int8_t error) +{ (void)client; (void)error; // _onDisconnect called anyway } -void AsyncMqttClient::_onTimeout(AsyncClient* client, uint32_t time) { +void AsyncMqttClient::_onTimeout(AsyncClient *client, uint32_t time) +{ (void)client; (void)time; // disconnection will be handled by ping/pong management } -void AsyncMqttClient::_onAck(AsyncClient* client, size_t len, uint32_t time) { +void AsyncMqttClient::_onAck(AsyncClient *client, size_t len, uint32_t time) +{ (void)client; (void)len; (void)time; } -void AsyncMqttClient::_onData(AsyncClient* client, char* data, size_t len) { +void AsyncMqttClient::_onData(AsyncClient *client, char *data, size_t len) +{ (void)client; size_t currentBytePosition = 0; char currentByte; - do { - switch (_parsingInformation.bufferState) { - case AsyncMqttClientInternals::BufferState::NONE: - currentByte = data[currentBytePosition++]; - _parsingInformation.packetType = currentByte >> 4; - _parsingInformation.packetFlags = (currentByte << 4) >> 4; - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::REMAINING_LENGTH; - _lastServerActivity = millis(); - switch (_parsingInformation.packetType) { - case AsyncMqttClientInternals::PacketType.CONNACK: - _currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.PINGRESP: - _currentParsedPacket = new AsyncMqttClientInternals::PingRespPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPingResp, this)); - break; - case AsyncMqttClientInternals::PacketType.SUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::SubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onSubAck, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.UNSUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::UnsubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onUnsubAck, this, std::placeholders::_1)); - break; - case AsyncMqttClientInternals::PacketType.PUBLISH: - _currentParsedPacket = new AsyncMqttClientInternals::PublishPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), std::bind(&AsyncMqttClient::_onPublish, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.PUBREL: - _currentParsedPacket = new AsyncMqttClientInternals::PubRelPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRel, this, std::placeholders::_1)); - break; - case AsyncMqttClientInternals::PacketType.PUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::PubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubAck, this, std::placeholders::_1)); - break; - case AsyncMqttClientInternals::PacketType.PUBREC: - _currentParsedPacket = new AsyncMqttClientInternals::PubRecPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRec, this, std::placeholders::_1)); - break; - case AsyncMqttClientInternals::PacketType.PUBCOMP: - _currentParsedPacket = new AsyncMqttClientInternals::PubCompPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubComp, this, std::placeholders::_1)); - break; - default: - break; - } + do + { + switch (_parsingInformation.bufferState) + { + case AsyncMqttClientInternals::BufferState::NONE: + currentByte = data[currentBytePosition++]; + _parsingInformation.packetType = currentByte >> 4; + _parsingInformation.packetFlags = (currentByte << 4) >> 4; + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::REMAINING_LENGTH; + _lastServerActivity = millis(); + switch (_parsingInformation.packetType) + { + case AsyncMqttClientInternals::PacketType.CONNACK: + _currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2)); break; - case AsyncMqttClientInternals::BufferState::REMAINING_LENGTH: - currentByte = data[currentBytePosition++]; - _remainingLengthBuffer[_remainingLengthBufferPosition++] = currentByte; - if (currentByte >> 7 == 0) { - _parsingInformation.remainingLength = AsyncMqttClientInternals::Helpers::decodeRemainingLength(_remainingLengthBuffer); - _remainingLengthBufferPosition = 0; - if (_parsingInformation.remainingLength > 0) { - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::VARIABLE_HEADER; - } else { - // PINGRESP is a special case where it has no variable header, so the packet ends right here - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE; - _onPingResp(); - } - } + case AsyncMqttClientInternals::PacketType.PINGRESP: + _currentParsedPacket = new AsyncMqttClientInternals::PingRespPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPingResp, this)); + break; + case AsyncMqttClientInternals::PacketType.SUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::SubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onSubAck, this, std::placeholders::_1, std::placeholders::_2)); + break; + case AsyncMqttClientInternals::PacketType.UNSUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::UnsubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onUnsubAck, this, std::placeholders::_1)); break; - case AsyncMqttClientInternals::BufferState::VARIABLE_HEADER: - _currentParsedPacket->parseVariableHeader(data, len, ¤tBytePosition); + case AsyncMqttClientInternals::PacketType.PUBLISH: + _currentParsedPacket = new AsyncMqttClientInternals::PublishPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), std::bind(&AsyncMqttClient::_onPublish, this, std::placeholders::_1, std::placeholders::_2)); break; - case AsyncMqttClientInternals::BufferState::PAYLOAD: - _currentParsedPacket->parsePayload(data, len, ¤tBytePosition); + case AsyncMqttClientInternals::PacketType.PUBREL: + _currentParsedPacket = new AsyncMqttClientInternals::PubRelPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRel, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::PubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubAck, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBREC: + _currentParsedPacket = new AsyncMqttClientInternals::PubRecPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRec, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBCOMP: + _currentParsedPacket = new AsyncMqttClientInternals::PubCompPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubComp, this, std::placeholders::_1)); break; default: - currentBytePosition = len; + break; + } + break; + case AsyncMqttClientInternals::BufferState::REMAINING_LENGTH: + currentByte = data[currentBytePosition++]; + _remainingLengthBuffer[_remainingLengthBufferPosition++] = currentByte; + if (currentByte >> 7 == 0) + { + _parsingInformation.remainingLength = AsyncMqttClientInternals::Helpers::decodeRemainingLength(_remainingLengthBuffer); + _remainingLengthBufferPosition = 0; + if (_parsingInformation.remainingLength > 0) + { + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::VARIABLE_HEADER; + } + else + { + // PINGRESP is a special case where it has no variable header, so the packet ends right here + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE; + _onPingResp(); + } + } + break; + case AsyncMqttClientInternals::BufferState::VARIABLE_HEADER: + _currentParsedPacket->parseVariableHeader(data, len, ¤tBytePosition); + break; + case AsyncMqttClientInternals::BufferState::PAYLOAD: + _currentParsedPacket->parsePayload(data, len, ¤tBytePosition); + break; + default: + currentBytePosition = len; } } while (currentBytePosition != len); } -void AsyncMqttClient::_onPoll(AsyncClient* client) { - if (!_connected) return; +void AsyncMqttClient::_onPoll(AsyncClient *client) +{ + if (!_connected) + return; // if there is too much time the client has sent a ping request without a response, disconnect client to avoid half open connections - if (_lastPingRequestTime != 0 && (millis() - _lastPingRequestTime) >= (_keepAlive * 1000 * 2)) { + if (_lastPingRequestTime != 0 && (millis() - _lastPingRequestTime) >= (_keepAlive * 1000 * 2)) + { disconnect(); return; - // send ping to ensure the server will receive at least one message inside keepalive window - } else if (_lastPingRequestTime == 0 && (millis() - _lastClientActivity) >= (_keepAlive * 1000 * 0.7)) { + // send ping to ensure the server will receive at least one message inside keepalive window + } + else if (_lastPingRequestTime == 0 && (millis() - _lastClientActivity) >= (_keepAlive * 1000 * 0.7)) + { _sendPing(); - // send ping to verify if the server is still there (ensure this is not a half connection) - } else if (_connected && _lastPingRequestTime == 0 && (millis() - _lastServerActivity) >= (_keepAlive * 1000 * 0.7)) { + // send ping to verify if the server is still there (ensure this is not a half connection) + } + else if (_connected && _lastPingRequestTime == 0 && (millis() - _lastServerActivity) >= (_keepAlive * 1000 * 0.7)) + { _sendPing(); } @@ -466,87 +529,113 @@ void AsyncMqttClient::_onPoll(AsyncClient* client) { // handle disconnect - if (_disconnectFlagged) { + if (_disconnectFlagged) + { _sendDisconnect(); } } /* MQTT */ -void AsyncMqttClient::_onPingResp() { +void AsyncMqttClient::_onPingResp() +{ _freeCurrentParsedPacket(); _lastPingRequestTime = 0; } -void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode) { +void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode) +{ (void)sessionPresent; _freeCurrentParsedPacket(); - if (connectReturnCode == 0) { + if (connectReturnCode == 0) + { + Serial.println("SETTING CONNECTED TO TRUE"); _connected = true; - for (auto callback : _onConnectUserCallbacks) callback(sessionPresent); - } else { - for (auto callback : _onDisconnectUserCallbacks) callback(static_cast(connectReturnCode)); + for (auto callback : _onConnectUserCallbacks) + callback(sessionPresent); + } + else + { + for (auto callback : _onDisconnectUserCallbacks) + callback(static_cast(connectReturnCode)); _disconnectFlagged = true; } } -void AsyncMqttClient::_onSubAck(uint16_t packetId, char status) { +void AsyncMqttClient::_onSubAck(uint16_t packetId, char status) +{ _freeCurrentParsedPacket(); - for (auto callback : _onSubscribeUserCallbacks) callback(packetId, status); + for (auto callback : _onSubscribeUserCallbacks) + callback(packetId, status); } -void AsyncMqttClient::_onUnsubAck(uint16_t packetId) { +void AsyncMqttClient::_onUnsubAck(uint16_t packetId) +{ _freeCurrentParsedPacket(); - for (auto callback : _onUnsubscribeUserCallbacks) callback(packetId); + for (auto callback : _onUnsubscribeUserCallbacks) + callback(packetId); } -void AsyncMqttClient::_onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId) { +void AsyncMqttClient::_onMessage(char *topic, char *payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId) +{ bool notifyPublish = true; - if (qos == 2) { - for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) { - if (pendingPubRel.packetId == packetId) { + if (qos == 2) + { + for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) + { + if (pendingPubRel.packetId == packetId) + { notifyPublish = false; break; } } } - if (notifyPublish) { + if (notifyPublish) + { AsyncMqttClientMessageProperties properties; properties.qos = qos; properties.dup = dup; properties.retain = retain; - for (auto callback : _onMessageUserCallbacks) callback(topic, payload, properties, len, index, total); + for (auto callback : _onMessageUserCallbacks) + callback(topic, payload, properties, len, index, total); } } -void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) { +void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) +{ AsyncMqttClientInternals::PendingAck pendingAck; - if (qos == 1) { + if (qos == 1) + { pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBACK; pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBACK_RESERVED; pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); - } else if (qos == 2) { + } + else if (qos == 2) + { pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBREC; pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBREC_RESERVED; pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); bool pubRelAwaiting = false; - for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) { - if (pendingPubRel.packetId == packetId) { + for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) + { + if (pendingPubRel.packetId == packetId) + { pubRelAwaiting = true; break; } } - if (!pubRelAwaiting) { + if (!pubRelAwaiting) + { AsyncMqttClientInternals::PendingPubRel pendingPubRel; pendingPubRel.packetId = packetId; _pendingPubRels.push_back(pendingPubRel); @@ -558,7 +647,8 @@ void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) { _freeCurrentParsedPacket(); } -void AsyncMqttClient::_onPubRel(uint16_t packetId) { +void AsyncMqttClient::_onPubRel(uint16_t packetId) +{ _freeCurrentParsedPacket(); AsyncMqttClientInternals::PendingAck pendingAck; @@ -567,8 +657,10 @@ void AsyncMqttClient::_onPubRel(uint16_t packetId) { pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); - for (size_t i = 0; i < _pendingPubRels.size(); i++) { - if (_pendingPubRels[i].packetId == packetId) { + for (size_t i = 0; i < _pendingPubRels.size(); i++) + { + if (_pendingPubRels[i].packetId == packetId) + { _pendingPubRels.erase(_pendingPubRels.begin() + i); _pendingPubRels.shrink_to_fit(); } @@ -577,13 +669,16 @@ void AsyncMqttClient::_onPubRel(uint16_t packetId) { _sendAcks(); } -void AsyncMqttClient::_onPubAck(uint16_t packetId) { +void AsyncMqttClient::_onPubAck(uint16_t packetId) +{ _freeCurrentParsedPacket(); - for (auto callback : _onPublishUserCallbacks) callback(packetId); + for (auto callback : _onPublishUserCallbacks) + callback(packetId); } -void AsyncMqttClient::_onPubRec(uint16_t packetId) { +void AsyncMqttClient::_onPubRec(uint16_t packetId) +{ _freeCurrentParsedPacket(); AsyncMqttClientInternals::PendingAck pendingAck; @@ -595,13 +690,16 @@ void AsyncMqttClient::_onPubRec(uint16_t packetId) { _sendAcks(); } -void AsyncMqttClient::_onPubComp(uint16_t packetId) { +void AsyncMqttClient::_onPubComp(uint16_t packetId) +{ _freeCurrentParsedPacket(); - for (auto callback : _onPublishUserCallbacks) callback(packetId); + for (auto callback : _onPublishUserCallbacks) + callback(packetId); } -bool AsyncMqttClient::_sendPing() { +bool AsyncMqttClient::_sendPing() +{ char fixedHeader[2]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.PINGREQ; fixedHeader[0] = fixedHeader[0] << 4; @@ -611,7 +709,11 @@ bool AsyncMqttClient::_sendPing() { size_t neededSpace = 2; SEMAPHORE_TAKE(false); - if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; } + if (_client.space() < neededSpace) + { + SEMAPHORE_GIVE(); + return false; + } _client.add(fixedHeader, 2); _client.send(); @@ -622,12 +724,15 @@ bool AsyncMqttClient::_sendPing() { return true; } -void AsyncMqttClient::_sendAcks() { +void AsyncMqttClient::_sendAcks() +{ uint8_t neededAckSpace = 2 + 2; SEMAPHORE_TAKE(); - for (size_t i = 0; i < _toSendAcks.size(); i++) { - if (_client.space() < neededAckSpace) break; + for (size_t i = 0; i < _toSendAcks.size(); i++) + { + if (_client.space() < neededAckSpace) + break; AsyncMqttClientInternals::PendingAck pendingAck = _toSendAcks[i]; @@ -653,14 +758,20 @@ void AsyncMqttClient::_sendAcks() { SEMAPHORE_GIVE(); } -bool AsyncMqttClient::_sendDisconnect() { - if (!_connected) return true; +bool AsyncMqttClient::_sendDisconnect() +{ + if (!_connected) + return true; const uint8_t neededSpace = 2; SEMAPHORE_TAKE(false); - if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; } + if (_client.space() < neededSpace) + { + SEMAPHORE_GIVE(); + return false; + } char fixedHeader[2]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.DISCONNECT; @@ -678,50 +789,68 @@ bool AsyncMqttClient::_sendDisconnect() { return true; } -uint16_t AsyncMqttClient::_getNextPacketId() { +uint16_t AsyncMqttClient::_getNextPacketId() +{ uint16_t nextPacketId = _nextPacketId; - if (_nextPacketId == 65535) _nextPacketId = 0; // 0 is forbidden + if (_nextPacketId == 65535) + _nextPacketId = 0; // 0 is forbidden _nextPacketId++; return nextPacketId; } -bool AsyncMqttClient::connected() const { +bool AsyncMqttClient::connected() const +{ return _connected; } -void AsyncMqttClient::connect() { - if (_connected) return; +void AsyncMqttClient::connect() +{ + if (_connected) + return; #if ASYNC_TCP_SSL_ENABLED - if (_useIp) { + if (_useIp) + { _client.connect(_ip, _port, _secure); - } else { + } + else + { _client.connect(_host, _port, _secure); } #else - if (_useIp) { + if (_useIp) + { _client.connect(_ip, _port); - } else { + } + else + { _client.connect(_host, _port); } #endif } -void AsyncMqttClient::disconnect(bool force) { - if (!_connected) return; +void AsyncMqttClient::disconnect(bool force) +{ + if (!_connected) + return; - if (force) { + if (force) + { _client.close(true); - } else { + } + else + { _disconnectFlagged = true; _sendDisconnect(); } } -uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) { - if (!_connected) return 0; +uint16_t AsyncMqttClient::subscribe(const char *topic, uint8_t qos) +{ + if (!_connected) + return 0; char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.SUBSCRIBE; @@ -746,7 +875,11 @@ uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) { neededSpace += 1; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } + if (_client.space() < neededSpace) + { + SEMAPHORE_GIVE(); + return 0; + } uint16_t packetId = _getNextPacketId(); char packetIdBytes[2]; @@ -765,8 +898,10 @@ uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) { return packetId; } -uint16_t AsyncMqttClient::unsubscribe(const char* topic) { - if (!_connected) return 0; +uint16_t AsyncMqttClient::unsubscribe(const char *topic) +{ + if (!_connected) + return 0; char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.UNSUBSCRIBE; @@ -787,7 +922,11 @@ uint16_t AsyncMqttClient::unsubscribe(const char* topic) { neededSpace += topicLength; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } + if (_client.space() < neededSpace) + { + SEMAPHORE_GIVE(); + return 0; + } uint16_t packetId = _getNextPacketId(); char packetIdBytes[2]; @@ -805,24 +944,32 @@ uint16_t AsyncMqttClient::unsubscribe(const char* topic) { return packetId; } -uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length, bool dup, uint16_t message_id) { - if (!_connected) return 0; +uint16_t AsyncMqttClient::publish(const char *topic, uint8_t qos, bool retain, const char *payload, size_t length, bool dup, uint16_t message_id) +{ + if (!_connected) + { + Serial.println("Not connected"); + return 0; + } char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.PUBLISH; fixedHeader[0] = fixedHeader[0] << 4; - if (dup) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP; - if (retain) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN; - switch (qos) { - case 0: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0; - break; - case 1: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1; - break; - case 2: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2; - break; + if (dup) + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP; + if (retain) + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN; + switch (qos) + { + case 0: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0; + break; + case 1: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1; + break; + case 2: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2; + break; } uint16_t topicLength = strlen(topic); @@ -831,28 +978,41 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c topicLengthBytes[1] = topicLength & 0xFF; uint32_t payloadLength = length; - if (payload != nullptr && payloadLength == 0) payloadLength = strlen(payload); + if (payload != nullptr && payloadLength == 0) + payloadLength = strlen(payload); uint32_t remainingLength = 2 + topicLength + payloadLength; - if (qos != 0) remainingLength += 2; + if (qos != 0) + remainingLength += 2; uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1); size_t neededSpace = 0; neededSpace += 1 + remainingLengthLength; neededSpace += 2; neededSpace += topicLength; - if (qos != 0) neededSpace += 2; - if (payload != nullptr) neededSpace += payloadLength; + if (qos != 0) + neededSpace += 2; + if (payload != nullptr) + neededSpace += payloadLength; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } + if (_client.space() < neededSpace) + { + SEMAPHORE_GIVE(); + Serial.println("Not enough space for request"); + return 0; + } uint16_t packetId = 0; char packetIdBytes[2]; - if (qos != 0) { - if (dup && message_id > 0) { + if (qos != 0) + { + if (dup && message_id > 0) + { packetId = message_id; - } else { + } + else + { packetId = _getNextPacketId(); } @@ -863,15 +1023,25 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c _client.add(fixedHeader, 1 + remainingLengthLength); _client.add(topicLengthBytes, 2); _client.add(topic, topicLength); - if (qos != 0) _client.add(packetIdBytes, 2); - if (payload != nullptr) _client.add(payload, payloadLength); + if (qos != 0) + _client.add(packetIdBytes, 2); + if (payload != nullptr) + _client.add(payload, payloadLength); _client.send(); _lastClientActivity = millis(); SEMAPHORE_GIVE(); - if (qos != 0) { + if (qos != 0) + { return packetId; - } else { + } + else + { return 1; } } + +void AsyncMqttClient::setConnected(bool connected) +{ + _connected = connected; +} \ No newline at end of file diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp index af8332b24e..4663621521 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp @@ -39,46 +39,52 @@ #include "AsyncMqttClient/Packets/PubCompPacket.hpp" #if ESP32 -#define SEMAPHORE_TAKE(X) if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) { return X; } // Waits max 1000ms +#define SEMAPHORE_TAKE(X) \ + if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) \ + { \ + return X; \ + } // Waits max 1000ms #define SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore); #elif defined(ESP8266) #define SEMAPHORE_TAKE(X) void() #define SEMAPHORE_GIVE() void() #endif -class AsyncMqttClient { - public: +class AsyncMqttClient +{ +public: AsyncMqttClient(); ~AsyncMqttClient(); - AsyncMqttClient& setKeepAlive(uint16_t keepAlive); - AsyncMqttClient& setClientId(const char* clientId); - AsyncMqttClient& setCleanSession(bool cleanSession); - AsyncMqttClient& setMaxTopicLength(uint16_t maxTopicLength); - AsyncMqttClient& setCredentials(const char* username, const char* password = nullptr); - AsyncMqttClient& setWill(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0); - AsyncMqttClient& setServer(IPAddress ip, uint16_t port); - AsyncMqttClient& setServer(const char* host, uint16_t port); + AsyncMqttClient &setKeepAlive(uint16_t keepAlive); + AsyncMqttClient &setClientId(const char *clientId); + AsyncMqttClient &setCleanSession(bool cleanSession); + AsyncMqttClient &setMaxTopicLength(uint16_t maxTopicLength); + AsyncMqttClient &setCredentials(const char *username, const char *password = nullptr); + AsyncMqttClient &setWill(const char *topic, uint8_t qos, bool retain, const char *payload = nullptr, size_t length = 0); + AsyncMqttClient &setServer(IPAddress ip, uint16_t port); + AsyncMqttClient &setServer(const char *host, uint16_t port); #if ASYNC_TCP_SSL_ENABLED - AsyncMqttClient& setSecure(bool secure); - AsyncMqttClient& addServerFingerprint(const uint8_t* fingerprint); + AsyncMqttClient &setSecure(bool secure); + AsyncMqttClient &addServerFingerprint(const uint8_t *fingerprint); #endif - AsyncMqttClient& onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback); - AsyncMqttClient& onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback); - AsyncMqttClient& onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback); - AsyncMqttClient& onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback); - AsyncMqttClient& onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback); - AsyncMqttClient& onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback); + AsyncMqttClient &onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback); + AsyncMqttClient &onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback); + AsyncMqttClient &onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback); + AsyncMqttClient &onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback); + AsyncMqttClient &onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback); + AsyncMqttClient &onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback); bool connected() const; void connect(); void disconnect(bool force = false); - uint16_t subscribe(const char* topic, uint8_t qos); - uint16_t unsubscribe(const char* topic); - uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); + uint16_t subscribe(const char *topic, uint8_t qos); + uint16_t unsubscribe(const char *topic); + uint16_t publish(const char *topic, uint8_t qos, bool retain, const char *payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); + void setConnected(bool connected); - private: +private: AsyncClient _client; bool _connected; @@ -89,9 +95,9 @@ class AsyncMqttClient { uint32_t _lastServerActivity; uint32_t _lastPingRequestTime; - char _generatedClientId[13 + 1]; // esp8266abc123 + char _generatedClientId[13 + 1]; // esp8266abc123 IPAddress _ip; - const char* _host; + const char *_host; bool _useIp; #if ASYNC_TCP_SSL_ENABLED bool _secure; @@ -99,11 +105,11 @@ class AsyncMqttClient { uint16_t _port; uint16_t _keepAlive; bool _cleanSession; - const char* _clientId; - const char* _username; - const char* _password; - const char* _willTopic; - const char* _willPayload; + const char *_clientId; + const char *_username; + const char *_password; + const char *_willTopic; + const char *_willPayload; uint16_t _willPayloadLength; uint8_t _willQos; bool _willRetain; @@ -120,7 +126,7 @@ class AsyncMqttClient { std::vector _onPublishUserCallbacks; AsyncMqttClientInternals::ParsingInformation _parsingInformation; - AsyncMqttClientInternals::Packet* _currentParsedPacket; + AsyncMqttClientInternals::Packet *_currentParsedPacket; uint8_t _remainingLengthBufferPosition; char _remainingLengthBuffer[4]; @@ -138,20 +144,20 @@ class AsyncMqttClient { void _freeCurrentParsedPacket(); // TCP - void _onConnect(AsyncClient* client); - void _onDisconnect(AsyncClient* client); - static void _onError(AsyncClient* client, int8_t error); - void _onTimeout(AsyncClient* client, uint32_t time); - static void _onAck(AsyncClient* client, size_t len, uint32_t time); - void _onData(AsyncClient* client, char* data, size_t len); - void _onPoll(AsyncClient* client); + void _onConnect(AsyncClient *client); + void _onDisconnect(AsyncClient *client); + static void _onError(AsyncClient *client, int8_t error); + void _onTimeout(AsyncClient *client, uint32_t time); + static void _onAck(AsyncClient *client, size_t len, uint32_t time); + void _onData(AsyncClient *client, char *data, size_t len); + void _onPoll(AsyncClient *client); // MQTT void _onPingResp(); void _onConnAck(bool sessionPresent, uint8_t connectReturnCode); void _onSubAck(uint16_t packetId, char status); void _onUnsubAck(uint16_t packetId); - void _onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId); + void _onMessage(char *topic, char *payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId); void _onPublish(uint16_t packetId, uint8_t qos); void _onPubRel(uint16_t packetId); void _onPubAck(uint16_t packetId); diff --git a/wled00/util.cpp b/wled00/util.cpp index 914f09ee35..e4774da2d8 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -2,48 +2,73 @@ #include "fcn_declare.h" #include "const.h" - -//helper to get int value at a position in string -int getNumVal(const String* req, uint16_t pos) +// helper to get int value at a position in string +int getNumVal(const String *req, uint16_t pos) { - return req->substring(pos+3).toInt(); + return req->substring(pos + 3).toInt(); } - -//helper to get int value with in/decrementing support via ~ syntax -void parseNumber(const char* str, byte* val, byte minv, byte maxv) +// helper to get int value with in/decrementing support via ~ syntax +void parseNumber(const char *str, byte *val, byte minv, byte maxv) { - if (str == nullptr || str[0] == '\0') return; - if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 + if (str == nullptr || str[0] == '\0') + return; + if (str[0] == 'r') + { + *val = random8(minv, maxv ? maxv : 255); + return; + } // maxv for random cannot be 0 bool wrap = false; - if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;} - if (str[0] == '~') { - int out = atoi(str +1); - if (out == 0) { - if (str[1] == '0') return; - if (str[1] == '-') { - *val = (int)(*val -1) < (int)minv ? maxv : min((int)maxv,(*val -1)); //-1, wrap around - } else { - *val = (int)(*val +1) > (int)maxv ? minv : max((int)minv,(*val +1)); //+1, wrap around + if (str[0] == 'w' && strlen(str) > 1) + { + str++; + wrap = true; + } + if (str[0] == '~') + { + int out = atoi(str + 1); + if (out == 0) + { + if (str[1] == '0') + return; + if (str[1] == '-') + { + *val = (int)(*val - 1) < (int)minv ? maxv : min((int)maxv, (*val - 1)); //-1, wrap around } - } else { - if (wrap && *val == maxv && out > 0) out = minv; - else if (wrap && *val == minv && out < 0) out = maxv; - else { + else + { + *val = (int)(*val + 1) > (int)maxv ? minv : max((int)minv, (*val + 1)); //+1, wrap around + } + } + else + { + if (wrap && *val == maxv && out > 0) + out = minv; + else if (wrap && *val == minv && out < 0) + out = maxv; + else + { out += *val; - if (out > maxv) out = maxv; - if (out < minv) out = minv; + if (out > maxv) + out = maxv; + if (out < minv) + out = minv; } *val = out; } return; - } else if (minv == maxv && minv == 0) { // limits "unset" i.e. both 0 + } + else if (minv == maxv && minv == 0) + { // limits "unset" i.e. both 0 byte p1 = atoi(str); - const char* str2 = strchr(str,'~'); // min/max range (for preset cycle, e.g. "1~5~") - if (str2) { - byte p2 = atoi(++str2); // skip ~ - if (p2 > 0) { - while (isdigit(*(++str2))); // skip digits + const char *str2 = strchr(str, '~'); // min/max range (for preset cycle, e.g. "1~5~") + if (str2) + { + byte p2 = atoi(++str2); // skip ~ + if (p2 > 0) + { + while (isdigit(*(++str2))) + ; // skip digits parseNumber(str2, val, p1, p2); return; } @@ -52,91 +77,96 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv) *val = atoi(str); } - -bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { - if (elem.is()) { - if (elem < 0) return false; //ignore e.g. {"ps":-1} +bool getVal(JsonVariant elem, byte *val, byte vmin, byte vmax) +{ + if (elem.is()) + { + if (elem < 0) + return false; // ignore e.g. {"ps":-1} *val = elem; return true; - } else if (elem.is()) { - const char* str = elem; + } + else if (elem.is()) + { + const char *str = elem; size_t len = strnlen(str, 12); - if (len == 0 || len > 10) return false; + if (len == 0 || len > 10) + return false; parseNumber(str, val, vmin, vmax); return true; } - return false; //key does not exist + return false; // key does not exist } - -bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv) +bool updateVal(const char *req, const char *key, byte *val, byte minv, byte maxv) { const char *v = strstr(req, key); - if (v) v += strlen(key); - else return false; + if (v) + v += strlen(key); + else + return false; parseNumber(v, val, minv, maxv); return true; } - -//append a numeric setting to string buffer -void sappend(char stype, const char* key, int val) +// append a numeric setting to string buffer +void sappend(char stype, const char *key, int val) { char ds[] = "d.Sf."; - switch(stype) + switch (stype) { - case 'c': //checkbox - oappend(ds); - oappend(key); - oappend(".checked="); - oappendi(val); - oappend(";"); - break; - case 'v': //numeric - oappend(ds); - oappend(key); - oappend(".value="); - oappendi(val); - oappend(";"); - break; - case 'i': //selectedIndex - oappend(ds); - oappend(key); - oappend(SET_F(".selectedIndex=")); - oappendi(val); - oappend(";"); - break; + case 'c': // checkbox + oappend(ds); + oappend(key); + oappend(".checked="); + oappendi(val); + oappend(";"); + break; + case 'v': // numeric + oappend(ds); + oappend(key); + oappend(".value="); + oappendi(val); + oappend(";"); + break; + case 'i': // selectedIndex + oappend(ds); + oappend(key); + oappend(SET_F(".selectedIndex=")); + oappendi(val); + oappend(";"); + break; } } - -//append a string setting to buffer -void sappends(char stype, const char* key, char* val) +// append a string setting to buffer +void sappends(char stype, const char *key, char *val) { - switch(stype) + switch (stype) { - case 's': {//string (we can interpret val as char*) - String buf = val; - //convert "%" to "%%" to make EspAsyncWebServer happy - //buf.replace("%","%%"); - oappend("d.Sf."); - oappend(key); - oappend(".value=\""); - oappend(buf.c_str()); - oappend("\";"); - break;} - case 'm': //message - oappend(SET_F("d.getElementsByClassName")); - oappend(key); - oappend(SET_F(".innerHTML=\"")); - oappend(val); - oappend("\";"); - break; + case 's': + { // string (we can interpret val as char*) + String buf = val; + // convert "%" to "%%" to make EspAsyncWebServer happy + // buf.replace("%","%%"); + oappend("d.Sf."); + oappend(key); + oappend(".value=\""); + oappend(buf.c_str()); + oappend("\";"); + break; + } + case 'm': // message + oappend(SET_F("d.getElementsByClassName")); + oappend(key); + oappend(SET_F(".innerHTML=\"")); + oappend(val); + oappend("\";"); + break; } } - bool oappendi(int i) { char s[11]; @@ -144,67 +174,77 @@ bool oappendi(int i) return oappend(s); } - -bool oappend(const char* txt) +bool oappend(const char *txt) { uint16_t len = strlen(txt); - if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks + if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) + { // sanity checks #ifdef WLED_DEBUG DEBUG_PRINT(F("oappend() buffer overflow. Cannot append ")); - DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\"")); - DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\"")); + DEBUG_PRINT(len); + DEBUG_PRINT(F(" bytes \t\"")); + DEBUG_PRINT(txt); + DEBUG_PRINTLN(F("\"")); #endif - return false; // buffer full + return false; // buffer full } strcpy(obuf + olen, txt); olen += len; return true; } - -void prepareHostname(char* hostname) +void prepareHostname(char *hostname) { sprintf_P(hostname, "wled-%*s", 6, escapedMac.c_str() + 6); const char *pC = serverDescription; - uint8_t pos = 5; // keep "wled-" - while (*pC && pos < 24) { // while !null and not over length - if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname + uint8_t pos = 5; // keep "wled-" + while (*pC && pos < 24) + { // while !null and not over length + if (isalnum(*pC)) + { // if the current char is alpha-numeric append it to the hostname hostname[pos] = *pC; pos++; - } else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') { + } + else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') + { hostname[pos] = '-'; pos++; } // else do nothing - no leading hyphens and do not include hyphens for all other characters. pC++; } - //last character must not be hyphen - if (pos > 5) { - while (pos > 4 && hostname[pos -1] == '-') pos--; + // last character must not be hyphen + if (pos > 5) + { + while (pos > 4 && hostname[pos - 1] == '-') + pos--; hostname[pos] = '\0'; // terminate string (leave at least "wled") } } - -bool isAsterisksOnly(const char* str, byte maxLen) +bool isAsterisksOnly(const char *str, byte maxLen) { - for (byte i = 0; i < maxLen; i++) { - if (str[i] == 0) break; - if (str[i] != '*') return false; + for (byte i = 0; i < maxLen; i++) + { + if (str[i] == 0) + break; + if (str[i] != '*') + return false; } - //at this point the password contains asterisks only - return (str[0] != 0); //false on empty string + // at this point the password contains asterisks only + return (str[0] != 0); // false on empty string } - -//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 +// threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 bool requestJSONBufferLock(uint8_t module) { unsigned long now = millis(); - while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock + while (jsonBufferLock && millis() - now < 1000) + delay(1); // wait for a second for buffer lock - if (millis()-now >= 1000) { + if (millis() - now >= 1000) + { DEBUG_PRINT(F("ERROR: Locking JSON buffer failed! (")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); @@ -215,12 +255,11 @@ bool requestJSONBufferLock(uint8_t module) DEBUG_PRINT(F("JSON buffer locked. (")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); - fileDoc = &doc; // used for applying presets (presets.cpp) + fileDoc = &doc; // used for applying presets (presets.cpp) doc.clear(); return true; } - void releaseJSONBufferLock() { DEBUG_PRINT(F("JSON buffer released. (")); @@ -230,31 +269,70 @@ void releaseJSONBufferLock() jsonBufferLock = 0; } +// the same functions but for my new response buffers +bool requestResponseBufferLock(uint8_t module) +{ + unsigned long now = millis(); + + while (responseBufferLock && millis() - now < 1000) + delay(1); // wait for a second for buffer lock + + if (millis() - now >= 1000) + { + DEBUG_PRINT(F("ERROR: Locking response buffer failed! (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + return false; // waiting time-outed + } + + responseBufferLock = module ? module : 255; + DEBUG_PRINT(F("Response buffer locked. (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + mqttResponseDoc.clear(); // Clear the JSON document + memset(mqttResponseBuffer, 0, JSON_BUFFER_SIZE); // Clear the buffer + return true; +} + +void releaseResponseBufferLock() +{ + DEBUG_PRINT(F("Response buffer released. (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + responseBufferLock = 0; +} // extracts effect mode (or palette) name from names serialized string // caller must provide large enough buffer for name (including SR extensions)! uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen) { - if (src == JSON_mode_names || src == nullptr) { - if (mode < strip.getModeCount()) { + if (src == JSON_mode_names || src == nullptr) + { + if (mode < strip.getModeCount()) + { char lineBuffer[256]; - //strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); - strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1); - lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string + // strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); + strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer) / sizeof(char) - 1); + lineBuffer[sizeof(lineBuffer) / sizeof(char) - 1] = '\0'; // terminate string size_t len = strlen(lineBuffer); size_t j = 0; - for (; j < maxLen && j < len; j++) { - if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break; + for (; j < maxLen && j < len; j++) + { + if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') + break; dest[j] = lineBuffer[j]; } dest[j] = 0; // terminate string return strlen(dest); - } else return 0; + } + else + return 0; } - if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) { - snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode); - dest[maxLen-1] = '\0'; + if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) + { + snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255 - mode); + dest[maxLen - 1] = '\0'; return strlen(dest); } @@ -265,95 +343,144 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe size_t len = strlen_P(src); // Find the mode name in JSON - for (size_t i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) + { singleJsonSymbol = pgm_read_byte_near(src + i); - if (singleJsonSymbol == '\0') break; - if (singleJsonSymbol == '@' && insideQuotes && qComma == mode) break; //stop when SR extension encountered - switch (singleJsonSymbol) { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': + if (singleJsonSymbol == '\0') + break; + if (singleJsonSymbol == '@' && insideQuotes && qComma == mode) + break; // stop when SR extension encountered + switch (singleJsonSymbol) + { + case '"': + insideQuotes = !insideQuotes; + break; + case '[': + case ']': + break; + case ',': + if (!insideQuotes) + qComma++; + default: + if (!insideQuotes || (qComma != mode)) break; - case ',': - if (!insideQuotes) qComma++; - default: - if (!insideQuotes || (qComma != mode)) break; - dest[printedChars++] = singleJsonSymbol; + dest[printedChars++] = singleJsonSymbol; } - if ((qComma > mode) || (printedChars >= maxLen)) break; + if ((qComma > mode) || (printedChars >= maxLen)) + break; } dest[printedChars] = '\0'; return strlen(dest); } - // extracts effect slider data (1st group after @) uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var) { dest[0] = '\0'; // start by clearing buffer - if (mode < strip.getModeCount()) { + if (mode < strip.getModeCount()) + { String lineBuffer = FPSTR(strip.getModeData(mode)); - if (lineBuffer.length() > 0) { + if (lineBuffer.length() > 0) + { int16_t start = lineBuffer.indexOf('@'); - int16_t stop = lineBuffer.indexOf(';', start); - if (start>0 && stop>0) { + int16_t stop = lineBuffer.indexOf(';', start); + if (start > 0 && stop > 0) + { String names = lineBuffer.substring(start, stop); // include @ int16_t nameBegin = 1, nameEnd, nameDefault; - if (slider < 10) { - for (size_t i=0; i<=slider; i++) { + if (slider < 10) + { + for (size_t i = 0; i <= slider; i++) + { const char *tmpstr; - dest[0] = '\0'; //clear dest buffer - if (nameBegin == 0) break; // there are no more names + dest[0] = '\0'; // clear dest buffer + if (nameBegin == 0) + break; // there are no more names nameEnd = names.indexOf(',', nameBegin); - if (i == slider) { + if (i == slider) + { nameDefault = names.indexOf('=', nameBegin); // find default value - if (nameDefault > 0 && var && ((nameEnd>0 && nameDefault 0 && var && ((nameEnd > 0 && nameDefault < nameEnd) || nameEnd < 0)) + { + *var = (uint8_t)atoi(names.substring(nameDefault + 1).c_str()); } - if (names.charAt(nameBegin) == '!') { - switch (slider) { - case 0: tmpstr = PSTR("FX Speed"); break; - case 1: tmpstr = PSTR("FX Intensity"); break; - case 2: tmpstr = PSTR("FX Custom 1"); break; - case 3: tmpstr = PSTR("FX Custom 2"); break; - case 4: tmpstr = PSTR("FX Custom 3"); break; - default: tmpstr = PSTR("FX Custom"); break; + if (names.charAt(nameBegin) == '!') + { + switch (slider) + { + case 0: + tmpstr = PSTR("FX Speed"); + break; + case 1: + tmpstr = PSTR("FX Intensity"); + break; + case 2: + tmpstr = PSTR("FX Custom 1"); + break; + case 3: + tmpstr = PSTR("FX Custom 2"); + break; + case 4: + tmpstr = PSTR("FX Custom 3"); + break; + default: + tmpstr = PSTR("FX Custom"); + break; } strncpy_P(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous) - dest[maxLen-1] = '\0'; - } else { - if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name? - else tmpstr = names.substring(nameBegin, nameEnd).c_str(); + dest[maxLen - 1] = '\0'; + } + else + { + if (nameEnd < 0) + tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name? + else + tmpstr = names.substring(nameBegin, nameEnd).c_str(); strlcpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous) } } - nameBegin = nameEnd+1; // next name (if "," is not found it will be 0) + nameBegin = nameEnd + 1; // next name (if "," is not found it will be 0) } // next slider - } else if (slider == 255) { + } + else if (slider == 255) + { // palette strlcpy(dest, "pal", maxLen); - names = lineBuffer.substring(stop+1); // stop has index of color slot names - nameBegin = names.indexOf(';'); // look for palette - if (nameBegin >= 0) { - nameEnd = names.indexOf(';', nameBegin+1); - if (!isdigit(names[nameBegin+1])) nameBegin = names.indexOf('=', nameBegin+1); // look for default value - if (nameEnd >= 0 && nameBegin > nameEnd) nameBegin = -1; - if (nameBegin >= 0 && var) { - *var = (uint8_t)atoi(names.substring(nameBegin+1).c_str()); + names = lineBuffer.substring(stop + 1); // stop has index of color slot names + nameBegin = names.indexOf(';'); // look for palette + if (nameBegin >= 0) + { + nameEnd = names.indexOf(';', nameBegin + 1); + if (!isdigit(names[nameBegin + 1])) + nameBegin = names.indexOf('=', nameBegin + 1); // look for default value + if (nameEnd >= 0 && nameBegin > nameEnd) + nameBegin = -1; + if (nameBegin >= 0 && var) + { + *var = (uint8_t)atoi(names.substring(nameBegin + 1).c_str()); } } } // we have slider name (including default value) in the dest buffer - for (size_t i=0; i(); - if (name != nullptr) len = strlen(name); - if (len > 0 && len < 33) { - ledmapNames[i-1] = new char[len+1]; - if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33); + const char *name = doc["n"].as(); + if (name != nullptr) + len = strlen(name); + if (len > 0 && len < 33) + { + ledmapNames[i - 1] = new char[len + 1]; + if (ledmapNames[i - 1]) + strlcpy(ledmapNames[i - 1], name, 33); } } - if (!ledmapNames[i-1]) { + if (!ledmapNames[i - 1]) + { char tmp[33]; snprintf_P(tmp, 32, PSTR("ledmap%d.json"), i); len = strlen(tmp); - ledmapNames[i-1] = new char[len+1]; - if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33); + ledmapNames[i - 1] = new char[len + 1]; + if (ledmapNames[i - 1]) + strlcpy(ledmapNames[i - 1], tmp, 33); } } releaseJSONBufferLock(); } - #endif +#endif } - } } /* * Returns a new, random color wheel index with a minimum distance of 42 from pos. */ -uint8_t get_random_wheel_index(uint8_t pos) { +uint8_t get_random_wheel_index(uint8_t pos) +{ uint8_t r = 0, x = 0, y = 0, d = 0; - while (d < 42) { + while (d < 42) + { r = random8(); x = abs(pos - r); y = 255 - x; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 8ba6b1a565..2dd6830209 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -1,4 +1,4 @@ -#define WLED_DEFINE_GLOBAL_VARS //only in one source file, wled.cpp! +#define WLED_DEFINE_GLOBAL_VARS // only in one source file, wled.cpp! #include "wled.h" #include "wled_ethernet.h" #include @@ -20,12 +20,13 @@ WLED::WLED() void WLED::reset() { briT = 0; - #ifdef WLED_ENABLE_WEBSOCKETS +#ifdef WLED_ENABLE_WEBSOCKETS ws.closeAll(1012); - #endif +#endif unsigned long dly = millis(); - while (millis() - dly < 450) { - yield(); // enough time to send response to client + while (millis() - dly < 450) + { + yield(); // enough time to send response to client } applyBri(); DEBUG_PRINTLN(F("WLED RESET")); @@ -34,29 +35,36 @@ void WLED::reset() void WLED::loop() { - #ifdef WLED_DEBUG + if (otaInProgress) + { + // stop the loop while ota in progress + return; + } +#ifdef WLED_DEBUG static unsigned long lastRun = 0; - unsigned long loopMillis = millis(); - size_t loopDelay = loopMillis - lastRun; - if (lastRun == 0) loopDelay=0; // startup - don't have valid data from last run. - if (loopDelay > 2) DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay); + unsigned long loopMillis = millis(); + size_t loopDelay = loopMillis - lastRun; + if (lastRun == 0) + loopDelay = 0; // startup - don't have valid data from last run. + if (loopDelay > 2) + DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay); static unsigned long maxLoopMillis = 0; - static size_t avgLoopMillis = 0; + static size_t avgLoopMillis = 0; static unsigned long maxUsermodMillis = 0; - static size_t avgUsermodMillis = 0; + static size_t avgUsermodMillis = 0; static unsigned long maxStripMillis = 0; - static size_t avgStripMillis = 0; - unsigned long stripMillis; - #endif + static size_t avgStripMillis = 0; + unsigned long stripMillis; +#endif handleTime(); - #ifndef WLED_DISABLE_INFRARED - handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too - #endif +#ifndef WLED_DISABLE_INFRARED + handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too +#endif handleConnection(); - #ifndef WLED_DISABLE_ESPNOW +#ifndef WLED_DISABLE_ESPNOW handleRemote(); - #endif +#endif handleSerial(); handleImprovWifiScan(); handleNotifications(); @@ -66,126 +74,146 @@ void WLED::loop() #endif userLoop(); - #ifdef WLED_DEBUG +#ifdef WLED_DEBUG unsigned long usermodMillis = millis(); - #endif +#endif usermods.loop(); - #ifdef WLED_DEBUG +#ifdef WLED_DEBUG usermodMillis = millis() - usermodMillis; avgUsermodMillis += usermodMillis; - if (usermodMillis > maxUsermodMillis) maxUsermodMillis = usermodMillis; - #endif + if (usermodMillis > maxUsermodMillis) + maxUsermodMillis = usermodMillis; +#endif yield(); handleIO(); - #ifndef WLED_DISABLE_INFRARED +#ifndef WLED_DISABLE_INFRARED handleIR(); - #endif - #ifndef WLED_DISABLE_ALEXA +#endif +#ifndef WLED_DISABLE_ALEXA handleAlexa(); - #endif +#endif - if (doCloseFile) { + if (doCloseFile) + { closeFile(); yield(); } - #ifdef WLED_DEBUG +#ifdef WLED_DEBUG stripMillis = millis(); - #endif - if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled +#endif + if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled { - if (apActive) dnsServer.processNextRequest(); - #ifndef WLED_DISABLE_OTA - if (WLED_CONNECTED && aOtaEnabled && !otaLock && correctPIN) ArduinoOTA.handle(); - #endif + if (apActive) + dnsServer.processNextRequest(); +#ifndef WLED_DISABLE_OTA + if (WLED_CONNECTED && aOtaEnabled && !otaLock && correctPIN) + ArduinoOTA.handle(); +#endif handleNightlight(); handlePlaylist(); yield(); - #ifndef WLED_DISABLE_HUESYNC +#ifndef WLED_DISABLE_HUESYNC handleHue(); yield(); - #endif +#endif handlePresets(); yield(); if (!offMode || strip.isOffRefreshRequired()) strip.service(); - #ifdef ESP8266 +#ifdef ESP8266 else if (!noWifiSleep) - delay(1); //required to make sure ESP enters modem sleep (see #1184) - #endif + delay(1); // required to make sure ESP enters modem sleep (see #1184) +#endif } - #ifdef WLED_DEBUG +#ifdef WLED_DEBUG stripMillis = millis() - stripMillis; avgStripMillis += stripMillis; - if (stripMillis > maxStripMillis) maxStripMillis = stripMillis; - #endif + if (stripMillis > maxStripMillis) + maxStripMillis = stripMillis; +#endif yield(); #ifdef ESP8266 MDNS.update(); #endif - //millis() rolls over every 50 days - if (lastMqttReconnectAttempt > millis()) { + // millis() rolls over every 50 days + if (lastMqttReconnectAttempt > millis()) + { rolloverMillis++; lastMqttReconnectAttempt = 0; - ntpLastSyncTime = NTP_NEVER; // force new NTP query + ntpLastSyncTime = NTP_NEVER; // force new NTP query strip.restartRuntime(); } - if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast + if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) + { // lastMqttReconnectAttempt==0 forces immediate broadcast lastMqttReconnectAttempt = millis(); - #ifndef WLED_DISABLE_MQTT +#ifndef WLED_DISABLE_MQTT initMqtt(); - #endif +#endif yield(); // refresh WLED nodes list refreshNodeList(); - if (nodeBroadcastEnabled) sendSysInfoUDP(); + if (nodeBroadcastEnabled) + sendSysInfoUDP(); yield(); } // 15min PIN time-out - if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) { + if (strlen(settingsPIN) > 0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) + { correctPIN = false; createEditHandler(false); } - //LED settings have been saved, re-init busses - //This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate! - if (doInitBusses) { + // LED settings have been saved, re-init busses + // This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate! + if (doInitBusses) + { doInitBusses = false; DEBUG_PRINTLN(F("Re-init busses.")); - bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) + bool aligned = strip.checkSegmentAlignment(); // see if old segments match old bus(ses) busses.removeAll(); uint32_t mem = 0, globalBufMem = 0; uint16_t maxlen = 0; - for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { - if (busConfigs[i] == nullptr) break; + for (uint8_t i = 0; i < WLED_MAX_BUSSES + WLED_MIN_VIRTUAL_BUSSES; i++) + { + if (busConfigs[i] == nullptr) + break; mem += BusManager::memUsage(*busConfigs[i]); - if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) { - maxlen = busConfigs[i]->start + busConfigs[i]->count; - globalBufMem = maxlen * 4; + if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) + { + maxlen = busConfigs[i]->start + busConfigs[i]->count; + globalBufMem = maxlen * 4; } - if (mem + globalBufMem <= MAX_LED_MEMORY) { + if (mem + globalBufMem <= MAX_LED_MEMORY) + { busses.add(*busConfigs[i]); } - delete busConfigs[i]; busConfigs[i] = nullptr; + delete busConfigs[i]; + busConfigs[i] = nullptr; } strip.finalizeInit(); // also loads default ledmap if present - if (aligned) strip.makeAutoSegments(); - else strip.fixInvalidSegments(); + if (aligned) + strip.makeAutoSegments(); + else + strip.fixInvalidSegments(); doSerializeConfig = true; } - if (loadLedmap >= 0) { - if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix(); + if (loadLedmap >= 0) + { + if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) + strip.setUpMatrix(); loadLedmap = -1; } yield(); - if (doSerializeConfig) serializeConfig(); + if (doSerializeConfig) + serializeConfig(); yield(); handleWs(); @@ -196,12 +224,13 @@ void WLED::loop() #if WLED_WATCHDOG_TIMEOUT > 0 // we finished our mainloop, reset the watchdog timer static unsigned long lastWDTFeed = 0; - if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT*500)) { - #ifdef ARDUINO_ARCH_ESP32 + if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT * 500)) + { +#ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_reset(); - #else +#else ESP.wdtFeed(); - #endif +#endif lastWDTFeed = millis(); } #endif @@ -212,38 +241,65 @@ void WLED::loop() // DEBUG serial logging (every 30s) #ifdef WLED_DEBUG loopMillis = millis() - loopMillis; - if (loopMillis > 30) { + if (loopMillis > 30) + { DEBUG_PRINTF("Loop took %lums.\n", loopMillis); DEBUG_PRINTF("Usermods took %lums.\n", usermodMillis); DEBUG_PRINTF("Strip took %lums.\n", stripMillis); } avgLoopMillis += loopMillis; - if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis; - if (millis() - debugTime > 29999) { + if (loopMillis > maxLoopMillis) + maxLoopMillis = loopMillis; + if (millis() - debugTime > 29999) + { DEBUG_PRINTLN(F("---DEBUG INFO---")); - DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis()); - DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime()); - DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); - #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) - if (psramFound()) { - DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); - DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Runtime: ")); + DEBUG_PRINTLN(millis()); + DEBUG_PRINT(F("Unix time: ")); + toki.printTime(toki.getTime()); + DEBUG_PRINT(F("Free heap: ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); +#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) + if (psramFound()) + { + DEBUG_PRINT(F("Total PSRAM: ")); + DEBUG_PRINT(ESP.getPsramSize() / 1024); + DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Free PSRAM: ")); + DEBUG_PRINT(ESP.getFreePsram() / 1024); + DEBUG_PRINTLN("kB"); } - #endif - DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status()); +#endif + DEBUG_PRINT(F("Wifi state: ")); + DEBUG_PRINTLN(WiFi.status()); - if (WiFi.status() != lastWifiState) { + if (WiFi.status() != lastWifiState) + { wifiStateChangedTime = millis(); } lastWifiState = WiFi.status(); - DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime); - DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime); - DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP()); - if (loops > 0) { // avoid division by zero - DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30); - DEBUG_PRINT(F("Loop time[ms]: ")); DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis); - DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis); - DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis); + DEBUG_PRINT(F("State time: ")); + DEBUG_PRINTLN(wifiStateChangedTime); + DEBUG_PRINT(F("NTP last sync: ")); + DEBUG_PRINTLN(ntpLastSyncTime); + DEBUG_PRINT(F("Client IP: ")); + DEBUG_PRINTLN(Network.localIP()); + if (loops > 0) + { // avoid division by zero + DEBUG_PRINT(F("Loops/sec: ")); + DEBUG_PRINTLN(loops / 30); + DEBUG_PRINT(F("Loop time[ms]: ")); + DEBUG_PRINT(avgLoopMillis / loops); + DEBUG_PRINT("/"); + DEBUG_PRINTLN(maxLoopMillis); + DEBUG_PRINT(F("UM time[ms]: ")); + DEBUG_PRINT(avgUsermodMillis / loops); + DEBUG_PRINT("/"); + DEBUG_PRINTLN(maxUsermodMillis); + DEBUG_PRINT(F("Strip time[ms]: ")); + DEBUG_PRINT(avgStripMillis / loops); + DEBUG_PRINT("/"); + DEBUG_PRINTLN(maxStripMillis); } strip.printSize(); loops = 0; @@ -256,17 +312,21 @@ void WLED::loop() } loops++; lastRun = millis(); -#endif // WLED_DEBUG +#endif // WLED_DEBUG } -void WLED::enableWatchdog() { +void WLED::enableWatchdog() +{ #if WLED_WATCHDOG_TIMEOUT > 0 #ifdef ARDUINO_ARCH_ESP32 esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true); DEBUG_PRINT(F("Watchdog enabled: ")); - if (watchdog == ESP_OK) { + if (watchdog == ESP_OK) + { DEBUG_PRINTLN(F("OK")); - } else { + } + else + { DEBUG_PRINTLN(watchdog); return; } @@ -277,9 +337,10 @@ void WLED::enableWatchdog() { #endif } -void WLED::disableWatchdog() { +void WLED::disableWatchdog() +{ #if WLED_WATCHDOG_TIMEOUT > 0 -DEBUG_PRINTLN(F("Watchdog: disabled")); + DEBUG_PRINTLN(F("Watchdog: disabled")); #ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_delete(NULL); #else @@ -290,24 +351,25 @@ DEBUG_PRINTLN(F("Watchdog: disabled")); void WLED::setup() { - #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detection - #endif +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detection +#endif - #ifdef ARDUINO_ARCH_ESP32 - pinMode(hardwareRX, INPUT_PULLDOWN); delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 - #endif +#ifdef ARDUINO_ARCH_ESP32 + pinMode(hardwareRX, INPUT_PULLDOWN); + delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 +#endif Serial.begin(115200); - #if !ARDUINO_USB_CDC_ON_BOOT - Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC) - #else - #endif - #if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT) - delay(2500); // allow CDC USB serial to initialise - #endif - #if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT +#if !ARDUINO_USB_CDC_ON_BOOT + Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC) +#else +#endif +#if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT) + delay(2500); // allow CDC USB serial to initialise +#endif +#if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC - #endif +#endif DEBUG_PRINTLN(); DEBUG_PRINT(F("---WLED ")); DEBUG_PRINT(versionString); @@ -317,86 +379,114 @@ void WLED::setup() #ifdef ARDUINO_ARCH_ESP32 DEBUG_PRINT(F("esp32 ")); DEBUG_PRINTLN(ESP.getSdkVersion()); - #if defined(ESP_ARDUINO_VERSION) - //DEBUG_PRINTF(F("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION); - DEBUG_PRINTF("arduino-esp32 v%d.%d.%d\n", int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0 - #else - DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. - #endif - - DEBUG_PRINT(F("CPU: ")); DEBUG_PRINT(ESP.getChipModel()); - DEBUG_PRINT(F(" rev.")); DEBUG_PRINT(ESP.getChipRevision()); - DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getChipCores()); DEBUG_PRINT(F(" core(s)")); - DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINTLN(F("MHz.")); - DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); - DEBUG_PRINT(F("MB, Mode ")); DEBUG_PRINT(ESP.getFlashChipMode()); - #ifdef WLED_DEBUG - switch (ESP.getFlashChipMode()) { - // missing: Octal modes - case FM_QIO: DEBUG_PRINT(F(" (QIO)")); break; - case FM_QOUT: DEBUG_PRINT(F(" (QOUT)"));break; - case FM_DIO: DEBUG_PRINT(F(" (DIO)")); break; - case FM_DOUT: DEBUG_PRINT(F(" (DOUT)"));break; - default: break; - } - #endif - DEBUG_PRINT(F(", speed ")); DEBUG_PRINT(ESP.getFlashChipSpeed()/1000000);DEBUG_PRINTLN(F("MHz.")); +#if defined(ESP_ARDUINO_VERSION) + // DEBUG_PRINTF(F("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION); + DEBUG_PRINTF("arduino-esp32 v%d.%d.%d\n", int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0 +#else + DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. +#endif + + DEBUG_PRINT(F("CPU: ")); + DEBUG_PRINT(ESP.getChipModel()); + DEBUG_PRINT(F(" rev.")); + DEBUG_PRINT(ESP.getChipRevision()); + DEBUG_PRINT(F(", ")); + DEBUG_PRINT(ESP.getChipCores()); + DEBUG_PRINT(F(" core(s)")); + DEBUG_PRINT(F(", ")); + DEBUG_PRINT(ESP.getCpuFreqMHz()); + DEBUG_PRINTLN(F("MHz.")); + DEBUG_PRINT(F("FLASH: ")); + DEBUG_PRINT((ESP.getFlashChipSize() / 1024) / 1024); + DEBUG_PRINT(F("MB, Mode ")); + DEBUG_PRINT(ESP.getFlashChipMode()); +#ifdef WLED_DEBUG + switch (ESP.getFlashChipMode()) + { + // missing: Octal modes + case FM_QIO: + DEBUG_PRINT(F(" (QIO)")); + break; + case FM_QOUT: + DEBUG_PRINT(F(" (QOUT)")); + break; + case FM_DIO: + DEBUG_PRINT(F(" (DIO)")); + break; + case FM_DOUT: + DEBUG_PRINT(F(" (DOUT)")); + break; + default: + break; + } +#endif + DEBUG_PRINT(F(", speed ")); + DEBUG_PRINT(ESP.getFlashChipSpeed() / 1000000); + DEBUG_PRINTLN(F("MHz.")); #else DEBUG_PRINT(F("esp8266 ")); DEBUG_PRINTLN(ESP.getCoreVersion()); #endif - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) - #if defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(CONFIG_IDF_TARGET_ESP32S3) // S3: reserve GPIO 33-37 for "octal" PSRAM - managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} }; - pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); - #elif defined(CONFIG_IDF_TARGET_ESP32S2) + managed_pin_type pins[] = {{33, true}, {34, true}, {35, true}, {36, true}, {37, true}}; + pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); +#elif defined(CONFIG_IDF_TARGET_ESP32S2) // S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation) - managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} }; - pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); - #elif defined(CONFIG_IDF_TARGET_ESP32C3) + managed_pin_type pins[] = {{26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true}}; + pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); +#elif defined(CONFIG_IDF_TARGET_ESP32C3) // C3: reserve GPIO 12-17 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation) - managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} }; - pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); - #else + managed_pin_type pins[] = {{12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true}}; + pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); +#else // GPIO16/GPIO17 reserved for SPI RAM - managed_pin_type pins[] = { {16, true}, {17, true} }; - pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); - #endif - #if defined(WLED_USE_PSRAM) - if (psramFound()) { - DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); - DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); - } - #else - DEBUG_PRINTLN(F("PSRAM not used.")); - #endif + managed_pin_type pins[] = {{16, true}, {17, true}}; + pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); +#endif +#if defined(WLED_USE_PSRAM) + if (psramFound()) + { + DEBUG_PRINT(F("Total PSRAM: ")); + DEBUG_PRINT(ESP.getPsramSize() / 1024); + DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Free PSRAM : ")); + DEBUG_PRINT(ESP.getFreePsram() / 1024); + DEBUG_PRINTLN("kB"); + } +#else + DEBUG_PRINTLN(F("PSRAM not used.")); +#endif #endif #if defined(ARDUINO_ESP32_PICO) -// special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM) -managed_pin_type pins[] = { {16, true}, {17, true} }; -pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); + // special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM) + managed_pin_type pins[] = {{16, true}, {17, true}}; + pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); #endif - //DEBUG_PRINT(F("LEDs inited. heap usage ~")); - //DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); + // DEBUG_PRINT(F("LEDs inited. heap usage ~")); + // DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); #ifdef WLED_DEBUG pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif -#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin +#ifdef WLED_ENABLE_DMX // reserve GPIO2 as hardcoded DMX pin pinManager.allocatePin(2, true, PinOwner::DMX); #endif DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); - for (uint8_t i=1; i=0 - if (!pinManager.isPinAllocated(STATUSLED)) { +#if defined(STATUSLED) && STATUSLED >= 0 + if (!pinManager.isPinAllocated(STATUSLED)) + { // NOTE: Special case: The status LED should *NOT* be allocated. // See comments in handleStatusLed(). pinMode(STATUSLED, OUTPUT); @@ -436,52 +529,62 @@ pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), Pin DEBUG_PRINTLN(F("Initializing strip")); beginStrip(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINTLN(F("Usermods setup")); userSetup(); usermods.setup(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) showWelcomePage = true; WiFi.persistent(false); - #ifdef WLED_USE_ETHERNET +#ifdef WLED_USE_ETHERNET WiFi.onEvent(WiFiEvent); - #endif +#endif - #ifdef WLED_ENABLE_ADALIGHT - //Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused - //Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused - if (!pinManager.isPinAllocated(hardwareRX) && !pinManager.isPinAllocated(hardwareTX)) { +#ifdef WLED_ENABLE_ADALIGHT + // Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused + // Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused + if (!pinManager.isPinAllocated(hardwareRX) && !pinManager.isPinAllocated(hardwareTX)) + { Serial.println(F("Ada")); } - #endif +#endif // fill in unique mdns default - if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); + if (strcmp(cmDNS, "x") == 0) + sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); #ifndef WLED_DISABLE_MQTT - if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6); - if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6); + if (mqttDeviceTopic[0] == 0) + sprintf_P(mqttDeviceTopic, PSTR("lights/%*s"), 6, escapedMac.c_str() + 6); + if (mqttClientID[0] == 0) + sprintf_P(mqttClientID, PSTR("LIGHTS-%*s"), 6, escapedMac.c_str() + 6); + if (mqttResponseTopic[0] == 0) + snprintf_P(mqttResponseTopic, 36, PSTR("%s/r"), mqttDeviceTopic); #endif #ifdef WLED_ENABLE_ADALIGHT - if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); + if (Serial.available() > 0 && Serial.peek() == 'I') + handleImprovPacket(); #endif #ifndef WLED_DISABLE_OTA - if (aOtaEnabled) { - ArduinoOTA.onStart([]() { + if (aOtaEnabled) + { + ArduinoOTA.onStart([]() + { #ifdef ESP8266 wifi_set_sleep_type(NONE_SLEEP_T); #endif WLED::instance().disableWatchdog(); - DEBUG_PRINTLN(F("Start ArduinoOTA")); - }); - ArduinoOTA.onError([](ota_error_t error) { + DEBUG_PRINTLN(F("Start ArduinoOTA")); }); + ArduinoOTA.onError([](ota_error_t error) + { // reenable watchdog on failed update - WLED::instance().enableWatchdog(); - }); + WLED::instance().enableWatchdog(); }); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); } @@ -491,19 +594,21 @@ pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), Pin #endif #ifdef WLED_ENABLE_ADALIGHT - if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); + if (Serial.available() > 0 && Serial.peek() == 'I') + handleImprovPacket(); #endif // HTTP server page init DEBUG_PRINTLN(F("initServer")); initServer(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); enableWatchdog(); - #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector - #endif +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); // enable brownout detector +#endif } void WLED::beginStrip() @@ -514,22 +619,29 @@ void WLED::beginStrip() strip.setBrightness(0); strip.setShowCallback(handleOverlayDraw); - if (turnOnAtBoot) { - if (briS > 0) bri = briS; - else if (bri == 0) bri = 128; - } else { + if (turnOnAtBoot) + { + if (briS > 0) + bri = briS; + else if (bri == 0) + bri = 128; + } + else + { // fix for #3196 - briLast = briS; bri = 0; + briLast = briS; + bri = 0; strip.fill(BLACK); strip.show(); } - if (bootPreset > 0) { + if (bootPreset > 0) + { applyPreset(bootPreset, CALL_MODE_INIT); } colorUpdated(CALL_MODE_INIT); // init relay pin - if (rlyPin>=0) + if (rlyPin >= 0) digitalWrite(rlyPin, (rlyMde ? bri : !bri)); } @@ -538,7 +650,8 @@ void WLED::initAP(bool resetAP) if (apBehavior == AP_BEHAVIOR_BUTTON_ONLY && !resetAP) return; - if (resetAP) { + if (resetAP) + { WLED_SET_AP_SSID(); strcpy_P(apPass, PSTR(WLED_AP_PASS)); } @@ -546,21 +659,24 @@ void WLED::initAP(bool resetAP) DEBUG_PRINTLN(apSSID); WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0)); WiFi.softAP(apSSID, apPass, apChannel, apHide); - #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) +#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WiFi.setTxPower(WIFI_POWER_8_5dBm); - #endif +#endif if (!apActive) // start captive portal if AP active { DEBUG_PRINTLN(F("Init AP interfaces")); server.begin(); - if (udpPort > 0 && udpPort != ntpLocalPort) { + if (udpPort > 0 && udpPort != ntpLocalPort) + { udpConnected = notifierUdp.begin(udpPort); } - if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) { + if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) + { udpRgbConnected = rgbUdp.begin(udpRgbPort); } - if (udpPort2 > 0 && udpPort2 != ntpLocalPort && udpPort2 != udpPort && udpPort2 != udpRgbPort) { + if (udpPort2 > 0 && udpPort2 != ntpLocalPort && udpPort2 != udpPort && udpPort2 != udpRgbPort) + { udp2Connected = notifier2Udp.begin(udpPort2); } e131.begin(false, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT); @@ -578,89 +694,106 @@ bool WLED::initEthernet() static bool successfullyConfiguredEthernet = false; - if (successfullyConfiguredEthernet) { + if (successfullyConfiguredEthernet) + { // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); return false; } - if (ethernetType == WLED_ETH_NONE) { + if (ethernetType == WLED_ETH_NONE) + { return false; } - if (ethernetType >= WLED_NUM_ETH_TYPES) { - DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); DEBUG_PRINTLN(ethernetType); + if (ethernetType >= WLED_NUM_ETH_TYPES) + { + DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); + DEBUG_PRINTLN(ethernetType); return false; } - DEBUG_PRINT(F("initE: Attempting ETH config: ")); DEBUG_PRINTLN(ethernetType); + DEBUG_PRINT(F("initE: Attempting ETH config: ")); + DEBUG_PRINTLN(ethernetType); // Ethernet initialization should only succeed once -- else reboot required ethernet_settings es = ethernetBoards[ethernetType]; managed_pin_type pinsToAllocate[10] = { - // first six pins are non-configurable - esp32_nonconfigurable_ethernet_pins[0], - esp32_nonconfigurable_ethernet_pins[1], - esp32_nonconfigurable_ethernet_pins[2], - esp32_nonconfigurable_ethernet_pins[3], - esp32_nonconfigurable_ethernet_pins[4], - esp32_nonconfigurable_ethernet_pins[5], - { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory - { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory - { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use - { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory + // first six pins are non-configurable + esp32_nonconfigurable_ethernet_pins[0], + esp32_nonconfigurable_ethernet_pins[1], + esp32_nonconfigurable_ethernet_pins[2], + esp32_nonconfigurable_ethernet_pins[3], + esp32_nonconfigurable_ethernet_pins[4], + esp32_nonconfigurable_ethernet_pins[5], + {(int8_t)es.eth_mdc, true}, // [6] = MDC is output and mandatory + {(int8_t)es.eth_mdio, true}, // [7] = MDIO is bidirectional and mandatory + {(int8_t)es.eth_power, true}, // [8] = optional pin, not all boards use + {((int8_t)0xFE), false}, // [9] = replaced with eth_clk_mode, mandatory }; // update the clock pin.... - if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { + if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) + { pinsToAllocate[9].pin = 0; pinsToAllocate[9].isOutput = false; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { + } + else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) + { pinsToAllocate[9].pin = 0; pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { + } + else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) + { pinsToAllocate[9].pin = 16; pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { + } + else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) + { pinsToAllocate[9].pin = 17; pinsToAllocate[9].isOutput = true; - } else { + } + else + { DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode (")); DEBUG_PRINT(es.eth_clk_mode); DEBUG_PRINTLN(")"); return false; } - if (!pinManager.allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { + if (!pinManager.allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) + { DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); return false; } - /* - For LAN8720 the most correct way is to perform clean reset each time before init - applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) - ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in - /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) - but ESP_IDF < V4 does not. Lets do it: - [not always needed, might be relevant in some EMI situations at startup and for hot resets] - */ - #if ESP_IDF_VERSION_MAJOR==3 - if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { +/* +For LAN8720 the most correct way is to perform clean reset each time before init +applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) +ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in +/components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) +but ESP_IDF < V4 does not. Lets do it: +[not always needed, might be relevant in some EMI situations at startup and for hot resets] +*/ +#if ESP_IDF_VERSION_MAJOR == 3 + if (es.eth_power > 0 && es.eth_type == ETH_PHY_LAN8720) + { pinMode(es.eth_power, OUTPUT); digitalWrite(es.eth_power, 0); delayMicroseconds(150); digitalWrite(es.eth_power, 1); delayMicroseconds(10); } - #endif +#endif if (!ETH.begin( - (uint8_t) es.eth_address, - (int) es.eth_power, - (int) es.eth_mdc, - (int) es.eth_mdio, - (eth_phy_type_t) es.eth_type, - (eth_clock_mode_t) es.eth_clk_mode - )) { + (uint8_t)es.eth_address, + (int)es.eth_power, + (int)es.eth_mdc, + (int)es.eth_mdio, + (eth_phy_type_t)es.eth_type, + (eth_clock_mode_t)es.eth_clk_mode)) + { DEBUG_PRINTLN(F("initC: ETH.begin() failed")); // de-allocate the allocated pins - for (managed_pin_type mpt : pinsToAllocate) { + for (managed_pin_type mpt : pinsToAllocate) + { pinManager.deallocatePin(mpt.pin, PinOwner::Ethernet); } return false; @@ -672,37 +805,46 @@ bool WLED::initEthernet() #else return false; // Ethernet not enabled for build #endif - } void WLED::initConnection() { - #ifdef WLED_ENABLE_WEBSOCKETS +#ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); - #endif +#endif - WiFi.disconnect(true); // close old connections + WiFi.disconnect(true); // close old connections #ifdef ESP8266 WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N); #endif - if (staticIP[0] != 0 && staticGateway[0] != 0) { + if (staticIP[0] != 0 && staticGateway[0] != 0) + { WiFi.config(staticIP, staticGateway, staticSubnet, IPAddress(1, 1, 1, 1)); - } else { + } + else + { WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0)); } lastReconnectAttempt = millis(); - if (!WLED_WIFI_CONFIGURED) { + if (!WLED_WIFI_CONFIGURED) + { DEBUG_PRINTLN(F("No connection configured.")); - if (!apActive) initAP(); // instantly go to ap mode + if (!apActive) + initAP(); // instantly go to ap mode return; - } else if (!apActive) { - if (apBehavior == AP_BEHAVIOR_ALWAYS) { + } + else if (!apActive) + { + if (apBehavior == AP_BEHAVIOR_ALWAYS) + { DEBUG_PRINTLN(F("Access point ALWAYS enabled.")); initAP(); - } else { + } + else + { DEBUG_PRINTLN(F("Access point disabled (init).")); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); @@ -724,9 +866,9 @@ void WLED::initConnection() WiFi.begin(clientSSID, clientPass); #ifdef ARDUINO_ARCH_ESP32 - #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) +#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WiFi.setTxPower(WIFI_POWER_8_5dBm); - #endif +#endif WiFi.setSleep(!noWifiSleep); WiFi.setHostname(hostname); #else @@ -740,7 +882,8 @@ void WLED::initInterfaces() #ifndef WLED_DISABLE_HUESYNC IPAddress ipAddress = Network.localIP(); - if (hueIP[0] == 0) { + if (hueIP[0] == 0) + { hueIP[0] = ipAddress[0]; hueIP[1] = ipAddress[1]; hueIP[2] = ipAddress[2]; @@ -759,7 +902,8 @@ void WLED::initInterfaces() #endif // Set up mDNS responder: - if (strlen(cmDNS) > 0) { + if (strlen(cmDNS) > 0) + { // "end" must be called before "begin" is called a 2nd time // see https://github.com/esp8266/Arduino/issues/7213 MDNS.end(); @@ -772,7 +916,8 @@ void WLED::initInterfaces() } server.begin(); - if (udpPort > 0 && udpPort != ntpLocalPort) { + if (udpPort > 0 && udpPort != ntpLocalPort) + { udpConnected = notifierUdp.begin(udpPort); if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort); @@ -802,21 +947,26 @@ void WLED::handleConnection() if (now < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS)) return; - if (lastReconnectAttempt == 0) { + if (lastReconnectAttempt == 0) + { DEBUG_PRINTLN(F("lastReconnectAttempt == 0")); initConnection(); return; } // reconnect WiFi to clear stale allocations if heap gets too low - if (now - heapTime > 5000) { + if (now - heapTime > 5000) + { uint32_t heap = ESP.getFreeHeap(); - if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { + if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) + { DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap); forceReconnect = true; strip.purgeSegments(true); // remove all but one segments from memory - } else if (heap < MIN_HEAP_SIZE) { + } + else if (heap < MIN_HEAP_SIZE) + { strip.purgeSegments(); } lastHeap = heap; @@ -824,7 +974,8 @@ void WLED::handleConnection() } byte stac = 0; - if (apActive) { + if (apActive) + { #ifdef ESP8266 stac = wifi_softap_get_station_num(); #else @@ -832,19 +983,22 @@ void WLED::handleConnection() esp_wifi_ap_get_sta_list(&stationList); stac = stationList.num; #endif - if (stac != stacO) { + if (stac != stacO) + { stacO = stac; DEBUG_PRINT(F("Connected AP clients: ")); DEBUG_PRINTLN(stac); - if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { // trying to connect, but not connected + if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) + { // trying to connect, but not connected if (stac) - WiFi.disconnect(); // disable search so that AP can work + WiFi.disconnect(); // disable search so that AP can work else - initConnection(); // restart search + initConnection(); // restart search } } } - if (forceReconnect) { + if (forceReconnect) + { DEBUG_PRINTLN(F("Forcing reconnect.")); initConnection(); interfacesInited = false; @@ -852,34 +1006,45 @@ void WLED::handleConnection() wasConnected = false; return; } - if (!Network.isConnected()) { - if (interfacesInited) { + if (!Network.isConnected()) + { + if (interfacesInited) + { DEBUG_PRINTLN(F("Disconnected!")); interfacesInited = false; initConnection(); } - //send improv failed 6 seconds after second init attempt (24 sec. after provisioning) - if (improvActive > 2 && now - lastReconnectAttempt > 6000) { + // send improv failed 6 seconds after second init attempt (24 sec. after provisioning) + if (improvActive > 2 && now - lastReconnectAttempt > 6000) + { sendImprovStateResponse(0x03, true); improvActive = 2; } - if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) { - if (improvActive == 2) improvActive = 3; + if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) + { + if (improvActive == 2) + improvActive = 3; DEBUG_PRINTLN(F("Last reconnect too old.")); initConnection(); } - if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) { + if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) + { DEBUG_PRINTLN(F("Not connected AP.")); initAP(); } - } else if (!interfacesInited) { //newly connected + } + else if (!interfacesInited) + { // newly connected DEBUG_PRINTLN(""); DEBUG_PRINT(F("Connected! IP address: ")); DEBUG_PRINTLN(Network.localIP()); - if (improvActive) { - if (improvError == 3) sendImprovStateResponse(0x00, true); + if (improvActive) + { + if (improvError == 3) + sendImprovStateResponse(0x00, true); sendImprovStateResponse(0x04); - if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi); + if (improvActive > 1) + sendImprovIPRPCResult(ImprovRPCType::Command_Wifi); } initInterfaces(); userConnected(); @@ -887,7 +1052,8 @@ void WLED::handleConnection() lastMqttReconnectAttempt = 0; // force immediate update // shut down AP - if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) { + if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) + { dnsServer.stop(); WiFi.softAPdisconnect(true); apActive = false; @@ -902,45 +1068,55 @@ void WLED::handleConnection() // else turn the status LED off void WLED::handleStatusLED() { - #if defined(STATUSLED) +#if defined(STATUSLED) uint32_t c = 0; - #if STATUSLED>=0 - if (pinManager.isPinAllocated(STATUSLED)) { - return; //lower priority if something else uses the same pin +#if STATUSLED >= 0 + if (pinManager.isPinAllocated(STATUSLED)) + { + return; // lower priority if something else uses the same pin } - #endif +#endif - if (WLED_CONNECTED) { - c = RGBW32(0,255,0,0); + if (WLED_CONNECTED) + { + c = RGBW32(0, 255, 0, 0); ledStatusType = 2; - } else if (WLED_MQTT_CONNECTED) { - c = RGBW32(0,128,0,0); + } + else if (WLED_MQTT_CONNECTED) + { + c = RGBW32(0, 128, 0, 0); ledStatusType = 4; - } else if (apActive) { - c = RGBW32(0,0,255,0); + } + else if (apActive) + { + c = RGBW32(0, 0, 255, 0); ledStatusType = 1; } - if (ledStatusType) { - if (millis() - ledStatusLastMillis >= (1000/ledStatusType)) { + if (ledStatusType) + { + if (millis() - ledStatusLastMillis >= (1000 / ledStatusType)) + { ledStatusLastMillis = millis(); ledStatusState = !ledStatusState; - #if STATUSLED>=0 +#if STATUSLED >= 0 digitalWrite(STATUSLED, ledStatusState); - #else +#else busses.setStatusPixel(ledStatusState ? c : 0); - #endif +#endif } - } else { - #if STATUSLED>=0 - #ifdef STATUSLEDINVERTED - digitalWrite(STATUSLED, HIGH); - #else - digitalWrite(STATUSLED, LOW); - #endif - #else - busses.setStatusPixel(0); - #endif - } - #endif + } + else + { +#if STATUSLED >= 0 +#ifdef STATUSLEDINVERTED + digitalWrite(STATUSLED, HIGH); +#else + digitalWrite(STATUSLED, LOW); +#endif +#else + busses.setStatusPixel(0); +#endif + } +#endif } diff --git a/wled00/wled.h b/wled00/wled.h index 5d4cca4e93..aafbd3bf2c 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -10,8 +10,8 @@ // version code in format yymmddb (b = daily build) #define VERSION 2405180 -//uncomment this if you have a "my_config.h" file you'd like to use -//#define WLED_USE_MY_CONFIG +// uncomment this if you have a "my_config.h" file you'd like to use +// #define WLED_USE_MY_CONFIG // ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit. @@ -21,83 +21,83 @@ // Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini // You are required to disable over-the-air updates: -//#define WLED_DISABLE_OTA // saves 14kb +// #define WLED_DISABLE_OTA // saves 14kb // You can choose some of these features to disable: -//#define WLED_DISABLE_ALEXA // saves 11kb -//#define WLED_DISABLE_HUESYNC // saves 4kb -//#define WLED_DISABLE_INFRARED // saves 12kb, there is no pin left for this on ESP8266-01 +// #define WLED_DISABLE_ALEXA // saves 11kb +// #define WLED_DISABLE_HUESYNC // saves 4kb +// #define WLED_DISABLE_INFRARED // saves 12kb, there is no pin left for this on ESP8266-01 #ifndef WLED_DISABLE_MQTT - #define WLED_ENABLE_MQTT // saves 12kb +#define WLED_ENABLE_MQTT // saves 12kb #endif -#ifndef WLED_DISABLE_ADALIGHT // can be used to disable reading commands from serial RX pin (see issue #3128). - #define WLED_ENABLE_ADALIGHT // disable saves 5Kb (uses GPIO3 (RX) for serial). Related serial protocols: Adalight/TPM2, Improv, Serial JSON, Continuous Serial Streaming +#ifndef WLED_DISABLE_ADALIGHT // can be used to disable reading commands from serial RX pin (see issue #3128). +#define WLED_ENABLE_ADALIGHT // disable saves 5Kb (uses GPIO3 (RX) for serial). Related serial protocols: Adalight/TPM2, Improv, Serial JSON, Continuous Serial Streaming #else - #undef WLED_ENABLE_ADALIGHT // disable has priority over enable +#undef WLED_ENABLE_ADALIGHT // disable has priority over enable #endif -//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) -#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) +// #define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) +#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) #ifndef WLED_DISABLE_LOXONE - #define WLED_ENABLE_LOXONE // uses 1.2kb +#define WLED_ENABLE_LOXONE // uses 1.2kb #endif #ifndef WLED_DISABLE_WEBSOCKETS - #define WLED_ENABLE_WEBSOCKETS +#define WLED_ENABLE_WEBSOCKETS #endif -//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now +// #define WLED_DISABLE_ESPNOW // Removes dependence on esp now -#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock +#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock // to toggle usb serial debug (un)comment the following line -//#define WLED_DEBUG +// #define WLED_DEBUG // filesystem specific debugging -//#define WLED_DEBUG_FS +// #define WLED_DEBUG_FS #ifndef WLED_WATCHDOG_TIMEOUT - // 3 seconds should be enough to detect a lockup - // define WLED_WATCHDOG_TIMEOUT=0 to disable watchdog, default - #define WLED_WATCHDOG_TIMEOUT 0 +// 3 seconds should be enough to detect a lockup +// define WLED_WATCHDOG_TIMEOUT=0 to disable watchdog, default +#define WLED_WATCHDOG_TIMEOUT 0 #endif -//optionally disable brownout detector on ESP32. -//This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks -//#define WLED_DISABLE_BROWNOUT_DET +// optionally disable brownout detector on ESP32. +// This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks +// #define WLED_DISABLE_BROWNOUT_DET // Library inclusions. #include #ifdef ESP8266 - #include - #include - #include - #include - extern "C" - { - #include - } - #ifndef WLED_DISABLE_ESPNOW - #include - #endif -#else // ESP32 - #include // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT) - #include - #include - #include "esp_wifi.h" - #include - #include - #if LOROL_LITTLEFS - #ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 - #define CONFIG_LITTLEFS_FOR_IDF_3_2 - #endif - #include - #else - #include - #endif - #include "esp_task_wdt.h" - - #ifndef WLED_DISABLE_ESPNOW - #include - #endif +#include +#include +#include +#include +extern "C" +{ +#include +} +#ifndef WLED_DISABLE_ESPNOW +#include +#endif +#else // ESP32 +#include // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT) +#include +#include +#include "esp_wifi.h" +#include +#include +#if LOROL_LITTLEFS +#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 +#define CONFIG_LITTLEFS_FOR_IDF_3_2 +#endif +#include +#else +#include +#endif +#include "esp_task_wdt.h" + +#ifndef WLED_DISABLE_ESPNOW +#include +#endif #endif #include #include @@ -105,18 +105,18 @@ #include "src/dependencies/network/Network.h" #ifdef WLED_USE_MY_CONFIG - #include "my_config.h" +#include "my_config.h" #endif #include #ifdef WLED_ADD_EEPROM_SUPPORT - #include +#include #endif #include #include #ifndef WLED_DISABLE_OTA - #define NO_OTA_PORT - #include +#define NO_OTA_PORT +#include #endif #include #include "src/dependencies/time/TimeLib.h" @@ -124,20 +124,20 @@ #include "src/dependencies/toki/Toki.h" #ifndef WLED_DISABLE_ALEXA - #define ESPALEXA_ASYNC - #define ESPALEXA_NO_SUBPAGE - #define ESPALEXA_MAXDEVICES 10 - // #define ESPALEXA_DEBUG - #include "src/dependencies/espalexa/Espalexa.h" - #include "src/dependencies/espalexa/EspalexaDevice.h" +#define ESPALEXA_ASYNC +#define ESPALEXA_NO_SUBPAGE +#define ESPALEXA_MAXDEVICES 10 +// #define ESPALEXA_DEBUG +#include "src/dependencies/espalexa/Espalexa.h" +#include "src/dependencies/espalexa/EspalexaDevice.h" #endif #ifdef WLED_ENABLE_DMX - #ifdef ESP8266 - #include "src/dependencies/dmx/ESPDMX.h" - #else //ESP32 - #include "src/dependencies/dmx/SparkFunDMX.h" - #endif +#ifdef ESP8266 +#include "src/dependencies/dmx/ESPDMX.h" +#else // ESP32 +#include "src/dependencies/dmx/SparkFunDMX.h" +#endif #endif #include "src/dependencies/e131/ESPAsyncE131.h" @@ -155,16 +155,24 @@ // There is a code that will still not use PSRAM though: // AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h) #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM) -struct PSRAM_Allocator { - void* allocate(size_t size) { - if (psramFound()) return ps_malloc(size); // use PSRAM if it exists - else return malloc(size); // fallback +struct PSRAM_Allocator +{ + void *allocate(size_t size) + { + if (psramFound()) + return ps_malloc(size); // use PSRAM if it exists + else + return malloc(size); // fallback } - void* reallocate(void* ptr, size_t new_size) { - if (psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists - else return realloc(ptr, new_size); // fallback + void *reallocate(void *ptr, size_t new_size) + { + if (psramFound()) + return ps_realloc(ptr, new_size); // use PSRAM if it exists + else + return realloc(ptr, new_size); // fallback } - void deallocate(void* pointer) { + void deallocate(void *pointer) + { free(pointer); } }; @@ -181,77 +189,77 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #include "FX.h" #ifndef CLIENT_SSID - #define CLIENT_SSID DEFAULT_CLIENT_SSID +#define CLIENT_SSID DEFAULT_CLIENT_SSID #endif #ifndef CLIENT_PASS - #define CLIENT_PASS "" +#define CLIENT_PASS "" #endif #ifndef MDNS_NAME - #define MDNS_NAME DEFAULT_MDNS_NAME +#define MDNS_NAME DEFAULT_MDNS_NAME #endif #if defined(WLED_AP_PASS) && !defined(WLED_AP_SSID) - #error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \ +#error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \ Please change WLED_AP_SSID to something unique. #endif #ifndef WLED_AP_SSID - #define WLED_AP_SSID DEFAULT_AP_SSID +#define WLED_AP_SSID DEFAULT_AP_SSID #endif #ifndef WLED_AP_PASS - #define WLED_AP_PASS DEFAULT_AP_PASS +#define WLED_AP_PASS DEFAULT_AP_PASS #endif #ifndef SPIFFS_EDITOR_AIRCOOOKIE - #error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\ +#error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\ Using upstream puts your WiFi password at risk of being served by the filesystem.\ Comment out this error message to build regardless. #endif #ifndef WLED_DISABLE_INFRARED - #include - #include - #include +#include +#include +#include #endif -//Filesystem to use for preset and config files. SPIFFS or LittleFS on ESP8266, SPIFFS only on ESP32 (now using LITTLEFS port by lorol) +// Filesystem to use for preset and config files. SPIFFS or LittleFS on ESP8266, SPIFFS only on ESP32 (now using LITTLEFS port by lorol) #ifdef ESP8266 - #define WLED_FS LittleFS +#define WLED_FS LittleFS +#else +#if LOROL_LITTLEFS +#define WLED_FS LITTLEFS #else - #if LOROL_LITTLEFS - #define WLED_FS LITTLEFS - #else - #define WLED_FS LittleFS - #endif +#define WLED_FS LittleFS +#endif #endif // GLOBAL VARIABLES // both declared and defined in header (solution from http://www.keil.com/support/docs/1868.htm) // -//e.g. byte test = 2 becomes WLED_GLOBAL byte test _INIT(2); +// e.g. byte test = 2 becomes WLED_GLOBAL byte test _INIT(2); // int arr[]{0,1,2} becomes WLED_GLOBAL int arr[] _INIT_N(({0,1,2})); #ifndef WLED_DEFINE_GLOBAL_VARS -# define WLED_GLOBAL extern -# define _INIT(x) -# define _INIT_N(x) +#define WLED_GLOBAL extern +#define _INIT(x) +#define _INIT_N(x) #else -# define WLED_GLOBAL -# define _INIT(x) = x +#define WLED_GLOBAL +#define _INIT(x) = x -//needed to ignore commas in array definitions -#define UNPACK( ... ) __VA_ARGS__ -# define _INIT_N(x) UNPACK x +// needed to ignore commas in array definitions +#define UNPACK(...) __VA_ARGS__ +#define _INIT_N(x) UNPACK x #endif #define STRINGIFY(X) #X #define TOSTRING(X) STRINGIFY(X) #ifndef WLED_VERSION - #define WLED_VERSION "dev" +#define WLED_VERSION "dev" #endif // Global Variable definitions @@ -259,8 +267,9 @@ WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); #define WLED_CODENAME "Hoshi" // AP and OTA default passwords (for maximum security change them!) -WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); +WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); +WLED_GLOBAL bool otaInProgress _INIT(false); // Hardware and pin config #ifndef BTNPIN @@ -273,7 +282,7 @@ WLED_GLOBAL int8_t rlyPin _INIT(-1); #else WLED_GLOBAL int8_t rlyPin _INIT(RLYPIN); #endif -//Relay mode (1 = active high, 0 = active low, flipped in cfg.json) +// Relay mode (1 = active high, 0 = active low, flipped in cfg.json) #ifndef RLYMDE WLED_GLOBAL bool rlyMde _INIT(true); #else @@ -286,132 +295,132 @@ WLED_GLOBAL int8_t irPin _INIT(IRPIN); #endif #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || (defined(RX) && defined(TX)) - // use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1 - constexpr uint8_t hardwareRX = RX; - constexpr uint8_t hardwareTX = TX; +// use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1 +constexpr uint8_t hardwareRX = RX; +constexpr uint8_t hardwareTX = TX; #else - // use defaults for RX/TX - constexpr uint8_t hardwareRX = 3; - constexpr uint8_t hardwareTX = 1; +// use defaults for RX/TX +constexpr uint8_t hardwareRX = 3; +constexpr uint8_t hardwareTX = 1; #endif -//WLED_GLOBAL byte presetToApply _INIT(0); +// WLED_GLOBAL byte presetToApply _INIT(0); -WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use +WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use // WiFi CONFIG (all these can be changed via web UI, no need to set them here) WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID); WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS); -WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) -WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) -WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) -WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID -WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default -WLED_GLOBAL IPAddress staticIP _INIT_N((( 0, 0, 0, 0))); // static IP of ESP -WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP -WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks +WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) +WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) +WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) +WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID +WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default +WLED_GLOBAL IPAddress staticIP _INIT_N(((0, 0, 0, 0))); // static IP of ESP +WLED_GLOBAL IPAddress staticGateway _INIT_N(((0, 0, 0, 0))); // gateway (router) IP +WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks #ifdef ARDUINO_ARCH_ESP32 -WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues +WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues #else WLED_GLOBAL bool noWifiSleep _INIT(false); #endif WLED_GLOBAL bool force802_3g _INIT(false); #ifdef WLED_USE_ETHERNET - #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified - WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type - #else - WLED_GLOBAL int ethernetType _INIT(WLED_ETH_NONE); // use none for ethernet board type if default not defined - #endif +#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified +WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type +#else +WLED_GLOBAL int ethernetType _INIT(WLED_ETH_NONE); // use none for ethernet board type if default not defined +#endif #endif // LED CONFIG -WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up -WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up +WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up +WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up -//if true, a segment per bus will be created on boot and LED settings save -//if false, only one segment spanning the total LEDs is created, -//but not on LED settings save if there is more than one segment currently -WLED_GLOBAL bool autoSegments _INIT(false); +// if true, a segment per bus will be created on boot and LED settings save +// if false, only one segment spanning the total LEDs is created, +// but not on LED settings save if there is more than one segment currently +WLED_GLOBAL bool autoSegments _INIT(false); #ifdef ESP8266 WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else -WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 +WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 #endif -WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color -WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct -WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors -WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness -WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value +WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color +WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct +WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors +WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness +WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value -WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color. -WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color -WLED_GLOBAL byte briS _INIT(128); // default brightness +WLED_GLOBAL byte col[] _INIT_N(({255, 160, 0, 0})); // current RGB(W) primary color. col[] should be updated if you want to change the color. +WLED_GLOBAL byte colSec[] _INIT_N(({0, 0, 0, 0})); // current RGB(W) secondary color +WLED_GLOBAL byte briS _INIT(128); // default brightness -WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over +WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over WLED_GLOBAL byte nightlightDelayMins _INIT(60); -WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade +WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade -WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) +WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) // User Interface CONFIG #ifndef SERVERNAME -WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use default +WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use default #else -WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name +WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name #endif -WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise -WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI -WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI +WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise +WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI +WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI // Sync CONFIG WLED_GLOBAL NodesMap Nodes; WLED_GLOBAL bool nodeListEnabled _INIT(true); WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true); -WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH}); +WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH}); #if defined(IRTYPE) && defined(IRPIN) -WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver +WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver #else -WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled +WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled #endif -WLED_GLOBAL bool irApplyToAllSelected _INIT(true); //apply IR to all selected segments +WLED_GLOBAL bool irApplyToAllSelected _INIT(true); // apply IR to all selected segments -WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port -WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port +WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port +WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port -WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync groups this instance syncs (bit mapped) -WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) -WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications -WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color -WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup -WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options -WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) -WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API -WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote -WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa -WLED_GLOBAL bool notifyMacro _INIT(false); // send notification for macro -WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes -WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability - -WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo -WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand -WLED_GLOBAL byte alexaNumPresets _INIT(0); // number of presets to expose to Alexa, starting from preset 1, up to 9 - -WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode -WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset -WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP realtime -WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source -WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black +WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync groups this instance syncs (bit mapped) +WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) +WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications +WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color +WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup +WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options +WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) +WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API +WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote +WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa +WLED_GLOBAL bool notifyMacro _INIT(false); // send notification for macro +WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes +WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability + +WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo +WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand +WLED_GLOBAL byte alexaNumPresets _INIT(0); // number of presets to expose to Alexa, starting from preset 1, up to 9 + +WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode +WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset +WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP realtime +WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source +WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black #ifdef WLED_ENABLE_DMX - #ifdef ESP8266 - WLED_GLOBAL DMXESPSerial dmx; - #else //ESP32 - WLED_GLOBAL SparkFunDMX dmx; - #endif -WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled) +#ifdef ESP8266 +WLED_GLOBAL DMXESPSerial dmx; +#else // ESP32 +WLED_GLOBAL SparkFunDMX dmx; +#endif +WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled) #endif WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consecutive universes) WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 @@ -426,35 +435,36 @@ WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze inst WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count number of replies for ArtPoll node report // mqtt -WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too +WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT - #ifndef MQTT_MAX_TOPIC_LEN - #define MQTT_MAX_TOPIC_LEN 32 - #endif - #ifndef MQTT_MAX_SERVER_LEN - #define MQTT_MAX_SERVER_LEN 32 - #endif +#ifndef MQTT_MAX_TOPIC_LEN +#define MQTT_MAX_TOPIC_LEN 32 +#endif +#ifndef MQTT_MAX_SERVER_LEN +#define MQTT_MAX_SERVER_LEN 52 +#endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers -WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) -WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices) -WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL) -WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth -WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth -WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID +WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) +WLED_GLOBAL char mqttResponseTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // MQTT response topic (individual per device, default is lights/mac/r) +WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) +WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) +WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth +WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth +WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL uint16_t mqttPort _INIT(1883); -WLED_GLOBAL bool retainMqttMsg _INIT(false); // retain brightness and color +WLED_GLOBAL bool retainMqttMsg _INIT(false); // retain brightness and color #define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected()) #else #define WLED_MQTT_CONNECTED false #endif #ifndef WLED_DISABLE_HUESYNC -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 char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge -WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section) +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 char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge +WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section) WLED_GLOBAL IPAddress hueIP _INIT_N(((0, 0, 0, 0))); // IP address of the bridge WLED_GLOBAL bool hueApplyOnOff _INIT(true); WLED_GLOBAL bool hueApplyBri _INIT(true); @@ -465,53 +475,53 @@ WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 10 #ifndef WLED_DISABLE_ESPNOW WLED_GLOBAL bool enable_espnow_remote _INIT(false); -WLED_GLOBAL char linked_remote[13] _INIT(""); -WLED_GLOBAL char last_signal_src[13] _INIT(""); +WLED_GLOBAL char linked_remote[13] _INIT(""); +WLED_GLOBAL char last_signal_src[13] _INIT(""); #endif // Time CONFIG -WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros -WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format -WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino -WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation +WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros +WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format +WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino +WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation -WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie -WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode +WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie +WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode -WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be -WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel -WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position +WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be +WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel +WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position -WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date -WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits -WLED_GLOBAL byte countdownDay _INIT(1) , countdownHour _INIT(0); -WLED_GLOBAL byte countdownMin _INIT(0) , countdownSec _INIT(0); +WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date +WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits +WLED_GLOBAL byte countdownDay _INIT(1), countdownHour _INIT(0); +WLED_GLOBAL byte countdownMin _INIT(0), countdownSec _INIT(0); -WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over +WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over WLED_GLOBAL byte macroCountdown _INIT(0); WLED_GLOBAL byte macroAlexaOn _INIT(0), macroAlexaOff _INIT(0); -WLED_GLOBAL byte macroButton[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroButton[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); // Security CONFIG -WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks -WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled -WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on -WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages -WLED_GLOBAL bool correctPIN _INIT(true); +WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled +WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on +WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages +WLED_GLOBAL bool correctPIN _INIT(true); WLED_GLOBAL unsigned long lastEditTime _INIT(0); -WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use in usermod +WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); // available for use in usermod #ifdef WLED_ENABLE_DMX - // dmx CONFIG - WLED_GLOBAL byte DMXChannels _INIT(7); // number of channels per fixture - WLED_GLOBAL byte DMXFixtureMap[15] _INIT_N(({ 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. - WLED_GLOBAL uint16_t DMXGap _INIT(10); // gap between the fixtures. makes addressing easier because you don't have to memorize odd numbers when climbing up onto a rig. - WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture - WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start + // dmx CONFIG +WLED_GLOBAL byte DMXChannels _INIT(7); // number of channels per fixture +WLED_GLOBAL byte DMXFixtureMap[15] _INIT_N(({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. +WLED_GLOBAL uint16_t DMXGap _INIT(10); // gap between the fixtures. makes addressing easier because you don't have to memorize odd numbers when climbing up onto a rig. +WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture +WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start #endif // internal global variable declarations @@ -523,18 +533,18 @@ WLED_GLOBAL bool interfacesInited _INIT(false); WLED_GLOBAL bool wasConnected _INIT(false); // color -WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same +WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same // transitions -WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color -WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending -WLED_GLOBAL bool transitionActive _INIT(false); -WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration -WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) +WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color +WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending +WLED_GLOBAL bool transitionActive _INIT(false); +WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration +WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f -WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") -WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f +WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") +WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); @@ -542,26 +552,26 @@ WLED_GLOBAL bool nightlightActiveOld _INIT(false); WLED_GLOBAL uint32_t nightlightDelayMs _INIT(10); WLED_GLOBAL byte nightlightDelayMinsDefault _INIT(nightlightDelayMins); WLED_GLOBAL unsigned long nightlightStartTime; -WLED_GLOBAL byte briNlT _INIT(0); // current nightlight brightness -WLED_GLOBAL byte colNlT[] _INIT_N(({ 0, 0, 0, 0 })); // current nightlight color +WLED_GLOBAL byte briNlT _INIT(0); // current nightlight brightness +WLED_GLOBAL byte colNlT[] _INIT_N(({0, 0, 0, 0})); // current nightlight color // brightness WLED_GLOBAL unsigned long lastOnTime _INIT(0); -WLED_GLOBAL bool offMode _INIT(!turnOnAtBoot); -WLED_GLOBAL byte bri _INIT(briS); // global brightness (set) -WLED_GLOBAL byte briOld _INIT(0); // global brightness while in transition loop (previous iteration) -WLED_GLOBAL byte briT _INIT(0); // global brightness during transition -WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function -WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function +WLED_GLOBAL bool offMode _INIT(!turnOnAtBoot); +WLED_GLOBAL byte bri _INIT(briS); // global brightness (set) +WLED_GLOBAL byte briOld _INIT(0); // global brightness while in transition loop (previous iteration) +WLED_GLOBAL byte briT _INIT(0); // global brightness during transition +WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function +WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function // button -WLED_GLOBAL bool buttonPublishMqtt _INIT(false); -WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); -WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); +WLED_GLOBAL bool buttonPublishMqtt _INIT(false); +WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); +WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL bool disablePullUp _INIT(false); -WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); +WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL bool disablePullUp _INIT(false); +WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); // notifications WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect); @@ -598,25 +608,25 @@ WLED_GLOBAL bool hueStoreAllowed _INIT(false), hueNewKey _INIT(false); WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L); WLED_GLOBAL bool countdownOverTriggered _INIT(true); -//timer -WLED_GLOBAL byte lastTimerMinute _INIT(0); -WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); -WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); -WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); -//weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity -WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); -//upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12) -WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28})); -WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1})); -WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31})); - -//improv -WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning +// timer +WLED_GLOBAL byte lastTimerMinute _INIT(0); +WLED_GLOBAL byte timerHours[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); +WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); +WLED_GLOBAL byte timerMacro[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); +// weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity +WLED_GLOBAL byte timerWeekday[] _INIT_N(({255, 255, 255, 255, 255, 255, 255, 255, 255, 255})); +// upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12) +WLED_GLOBAL byte timerMonth[] _INIT_N(({28, 28, 28, 28, 28, 28, 28, 28})); +WLED_GLOBAL byte timerDay[] _INIT_N(({1, 1, 1, 1, 1, 1, 1, 1})); +WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31, 31, 31, 31, 31, 31, 31, 31})); + +// improv +WLED_GLOBAL byte improvActive _INIT(0); // 0: no improv packet received, 1: improv active, 2: provisioning WLED_GLOBAL byte improvError _INIT(0); -//playlists +// playlists WLED_GLOBAL int16_t currentPlaylist _INIT(-1); -//still used for "PL=~" HTTP API command +// still used for "PL=~" HTTP API command WLED_GLOBAL byte presetCycCurr _INIT(0); WLED_GLOBAL byte presetCycMin _INIT(1); WLED_GLOBAL byte presetCycMax _INIT(5); @@ -636,8 +646,8 @@ WLED_GLOBAL byte interfaceUpdateCallMode _INIT(CALL_MODE_INIT); // alexa udp WLED_GLOBAL String escapedMac; #ifndef WLED_DISABLE_ALEXA - WLED_GLOBAL Espalexa espalexa; - WLED_GLOBAL EspalexaDevice* espalexaDevice; +WLED_GLOBAL Espalexa espalexa; +WLED_GLOBAL EspalexaDevice *espalexaDevice; #endif // dns server @@ -659,14 +669,14 @@ WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL Toki toki _INIT(Toki()); // Temp buffer -WLED_GLOBAL char* obuf; +WLED_GLOBAL char *obuf; WLED_GLOBAL uint16_t olen _INIT(0); // General filesystem WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0); WLED_GLOBAL unsigned long presetsModifiedTime _INIT(0L); -WLED_GLOBAL JsonDocument* fileDoc; +WLED_GLOBAL JsonDocument *fileDoc; WLED_GLOBAL bool doCloseFile _INIT(false); // presets @@ -677,14 +687,14 @@ WLED_GLOBAL byte errorFlag _INIT(0); WLED_GLOBAL String messageHead, messageSub; WLED_GLOBAL byte optionType; -WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config -WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers -WLED_GLOBAL bool doPublishMqtt _INIT(false); +WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config +WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers +WLED_GLOBAL bool doPublishMqtt _INIT(false); // status led #if defined(STATUSLED) WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0); -WLED_GLOBAL uint8_t ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second +WLED_GLOBAL uint8_t ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second WLED_GLOBAL bool ledStatusState _INIT(false); // the current LED state #endif @@ -693,26 +703,26 @@ 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 AsyncWebHandler *editHandler _INIT(nullptr); // udp interface objects WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp, notifier2Udp; WLED_GLOBAL WiFiUDP ntpUdp; WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet))); -WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet))); +WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet))); WLED_GLOBAL bool e131NewData _INIT(false); // led fx library object WLED_GLOBAL BusManager busses _INIT(BusManager()); WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); -WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after +WLED_GLOBAL BusConfig *busConfigs[WLED_MAX_BUSSES + WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); // temporary, to remember values from network callback until after WLED_GLOBAL bool doInitBusses _INIT(false); WLED_GLOBAL int8_t loadLedmap _INIT(-1); #ifndef ESP8266 -WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr})); +WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS - 1] _INIT_N(({nullptr})); #endif -#if WLED_MAX_LEDMAPS>16 +#if WLED_MAX_LEDMAPS > 16 WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available ledmaps #else WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps @@ -723,125 +733,134 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN -WLED_GLOBAL int8_t i2c_sda _INIT(-1); +WLED_GLOBAL int8_t i2c_sda _INIT(-1); #else -WLED_GLOBAL int8_t i2c_sda _INIT(I2CSDAPIN); +WLED_GLOBAL int8_t i2c_sda _INIT(I2CSDAPIN); #endif // global I2C SCL pin (used for usermods) #ifndef I2CSCLPIN -WLED_GLOBAL int8_t i2c_scl _INIT(-1); +WLED_GLOBAL int8_t i2c_scl _INIT(-1); #else -WLED_GLOBAL int8_t i2c_scl _INIT(I2CSCLPIN); +WLED_GLOBAL int8_t i2c_scl _INIT(I2CSCLPIN); #endif // global SPI DATA/MOSI pin (used for usermods) #ifndef SPIMOSIPIN -WLED_GLOBAL int8_t spi_mosi _INIT(-1); +WLED_GLOBAL int8_t spi_mosi _INIT(-1); #else -WLED_GLOBAL int8_t spi_mosi _INIT(SPIMOSIPIN); +WLED_GLOBAL int8_t spi_mosi _INIT(SPIMOSIPIN); #endif // global SPI DATA/MISO pin (used for usermods) #ifndef SPIMISOPIN -WLED_GLOBAL int8_t spi_miso _INIT(-1); +WLED_GLOBAL int8_t spi_miso _INIT(-1); #else -WLED_GLOBAL int8_t spi_miso _INIT(SPIMISOPIN); +WLED_GLOBAL int8_t spi_miso _INIT(SPIMISOPIN); #endif // global SPI CLOCK/SCLK pin (used for usermods) #ifndef SPISCLKPIN -WLED_GLOBAL int8_t spi_sclk _INIT(-1); +WLED_GLOBAL int8_t spi_sclk _INIT(-1); #else -WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); +WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); #endif // global ArduinoJson buffer WLED_GLOBAL StaticJsonDocument doc; WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0); +// global buffers for mqtt responses +WLED_GLOBAL StaticJsonDocument mqttResponseDoc; +WLED_GLOBAL char mqttResponseBuffer[JSON_BUFFER_SIZE] _INIT(""); +WLED_GLOBAL volatile uint8_t responseBufferLock _INIT(0); + // enable additional debug output #if defined(WLED_DEBUG_HOST) - #include "net_debug.h" - // On the host side, use netcat to receive the log statements: nc -l 7868 -u - // use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes - #define DEBUGOUT NetDebug - WLED_GLOBAL bool netDebugEnabled _INIT(true); - WLED_GLOBAL char netDebugPrintHost[33] _INIT(WLED_DEBUG_HOST); - #ifndef WLED_DEBUG_PORT - #define WLED_DEBUG_PORT 7868 - #endif - WLED_GLOBAL int netDebugPrintPort _INIT(WLED_DEBUG_PORT); +#include "net_debug.h" +// On the host side, use netcat to receive the log statements: nc -l 7868 -u +// use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes +#define DEBUGOUT NetDebug +WLED_GLOBAL bool netDebugEnabled _INIT(true); +WLED_GLOBAL char netDebugPrintHost[33] _INIT(WLED_DEBUG_HOST); +#ifndef WLED_DEBUG_PORT +#define WLED_DEBUG_PORT 7868 +#endif +WLED_GLOBAL int netDebugPrintPort _INIT(WLED_DEBUG_PORT); #else - #define DEBUGOUT Serial +#define DEBUGOUT Serial #endif #ifdef WLED_DEBUG - #ifndef ESP8266 - #include - #endif - #define DEBUG_PRINT(x) DEBUGOUT.print(x) - #define DEBUG_PRINTLN(x) DEBUGOUT.println(x) - #define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) +#ifndef ESP8266 +#include +#endif +#define DEBUG_PRINT(x) DEBUGOUT.print(x) +#define DEBUG_PRINTLN(x) DEBUGOUT.println(x) +#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) #else - #define DEBUG_PRINT(x) - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINTF(x...) +#define DEBUG_PRINT(x) +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINTF(x...) #endif #ifdef WLED_DEBUG_FS - #define DEBUGFS_PRINT(x) DEBUGOUT.print(x) - #define DEBUGFS_PRINTLN(x) DEBUGOUT.println(x) - #define DEBUGFS_PRINTF(x...) DEBUGOUT.printf(x) +#define DEBUGFS_PRINT(x) DEBUGOUT.print(x) +#define DEBUGFS_PRINTLN(x) DEBUGOUT.println(x) +#define DEBUGFS_PRINTF(x...) DEBUGOUT.printf(x) #else - #define DEBUGFS_PRINT(x) - #define DEBUGFS_PRINTLN(x) - #define DEBUGFS_PRINTF(x...) +#define DEBUGFS_PRINT(x) +#define DEBUGFS_PRINTLN(x) +#define DEBUGFS_PRINTF(x...) #endif // debug macro variable definitions #ifdef WLED_DEBUG - WLED_GLOBAL unsigned long debugTime _INIT(0); - WLED_GLOBAL int lastWifiState _INIT(3); - WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0); - WLED_GLOBAL unsigned long loops _INIT(0); +WLED_GLOBAL unsigned long debugTime _INIT(0); +WLED_GLOBAL int lastWifiState _INIT(3); +WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0); +WLED_GLOBAL unsigned long loops _INIT(0); #endif #ifdef ARDUINO_ARCH_ESP32 - #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) +#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) #else - #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) +#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) #endif #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #ifndef WLED_AP_SSID_UNIQUE - #define WLED_SET_AP_SSID() do { \ +#define WLED_SET_AP_SSID() \ + do \ + { \ strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ - } while(0) + } while (0) #else - #define WLED_SET_AP_SSID() do { \ - strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ - snprintf_P(\ - apSSID+strlen(WLED_AP_SSID), \ - sizeof(apSSID)-strlen(WLED_AP_SSID), \ - PSTR("-%*s"), \ - 6, \ - escapedMac.c_str() + 6\ - ); \ - } while(0) -#endif - -//macro to convert F to const -#define SET_F(x) (const char*)F(x) - -//color mangling macros -#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) +#define WLED_SET_AP_SSID() \ + do \ + { \ + strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ + snprintf_P( \ + apSSID + strlen(WLED_AP_SSID), \ + sizeof(apSSID) - strlen(WLED_AP_SSID), \ + PSTR("-%*s"), \ + 6, \ + escapedMac.c_str() + 6); \ + } while (0) +#endif + +// macro to convert F to const +#define SET_F(x) (const char *)F(x) + +// color mangling macros +#define RGBW32(r, g, b, w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #define R(c) (byte((c) >> 16)) #define G(c) (byte((c) >> 8)) #define B(c) (byte(c)) #define W(c) (byte((c) >> 24)) -class WLED { +class WLED +{ public: WLED(); - static WLED& instance() + static WLED &instance() { static WLED instance; return instance; @@ -863,4 +882,4 @@ class WLED { void enableWatchdog(); void disableWatchdog(); }; -#endif // WLED_H +#endif // WLED_H From cb9ea10311dd3fa66fb36596739f8b9f333f2341 Mon Sep 17 00:00:00 2001 From: JacobK5 Date: Sat, 21 Sep 2024 09:51:04 -0600 Subject: [PATCH 2/3] Revert "Made Relevant Changes From My Own Codebase" This reverts commit c6ee7da74fc916220b0af699baab61b5fc13ecd6. --- platformio.ini | 5 +- wled00/fcn_declare.h | 447 +++++----- wled00/mqtt.cpp | 366 ++------ .../async-mqtt-client/AsyncMqttClient.cpp | 666 ++++++-------- .../async-mqtt-client/AsyncMqttClient.hpp | 84 +- wled00/util.cpp | 758 +++++++--------- wled00/wled.cpp | 812 +++++++----------- wled00/wled.h | 727 ++++++++-------- 8 files changed, 1516 insertions(+), 2349 deletions(-) diff --git a/platformio.ini b/platformio.ini index f14c00d1c4..2ef4ae01bf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ # CI binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment -; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi # Release binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB @@ -30,7 +30,7 @@ ; default_envs = h803wf ; default_envs = d1_mini_debug ; default_envs = d1_mini_ota -default_envs = esp32dev +; default_envs = esp32dev ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_H801 ; default_envs = d1_mini_5CH_Shojo_PCB @@ -257,7 +257,6 @@ build_flags = -g -D CONFIG_ASYNC_TCP_USE_WDT=0 #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS - -D WLED_DEBUG # for full debugging ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv lib_deps = diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 665ee808bd..c65f7a90b4 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -5,34 +5,32 @@ * All globally accessible functions are declared here */ -// alexa.cpp +//alexa.cpp #ifndef WLED_DISABLE_ALEXA -void onAlexaChange(EspalexaDevice *dev); +void onAlexaChange(EspalexaDevice* dev); void alexaInit(); void handleAlexa(); -void onAlexaChange(EspalexaDevice *dev); +void onAlexaChange(EspalexaDevice* dev); #endif -// button.cpp -void shortPressAction(uint8_t b = 0); -void longPressAction(uint8_t b = 0); -void doublePressAction(uint8_t b = 0); -bool isButtonPressed(uint8_t b = 0); +//button.cpp +void shortPressAction(uint8_t b=0); +void longPressAction(uint8_t b=0); +void doublePressAction(uint8_t b=0); +bool isButtonPressed(uint8_t b=0); void handleButton(); void handleIO(); -// cfg.cpp +//cfg.cpp bool deserializeConfig(JsonObject doc, bool fromFS = false); void deserializeConfigFromFS(); bool deserializeConfigSec(); void serializeConfig(); void serializeConfigSec(); -template -bool getJsonValue(const JsonVariant &element, DestType &destination) -{ - if (element.isNull()) - { +template +bool getJsonValue(const JsonVariant& element, DestType& destination) { + if (element.isNull()) { return false; } @@ -40,11 +38,9 @@ bool getJsonValue(const JsonVariant &element, DestType &destination) return true; } -template -bool getJsonValue(const JsonVariant &element, DestType &destination, const DefaultType defaultValue) -{ - if (!getJsonValue(element, destination)) - { +template +bool getJsonValue(const JsonVariant& element, DestType& destination, const DefaultType defaultValue) { + if(!getJsonValue(element, destination)) { destination = defaultValue; return false; } @@ -52,65 +48,64 @@ bool getJsonValue(const JsonVariant &element, DestType &destination, const Defau return true; } -// colors.cpp -// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) -class NeoGammaWLEDMethod -{ -public: - static uint8_t Correct(uint8_t value); // apply Gamma to single channel - static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) - static void calcGammaTable(float gamma); // re-calculates & fills gamma table - static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) -private: - static uint8_t gammaT[]; + +//colors.cpp +// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) +class NeoGammaWLEDMethod { + public: + static uint8_t Correct(uint8_t value); // apply Gamma to single channel + static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) + static void calcGammaTable(float gamma); // re-calculates & fills gamma table + static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) + private: + static uint8_t gammaT[]; }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) -#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16 = false); -uint32_t color_add(uint32_t, uint32_t, bool fast = false); -uint32_t color_fade(uint32_t c1, uint8_t amount, bool video = false); -inline uint32_t colorFromRgbw(byte *rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } -void colorHStoRGB(uint16_t hue, byte sat, byte *rgb); // hue, sat to rgb -void colorKtoRGB(uint16_t kelvin, byte *rgb); -void colorCTtoRGB(uint16_t mired, byte *rgb); // white spectrum to rgb -void colorXYtoRGB(float x, float y, byte *rgb); // only defined if huesync disabled TODO -void colorRGBtoXY(byte *rgb, float *xy); // only defined if huesync disabled TODO -void colorFromDecOrHexString(byte *rgb, char *in); -bool colorFromHexString(byte *rgb, const char *in); +#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) +uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); +uint32_t color_add(uint32_t,uint32_t, bool fast=false); +uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); +inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb +void colorKtoRGB(uint16_t kelvin, byte* rgb); +void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb +void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO +void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO +void colorFromDecOrHexString(byte* rgb, char* in); +bool colorFromHexString(byte* rgb, const char* in); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); -void setRandomColor(byte *rgb); +void setRandomColor(byte* rgb); -// dmx.cpp +//dmx.cpp void initDMX(); void handleDMX(); -// e131.cpp -void handleE131Packet(e131_packet_t *p, IPAddress clientIP, byte protocol); +//e131.cpp +void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); void handleArtnetPollReply(IPAddress ipAddress); -void prepareArtnetPollReply(ArtPollReply *reply); -void sendArtnetPollReply(ArtPollReply *reply, IPAddress ipAddress, uint16_t portAddress); - -// file.cpp -bool handleFileRead(AsyncWebServerRequest *, String path); -bool writeObjectToFileUsingId(const char *file, uint16_t id, JsonDocument *content); -bool writeObjectToFile(const char *file, const char *key, JsonDocument *content); -bool readObjectFromFileUsingId(const char *file, uint16_t id, JsonDocument *dest); -bool readObjectFromFile(const char *file, const char *key, JsonDocument *dest); +void prepareArtnetPollReply(ArtPollReply* reply); +void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress); + +//file.cpp +bool handleFileRead(AsyncWebServerRequest*, String path); +bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content); +bool writeObjectToFile(const char* file, const char* key, JsonDocument* content); +bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); +bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); void updateFSInfo(); void closeFile(); -// hue.cpp +//hue.cpp void handleHue(); void reconnectHue(); -void onHueError(void *arg, AsyncClient *client, int8_t error); -void onHueConnect(void *arg, AsyncClient *client); +void onHueError(void* arg, AsyncClient* client, int8_t error); +void onHueConnect(void* arg, AsyncClient* client); void sendHuePoll(); -void onHueData(void *arg, AsyncClient *client, void *data, size_t len); +void onHueData(void* arg, AsyncClient* client, void *data, size_t len); -// improv.cpp -enum ImprovRPCType -{ +//improv.cpp +enum ImprovRPCType { Command_Wifi = 0x01, Request_State = 0x02, Request_Info = 0x03, @@ -125,7 +120,7 @@ void startImprovWifiScan(); void handleImprovWifiScan(); void sendImprovIPRPCResult(ImprovRPCType type); -// ir.cpp +//ir.cpp void applyRepeatActions(); byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); void decodeIR(uint32_t code); @@ -142,7 +137,7 @@ void decodeIRJson(uint32_t code); void initIR(); void handleIR(); -// json.cpp +//json.cpp #include "ESPAsyncWebServer.h" #include "src/dependencies/json/ArduinoJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h" @@ -150,17 +145,17 @@ void handleIR(); bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0); bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0); -void serializeSegment(JsonObject &root, Segment &seg, byte id, bool forPreset = false, bool segmentBounds = true); +void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false); void serializeInfo(JsonObject root); void serializeModeNames(JsonArray root); void serializeModeData(JsonArray root); -void serveJson(AsyncWebServerRequest *request); +void serveJson(AsyncWebServerRequest* request); #ifdef WLED_ENABLE_JSONLIVE -bool serveLiveLeds(AsyncWebServerRequest *request, uint32_t wsClient = 0); +bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); #endif -// led.cpp +//led.cpp void setValuesFromSegment(uint8_t s); void setValuesFromMainSeg(); void setValuesFromFirstSelectedSeg(); @@ -177,22 +172,22 @@ void handleNightlight(); byte scaledBri(byte in); #ifdef WLED_ENABLE_LOXONE -// lx_parser.cpp -bool parseLx(int lxValue, byte *rgbw); +//lx_parser.cpp +bool parseLx(int lxValue, byte* rgbw); void parseLxJson(int lxValue, byte segId, bool secondary); #endif -// mqtt.cpp +//mqtt.cpp bool initMqtt(); void publishMqtt(); -// ntp.cpp +//ntp.cpp void handleTime(); void handleNetworkTime(); void sendNTPPacket(); bool checkNTPResponse(); void updateLocalTime(); -void getTimeString(char *out); +void getTimeString(char* out); bool checkCountdown(); void setCountdown(); byte weekdayMondayFirst(); @@ -200,40 +195,40 @@ void checkTimers(); void calculateSunriseAndSunset(); void setTimeFromAPI(uint32_t timein); -// overlay.cpp +//overlay.cpp void handleOverlayDraw(); void _overlayAnalogCountdown(); void _overlayAnalogClock(); -// playlist.cpp +//playlist.cpp void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); void handlePlaylist(); void serializePlaylist(JsonObject obj); -// presets.cpp +//presets.cpp void initPresetsFile(); void handlePresets(); bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE); void applyPresetWithFallback(uint8_t presetID, uint8_t callMode, uint8_t effectID = 0, uint8_t paletteID = 0); -inline bool applyTemporaryPreset() { return applyPreset(255); }; -void savePreset(byte index, const char *pname = nullptr, JsonObject saveobj = JsonObject()); -inline void saveTemporaryPreset() { savePreset(255); }; +inline bool applyTemporaryPreset() {return applyPreset(255);}; +void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject()); +inline void saveTemporaryPreset() {savePreset(255);}; void deletePreset(byte index); -bool getPresetName(byte index, String &name); +bool getPresetName(byte index, String& name); -// remote.cpp +//remote.cpp void handleRemote(); -// set.cpp -bool isAsterisksOnly(const char *str, byte maxLen); +//set.cpp +bool isAsterisksOnly(const char* str, byte maxLen); void handleSettingsSet(AsyncWebServerRequest *request, byte subPage); -bool handleSet(AsyncWebServerRequest *request, const String &req, bool apply = true); +bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true); -// udp.cpp -void notify(byte callMode, bool followUp = false); -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri = 255, bool isRGBW = false); +//udp.cpp +void notify(byte callMode, bool followUp=false); +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void exitRealtime(); void handleNotifications(); @@ -241,13 +236,12 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); void refreshNodeList(); void sendSysInfoUDP(); -// network.cpp +//network.cpp int getSignalQuality(int rssi); void WiFiEvent(WiFiEvent_t event); -// um_manager.cpp -typedef enum UM_Data_Types -{ +//um_manager.cpp +typedef enum UM_Data_Types { UMT_BYTE = 0, UMT_UINT16, UMT_INT16, @@ -263,211 +257,176 @@ typedef enum UM_Data_Types UMT_FLOAT_ARR, UMT_DOUBLE_ARR } um_types_t; -typedef struct UM_Exchange_Data -{ +typedef struct UM_Exchange_Data { // should just use: size_t arr_size, void **arr_ptr, byte *ptr_type - size_t u_size; // size of u_data array - um_types_t *u_type; // array of data types - void **u_data; // array of pointers to data - UM_Exchange_Data() - { + size_t u_size; // size of u_data array + um_types_t *u_type; // array of data types + void **u_data; // array of pointers to data + UM_Exchange_Data() { u_size = 0; u_type = nullptr; u_data = nullptr; } - ~UM_Exchange_Data() - { - if (u_type) - delete[] u_type; - if (u_data) - delete[] u_data; + ~UM_Exchange_Data() { + if (u_type) delete[] u_type; + if (u_data) delete[] u_data; } } um_data_t; -const unsigned int um_data_size = sizeof(um_data_t); // 12 bytes - -class Usermod -{ -protected: - um_data_t *um_data; // um_data should be allocated using new in (derived) Usermod's setup() or constructor -public: - Usermod() { um_data = nullptr; } - virtual ~Usermod() - { - if (um_data) - delete um_data; - } - virtual void setup() = 0; // pure virtual, has to be overriden - virtual void loop() = 0; // pure virtual, has to be overriden - virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show() - virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here - virtual bool getUMData(um_data_t **data) - { - if (data) - *data = nullptr; - return false; - }; // usermod data exchange [see examples for audio effects] - virtual void connected() {} // called when WiFi is (re)connected - virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields - virtual void addToJsonState(JsonObject &obj) {} // add JSON objects for WLED state - virtual void addToJsonInfo(JsonObject &obj) {} // add JSON objects for UI Info page - virtual void readFromJsonState(JsonObject &obj) {} // process JSON messages received from web server - virtual void addToConfig(JsonObject &obj) {} // add JSON entries that go to cfg.json - virtual bool readFromConfig(JsonObject &obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h - virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe) - virtual bool onMqttMessage(char *topic, char *payload) { return false; } // fired upon MQTT message received (wled topic) - virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update - virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change - virtual uint16_t getId() { return USERMOD_ID_UNSPECIFIED; } +const unsigned int um_data_size = sizeof(um_data_t); // 12 bytes + +class Usermod { + protected: + um_data_t *um_data; // um_data should be allocated using new in (derived) Usermod's setup() or constructor + public: + Usermod() { um_data = nullptr; } + virtual ~Usermod() { if (um_data) delete um_data; } + virtual void setup() = 0; // pure virtual, has to be overriden + virtual void loop() = 0; // pure virtual, has to be overriden + virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show() + virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here + virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] + virtual void connected() {} // called when WiFi is (re)connected + virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields + virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state + virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page + virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server + virtual void addToConfig(JsonObject& obj) {} // add JSON entries that go to cfg.json + virtual bool readFromConfig(JsonObject& obj) { return true; } // Note as of 2021-06 readFromConfig() now needs to return a bool, see usermod_v2_example.h + virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe) + virtual bool onMqttMessage(char* topic, char* payload) { return false; } // fired upon MQTT message received (wled topic) + virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update + virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change + virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} }; -class UsermodManager -{ -private: - Usermod *ums[WLED_MAX_USERMODS]; - byte numMods = 0; - -public: - void loop(); - void handleOverlayDraw(); - bool handleButton(uint8_t b); - bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods - void setup(); - void connected(); - void appendConfigData(); - void addToJsonState(JsonObject &obj); - void addToJsonInfo(JsonObject &obj); - void readFromJsonState(JsonObject &obj); - void addToConfig(JsonObject &obj); - bool readFromConfig(JsonObject &obj); - void onMqttConnect(bool sessionPresent); - bool onMqttMessage(char *topic, char *payload); - void onUpdateBegin(bool); - void onStateChange(uint8_t); - bool add(Usermod *um); - Usermod *lookup(uint16_t mod_id); - byte getModCount() { return numMods; }; +class UsermodManager { + private: + Usermod* ums[WLED_MAX_USERMODS]; + byte numMods = 0; + + public: + void loop(); + void handleOverlayDraw(); + bool handleButton(uint8_t b); + bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods + void setup(); + void connected(); + void appendConfigData(); + void addToJsonState(JsonObject& obj); + void addToJsonInfo(JsonObject& obj); + void readFromJsonState(JsonObject& obj); + void addToConfig(JsonObject& obj); + bool readFromConfig(JsonObject& obj); + void onMqttConnect(bool sessionPresent); + bool onMqttMessage(char* topic, char* payload); + void onUpdateBegin(bool); + void onStateChange(uint8_t); + bool add(Usermod* um); + Usermod* lookup(uint16_t mod_id); + byte getModCount() {return numMods;}; }; -// usermods_list.cpp +//usermods_list.cpp void registerUsermods(); -// usermod.cpp +//usermod.cpp void userSetup(); void userConnected(); void userLoop(); -// util.cpp -int getNumVal(const String *req, uint16_t pos); -void parseNumber(const char *str, byte *val, byte minv = 0, byte maxv = 255); -bool getVal(JsonVariant elem, byte *val, byte minv = 0, byte maxv = 255); -bool updateVal(const char *req, const char *key, byte *val, byte minv = 0, byte maxv = 255); -bool oappend(const char *txt); // append new c string to temp buffer efficiently +//util.cpp +int getNumVal(const String* req, uint16_t pos); +void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); +bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); +bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); +bool oappend(const char* txt); // append new c string to temp buffer efficiently bool oappendi(int i); // append new number to temp buffer efficiently -void sappend(char stype, const char *key, int val); -void sappends(char stype, const char *key, char *val); -void prepareHostname(char *hostname); -bool isAsterisksOnly(const char *str, byte maxLen); -bool requestJSONBufferLock(uint8_t module = 255); +void sappend(char stype, const char* key, int val); +void sappends(char stype, const char* key, char* val); +void prepareHostname(char* hostname); +bool isAsterisksOnly(const char* str, byte maxLen); +bool requestJSONBufferLock(uint8_t module=255); void releaseJSONBufferLock(); -bool requestResponseBufferLock(uint8_t module = 255); -void releaseResponseBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr); int16_t extractModeDefaults(uint8_t mode, const char *segVar); void checkSettingsPIN(const char *pin); -uint16_t crc16(const unsigned char *data_p, size_t length); -um_data_t *simulateSound(uint8_t simulationId); +uint16_t crc16(const unsigned char* data_p, size_t length); +um_data_t* simulateSound(uint8_t simulationId); void enumerateLedmaps(); uint8_t get_random_wheel_index(uint8_t pos); // RAII guard class for the JSON Buffer lock // Modeled after std::lock_guard -class JSONBufferGuard -{ +class JSONBufferGuard { bool holding_lock; - -public: - inline JSONBufferGuard(uint8_t module = 255) : holding_lock(requestJSONBufferLock(module)) {}; - inline ~JSONBufferGuard() - { - if (holding_lock) - releaseJSONBufferLock(); - }; - inline JSONBufferGuard(const JSONBufferGuard &) = delete; // Noncopyable - inline JSONBufferGuard &operator=(const JSONBufferGuard &) = delete; - inline JSONBufferGuard(JSONBufferGuard &&r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable - inline JSONBufferGuard &operator=(JSONBufferGuard &&r) - { - holding_lock |= r.holding_lock; - r.holding_lock = false; - return *this; - }; - inline bool owns_lock() const { return holding_lock; } - explicit inline operator bool() const { return owns_lock(); }; - inline void release() - { - if (holding_lock) - releaseJSONBufferLock(); - holding_lock = false; - } + public: + inline JSONBufferGuard(uint8_t module=255) : holding_lock(requestJSONBufferLock(module)) {}; + inline ~JSONBufferGuard() { if (holding_lock) releaseJSONBufferLock(); }; + inline JSONBufferGuard(const JSONBufferGuard&) = delete; // Noncopyable + inline JSONBufferGuard& operator=(const JSONBufferGuard&) = delete; + inline JSONBufferGuard(JSONBufferGuard&& r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable + inline JSONBufferGuard& operator=(JSONBufferGuard&& r) { holding_lock |= r.holding_lock; r.holding_lock = false; return *this; }; + inline bool owns_lock() const { return holding_lock; } + explicit inline operator bool() const { return owns_lock(); }; + inline void release() { if (holding_lock) releaseJSONBufferLock(); holding_lock = false; } }; #ifdef WLED_ADD_EEPROM_SUPPORT -// wled_eeprom.cpp +//wled_eeprom.cpp void applyMacro(byte index); void deEEP(); void deEEPSettings(); void clearEEPROM(); #endif -// wled_math.cpp +//wled_math.cpp #ifndef WLED_USE_REAL_MATH -template -T atan_t(T x); -float cos_t(float phi); -float sin_t(float x); -float tan_t(float x); -float acos_t(float x); -float asin_t(float x); -float floor_t(float x); -float fmod_t(float num, float denom); + template T atan_t(T x); + float cos_t(float phi); + float sin_t(float x); + float tan_t(float x); + float acos_t(float x); + float asin_t(float x); + float floor_t(float x); + float fmod_t(float num, float denom); #else -#include -#define sin_t sin -#define cos_t cos -#define tan_t tan -#define asin_t asin -#define acos_t acos -#define atan_t atan -#define fmod_t fmod -#define floor_t floor + #include + #define sin_t sin + #define cos_t cos + #define tan_t tan + #define asin_t asin + #define acos_t acos + #define atan_t atan + #define fmod_t fmod + #define floor_t floor #endif -// wled_serial.cpp +//wled_serial.cpp void handleSerial(); void updateBaudRate(uint32_t rate); -// wled_server.cpp +//wled_server.cpp bool isIp(String str); void createEditHandler(bool enable); bool captivePortal(AsyncWebServerRequest *request); void initServer(); void serveIndexOrWelcome(AsyncWebServerRequest *request); -void serveIndex(AsyncWebServerRequest *request); -String msgProcessor(const String &var); -void serveMessage(AsyncWebServerRequest *request, uint16_t code, const String &headl, const String &subl = "", byte optionT = 255); -String dmxProcessor(const String &var); -void serveSettings(AsyncWebServerRequest *request, bool post = false); -void serveSettingsJS(AsyncWebServerRequest *request); - -// ws.cpp +void serveIndex(AsyncWebServerRequest* request); +String msgProcessor(const String& var); +void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255); +String dmxProcessor(const String& var); +void serveSettings(AsyncWebServerRequest* request, bool post = false); +void serveSettingsJS(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); +void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); +void sendDataWs(AsyncWebSocketClient * client = nullptr); -// xml.cpp -void XML_response(AsyncWebServerRequest *request, char *dest = nullptr); +//xml.cpp +void XML_response(AsyncWebServerRequest *request, char* dest = nullptr); void URL_response(AsyncWebServerRequest *request); -void getSettingsJS(byte subPage, char *dest); +void getSettingsJS(byte subPage, char* dest); #endif diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 328cbec07b..a5caaf472e 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -1,45 +1,31 @@ #include "wled.h" -#include /* * MQTT communication protocol for home automation */ #ifdef WLED_ENABLE_MQTT -#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds +#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds -// declaring this function up here -void otaUpdate(String url); - -void parseMQTTBriPayload(char *payload) +void parseMQTTBriPayload(char* payload) { - if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) - { - bri = briLast; - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - else if (strstr(payload, "T") || strstr(payload, "t")) - { - toggleOnOff(); - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - else - { + if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} + else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);} + else { uint8_t in = strtoul(payload, NULL, 10); - if (in == 0 && bri > 0) - briLast = bri; + if (in == 0 && bri > 0) briLast = bri; bri = in; stateUpdated(CALL_MODE_DIRECT_CHANGE); } } + void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics char subuf[38]; - if (mqttDeviceTopic[0] != 0) - { + if (mqttDeviceTopic[0] != 0) { strlcpy(subuf, mqttDeviceTopic, 33); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); @@ -47,13 +33,9 @@ void onMqttConnect(bool sessionPresent) strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/update")); - mqtt->subscribe(subuf, 0); } - if (mqttGroupTopic[0] != 0) - { + if (mqttGroupTopic[0] != 0) { strlcpy(subuf, mqttGroupTopic, 33); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); @@ -69,60 +51,44 @@ void onMqttConnect(bool sessionPresent) DEBUG_PRINTLN(F("MQTT ready")); } -void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) -{ + +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { static char *payloadStr; DEBUG_PRINT(F("MQTT msg: ")); DEBUG_PRINTLN(topic); - // set connected to true. If we got a message, we must be connected (this fixes a lot of issues with AsyncMqttClient) - mqtt->setConnected(true); // note that setConnected is a function that I added to AsyncMqttClient - // paranoia check to avoid npe if no payload - if (payload == nullptr) - { + if (payload==nullptr) { DEBUG_PRINTLN(F("no payload -> leave")); return; } - if (index == 0) - { // start (1st partial packet or the only packet) - if (payloadStr) - delete[] payloadStr; // fail-safe: release buffer - payloadStr = new char[total + 1]; // allocate new buffer + if (index == 0) { // start (1st partial packet or the only packet) + if (payloadStr) delete[] payloadStr; // fail-safe: release buffer + payloadStr = new char[total+1]; // allocate new buffer } - if (payloadStr == nullptr) - return; // buffer not allocated + if (payloadStr == nullptr) return; // buffer not allocated // copy (partial) packet to buffer and 0-terminate it if it is last packet - char *buff = payloadStr + index; + char* buff = payloadStr + index; memcpy(buff, payload, len); - if (index + len >= total) - { // at end + if (index + len >= total) { // at end payloadStr[total] = '\0'; // terminate c style string - } - else - { + } else { DEBUG_PRINTLN(F("Partial packet received.")); return; // process next packet } DEBUG_PRINTLN(payloadStr); size_t topicPrefixLen = strlen(mqttDeviceTopic); - if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) - { + if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) { topic += topicPrefixLen; - } - else - { + } else { topicPrefixLen = strlen(mqttGroupTopic); - if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) - { + if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) { topic += topicPrefixLen; - } - else - { + } else { // Non-Wled Topic used here. Probably a usermod subscribed to this topic. usermods.onMqttMessage(topic, payloadStr); delete[] payloadStr; @@ -131,100 +97,30 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties } } - // Prefix is stripped from the topic at this point + //Prefix is stripped from the topic at this point - if (strcmp_P(topic, PSTR("/col")) == 0) - { + if (strcmp_P(topic, PSTR("/col")) == 0) { colorFromDecOrHexString(col, payloadStr); colorUpdated(CALL_MODE_DIRECT_CHANGE); - } - else if (strcmp_P(topic, PSTR("/api")) == 0) - { - if (!requestJSONBufferLock(15)) - { + } else if (strcmp_P(topic, PSTR("/api")) == 0) { + if (!requestJSONBufferLock(15)) { delete[] payloadStr; payloadStr = nullptr; return; } - if (payloadStr[0] == '{') - { // JSON API + if (payloadStr[0] == '{') { //JSON API deserializeJson(doc, payloadStr); deserializeState(doc.as()); - } - else - { // HTTP API - String apireq = "win"; - apireq += '&'; // reduce flash string usage + } else { //HTTP API + String apireq = "win"; apireq += '&'; // reduce flash string usage apireq += payloadStr; handleSet(nullptr, apireq); } releaseJSONBufferLock(); - } - else if (strcmp_P(topic, PSTR("/update")) == 0) - { - // get the json buffer lock - if (!requestJSONBufferLock(15)) - { - delete[] payloadStr; - payloadStr = nullptr; - return; - } - - // deserialize the request - deserializeJson(doc, payloadStr); - JsonObject obj = doc.as(); - - // make sure the request has a url - if (!obj.containsKey("url") || !obj["url"].is()) - { - DEBUG_PRINTLN("No url in request, won't update. Returning."); - // release the json buffer lock - releaseJSONBufferLock(); - // clear out the payload string - delete[] payloadStr; - payloadStr = nullptr; - return; - } - - // get the url - String url = obj["url"].as(); - - // request the response buffer lock - if (!requestResponseBufferLock()) - { - DEBUG_PRINTLN("Failed to get response buffer lock, returning."); - // release the json buffer lock - releaseJSONBufferLock(); - // clear out the payload string - delete[] payloadStr; - payloadStr = nullptr; - return; - } - - // make the response - mqttResponseDoc["id"] = obj["id"]; - mqttResponseDoc["update"] = "Starting update, do not power off the device."; - serializeJson(mqttResponseDoc, mqttResponseBuffer); - - // release the json buffer lock - releaseJSONBufferLock(); - - // send the response - mqtt->publish(mqttResponseTopic, 1, false, mqttResponseBuffer); - - // release the response buffer lock - releaseResponseBufferLock(); - - // do the update - return otaUpdate(url); - } - else if (strlen(topic) != 0) - { + } else if (strlen(topic) != 0) { // non standard topic, check with usermods usermods.onMqttMessage(topic, payloadStr); - } - else - { + } else { // topmost topic (just wled/MAC) parseMQTTBriPayload(payloadStr); } @@ -232,229 +128,71 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties payloadStr = nullptr; } + void publishMqtt() { doPublishMqtt = false; - if (!WLED_MQTT_CONNECTED) - return; + if (!WLED_MQTT_CONNECTED) return; DEBUG_PRINTLN(F("Publish MQTT")); -#ifndef USERMOD_SMARTNEST + #ifndef USERMOD_SMARTNEST char s[10]; char subuf[38]; sprintf_P(s, PSTR("%u"), bri); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/g")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/c")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/status")); - mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT - char apires[1024]; // allocating 1024 bytes from stack can be risky + char apires[1024]; // allocating 1024 bytes from stack can be risky XML_response(nullptr, apires); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/v")); - mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) -#endif + mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) + #endif } -// HA autodiscovery was removed in favor of the native integration in HA v0.102.0 + +//HA autodiscovery was removed in favor of the native integration in HA v0.102.0 bool initMqtt() { - DEBUG_PRINTLN(F("Initializing MQTT")); - // set the important variables - mqttEnabled = true; - strlcpy(mqttServer, "my-server-name-here", MQTT_MAX_SERVER_LEN + 1); // put actual mqtt server here, I use emqx - mqttPort = 0; // put actual port here - strlcpy(mqttUser, "username", 41); // put actual username here - strlcpy(mqttPass, "password", 65); // put actual password here - - if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) - return false; + if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; - if (mqtt == nullptr) - { + if (mqtt == nullptr) { mqtt = new AsyncMqttClient(); mqtt->onMessage(onMqttMessage); mqtt->onConnect(onMqttConnect); } - if (mqtt->connected()) - return true; + if (mqtt->connected()) return true; - DEBUG_PRINTLN(F("Reconnecting MQTT with info:")); - DEBUG_PRINTLN(mqttServer); - DEBUG_PRINTLN(mqttPort); - DEBUG_PRINTLN(mqttUser); - DEBUG_PRINTLN(mqttPass); + DEBUG_PRINTLN(F("Reconnecting MQTT")); IPAddress mqttIP; - if (mqttIP.fromString(mqttServer)) // see if server is IP or domain + if (mqttIP.fromString(mqttServer)) //see if server is IP or domain { mqtt->setServer(mqttIP, mqttPort); - } - else - { + } else { mqtt->setServer(mqttServer, mqttPort); } mqtt->setClientId(mqttClientID); - if (mqttUser[0] && mqttPass[0]) - mqtt->setCredentials(mqttUser, mqttPass); + if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); -#ifndef USERMOD_SMARTNEST + #ifndef USERMOD_SMARTNEST strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); strcat_P(mqttStatusTopic, PSTR("/status")); mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message -#endif + #endif mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); mqtt->connect(); return true; } - -void otaUpdate(String url) -{ - DEBUG_PRINT(F("OTA update from URL: ")); - DEBUG_PRINTLN(url); - - // make client for HTTP request - HTTPClient http; - http.begin(url); - http.setTimeout(3000000); // 5 minute timeout, may change - - // do a get request to get the update binary - int httpCode = http.GET(); - // make sure the request was successful - if (httpCode != HTTP_CODE_OK) - { - DEBUG_PRINT(F("HTTP GET failed, code: ")); - DEBUG_PRINTLN(httpCode); - http.end(); - return; - } - - // disable the watchdog - WLED::instance().disableWatchdog(); - otaInProgress = true; // I've tried both with and without this and neither works - - // get the size of the update - int len = http.getSize(); - DEBUG_PRINT(F("Update size: ")); - DEBUG_PRINTLN(len); - - // make a buffer for reading - WiFiClient *stream = http.getStreamPtr(); - - DEBUG_PRINTLN("Got stream"); - - // Initialize Update - if (!Update.begin(len)) - { - DEBUG_PRINTLN(F("Update.begin failed, most likely not enough space")); - http.end(); - WLED::instance().enableWatchdog(); - otaInProgress = false; - return; - } - - DEBUG_PRINTLN("Update.begin succeeded"); - DEBUG_PRINTLN("Is the stream null?"); - DEBUG_PRINTLN(stream == nullptr); - DEBUG_PRINT(F("Free Heap: ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); - - // write the update to the device - size_t written = 0; - int bufferSize = 512; - uint8_t buffer[bufferSize]; - // size_t written = Update.writeStream(*stream); - while (http.connected() && written < len) - { - if (stream->available()) - { - int bytesRead = stream->readBytes(buffer, bufferSize); - if (bytesRead == 0) - { - DEBUG_PRINTLN("No bytes read"); - } - written += Update.write(buffer, bytesRead); - DEBUG_PRINT("Bytes written: "); - DEBUG_PRINTLN(written); - if (ESP.getFreeHeap() < 80000) - { - DEBUG_PRINT(F("Free Heap below 80000: ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); - } - if (http.connected() != 1) - { - DEBUG_PRINT("http Connection status: "); - DEBUG_PRINTLN(http.connected()); - } - if (WiFi.status() != 3) - { - DEBUG_PRINT("Wifi status: "); - DEBUG_PRINTLN(WiFi.status()); - } - } - else - { - DEBUG_PRINTLN("No bytes available"); - } - delay(10); - } - - DEBUG_PRINTLN("Wrote stream"); - - // check if the update was successful - if (written == len) - { - DEBUG_PRINTLN(F("Written to flash successfully")); - } - else - { - DEBUG_PRINT(F("Update failed, only wrote : ")); - DEBUG_PRINT(written); - DEBUG_PRINTLN(F(" bytes")); - http.end(); - WLED::instance().enableWatchdog(); - otaInProgress = false; - return; - } - - // End the update process - if (Update.end()) - { - if (Update.isFinished()) - { - DEBUG_PRINTLN(F("Update finished successfully, restarting now")); - http.end(); - delay(1000); - ESP.restart(); - } - else - { - DEBUG_PRINTLN(F("Update not finished, something went wrong!")); - } - } - else - { - DEBUG_PRINT(F("OTA Error Occurred. Error: ")); - DEBUG_PRINT(Update.errorString()); - DEBUG_PRINT(" Code: "); - DEBUG_PRINTLN(Update.getError()); - } - - // reenable the watchdog - WLED::instance().enableWatchdog(); - // end the http request - http.end(); - // set ota in progress to false - otaInProgress = false; -} - #endif diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp index def0b52ab9..d0c44cb6ba 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp @@ -1,28 +1,40 @@ #include "AsyncMqttClient.hpp" AsyncMqttClient::AsyncMqttClient() - : _connected(false), _connectPacketNotEnoughSpace(false), _disconnectFlagged(false), _tlsBadFingerprint(false), _lastClientActivity(0), _lastServerActivity(0), _lastPingRequestTime(0), _host(nullptr), _useIp(false) +: _connected(false) +, _connectPacketNotEnoughSpace(false) +, _disconnectFlagged(false) +, _tlsBadFingerprint(false) +, _lastClientActivity(0) +, _lastServerActivity(0) +, _lastPingRequestTime(0) +, _host(nullptr) +, _useIp(false) #if ASYNC_TCP_SSL_ENABLED - , - _secure(false) +, _secure(false) #endif - , - _port(0), _keepAlive(15), _cleanSession(true), _clientId(nullptr), _username(nullptr), _password(nullptr), _willTopic(nullptr), _willPayload(nullptr), _willPayloadLength(0), _willQos(0), _willRetain(false), _parsingInformation{.bufferState = AsyncMqttClientInternals::BufferState::NONE}, _currentParsedPacket(nullptr), _remainingLengthBufferPosition(0), _nextPacketId(1) -{ - _client.onConnect([](void *obj, AsyncClient *c) - { (static_cast(obj))->_onConnect(c); }, this); - _client.onDisconnect([](void *obj, AsyncClient *c) - { (static_cast(obj))->_onDisconnect(c); }, this); - _client.onError([](void *obj, AsyncClient *c, int8_t error) - { (static_cast(obj))->_onError(c, error); }, this); - _client.onTimeout([](void *obj, AsyncClient *c, uint32_t time) - { (static_cast(obj))->_onTimeout(c, time); }, this); - _client.onAck([](void *obj, AsyncClient *c, size_t len, uint32_t time) - { (static_cast(obj))->_onAck(c, len, time); }, this); - _client.onData([](void *obj, AsyncClient *c, void *data, size_t len) - { (static_cast(obj))->_onData(c, static_cast(data), len); }, this); - _client.onPoll([](void *obj, AsyncClient *c) - { (static_cast(obj))->_onPoll(c); }, this); +, _port(0) +, _keepAlive(15) +, _cleanSession(true) +, _clientId(nullptr) +, _username(nullptr) +, _password(nullptr) +, _willTopic(nullptr) +, _willPayload(nullptr) +, _willPayloadLength(0) +, _willQos(0) +, _willRetain(false) +, _parsingInformation { .bufferState = AsyncMqttClientInternals::BufferState::NONE } +, _currentParsedPacket(nullptr) +, _remainingLengthBufferPosition(0) +, _nextPacketId(1) { + _client.onConnect([](void* obj, AsyncClient* c) { (static_cast(obj))->_onConnect(c); }, this); + _client.onDisconnect([](void* obj, AsyncClient* c) { (static_cast(obj))->_onDisconnect(c); }, this); + _client.onError([](void* obj, AsyncClient* c, int8_t error) { (static_cast(obj))->_onError(c, error); }, this); + _client.onTimeout([](void* obj, AsyncClient* c, uint32_t time) { (static_cast(obj))->_onTimeout(c, time); }, this); + _client.onAck([](void* obj, AsyncClient* c, size_t len, uint32_t time) { (static_cast(obj))->_onAck(c, len, time); }, this); + _client.onData([](void* obj, AsyncClient* c, void* data, size_t len) { (static_cast(obj))->_onData(c, static_cast(data), len); }, this); + _client.onPoll([](void* obj, AsyncClient* c) { (static_cast(obj))->_onPoll(c); }, this); #ifdef ESP32 sprintf(_generatedClientId, "esp32%06x", (uint32_t)ESP.getEfuseMac()); @@ -35,8 +47,7 @@ AsyncMqttClient::AsyncMqttClient() setMaxTopicLength(128); } -AsyncMqttClient::~AsyncMqttClient() -{ +AsyncMqttClient::~AsyncMqttClient() { delete _currentParsedPacket; delete[] _parsingInformation.topicBuffer; #ifdef ESP32 @@ -44,41 +55,35 @@ AsyncMqttClient::~AsyncMqttClient() #endif } -AsyncMqttClient &AsyncMqttClient::setKeepAlive(uint16_t keepAlive) -{ +AsyncMqttClient& AsyncMqttClient::setKeepAlive(uint16_t keepAlive) { _keepAlive = keepAlive; return *this; } -AsyncMqttClient &AsyncMqttClient::setClientId(const char *clientId) -{ +AsyncMqttClient& AsyncMqttClient::setClientId(const char* clientId) { _clientId = clientId; return *this; } -AsyncMqttClient &AsyncMqttClient::setCleanSession(bool cleanSession) -{ +AsyncMqttClient& AsyncMqttClient::setCleanSession(bool cleanSession) { _cleanSession = cleanSession; return *this; } -AsyncMqttClient &AsyncMqttClient::setMaxTopicLength(uint16_t maxTopicLength) -{ +AsyncMqttClient& AsyncMqttClient::setMaxTopicLength(uint16_t maxTopicLength) { _parsingInformation.maxTopicLength = maxTopicLength; delete[] _parsingInformation.topicBuffer; _parsingInformation.topicBuffer = new char[maxTopicLength + 1]; return *this; } -AsyncMqttClient &AsyncMqttClient::setCredentials(const char *username, const char *password) -{ +AsyncMqttClient& AsyncMqttClient::setCredentials(const char* username, const char* password) { _username = username; _password = password; return *this; } -AsyncMqttClient &AsyncMqttClient::setWill(const char *topic, uint8_t qos, bool retain, const char *payload, size_t length) -{ +AsyncMqttClient& AsyncMqttClient::setWill(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length) { _willTopic = topic; _willQos = qos; _willRetain = retain; @@ -87,16 +92,14 @@ AsyncMqttClient &AsyncMqttClient::setWill(const char *topic, uint8_t qos, bool r return *this; } -AsyncMqttClient &AsyncMqttClient::setServer(IPAddress ip, uint16_t port) -{ +AsyncMqttClient& AsyncMqttClient::setServer(IPAddress ip, uint16_t port) { _useIp = true; _ip = ip; _port = port; return *this; } -AsyncMqttClient &AsyncMqttClient::setServer(const char *host, uint16_t port) -{ +AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) { _useIp = false; _host = host; _port = port; @@ -104,14 +107,12 @@ AsyncMqttClient &AsyncMqttClient::setServer(const char *host, uint16_t port) } #if ASYNC_TCP_SSL_ENABLED -AsyncMqttClient &AsyncMqttClient::setSecure(bool secure) -{ +AsyncMqttClient& AsyncMqttClient::setSecure(bool secure) { _secure = secure; return *this; } -AsyncMqttClient &AsyncMqttClient::addServerFingerprint(const uint8_t *fingerprint) -{ +AsyncMqttClient& AsyncMqttClient::addServerFingerprint(const uint8_t* fingerprint) { std::array newFingerprint; memcpy(newFingerprint.data(), fingerprint, SHA1_SIZE); _secureServerFingerprints.push_back(newFingerprint); @@ -119,52 +120,43 @@ AsyncMqttClient &AsyncMqttClient::addServerFingerprint(const uint8_t *fingerprin } #endif -AsyncMqttClient &AsyncMqttClient::onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback) { _onConnectUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient &AsyncMqttClient::onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback) { _onDisconnectUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient &AsyncMqttClient::onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback) { _onSubscribeUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient &AsyncMqttClient::onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback) { _onUnsubscribeUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient &AsyncMqttClient::onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback) { _onMessageUserCallbacks.push_back(callback); return *this; } -AsyncMqttClient &AsyncMqttClient::onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback) -{ +AsyncMqttClient& AsyncMqttClient::onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback) { _onPublishUserCallbacks.push_back(callback); return *this; } -void AsyncMqttClient::_freeCurrentParsedPacket() -{ +void AsyncMqttClient::_freeCurrentParsedPacket() { delete _currentParsedPacket; _currentParsedPacket = nullptr; } -void AsyncMqttClient::_clear() -{ +void AsyncMqttClient::_clear() { _lastPingRequestTime = 0; - Serial.println("SETTING CONNECTED TO FALSE"); _connected = false; _disconnectFlagged = false; _connectPacketNotEnoughSpace = false; @@ -182,27 +174,22 @@ void AsyncMqttClient::_clear() } /* TCP */ -void AsyncMqttClient::_onConnect(AsyncClient *client) -{ +void AsyncMqttClient::_onConnect(AsyncClient* client) { (void)client; #if ASYNC_TCP_SSL_ENABLED - if (_secure && _secureServerFingerprints.size() > 0) - { - SSL *clientSsl = _client.getSSL(); + if (_secure && _secureServerFingerprints.size() > 0) { + SSL* clientSsl = _client.getSSL(); bool sslFoundFingerprint = false; - for (std::array fingerprint : _secureServerFingerprints) - { - if (ssl_match_fingerprint(clientSsl, fingerprint.data()) == SSL_OK) - { + for (std::array fingerprint : _secureServerFingerprints) { + if (ssl_match_fingerprint(clientSsl, fingerprint.data()) == SSL_OK) { sslFoundFingerprint = true; break; } } - if (!sslFoundFingerprint) - { + if (!sslFoundFingerprint) { _tlsBadFingerprint = true; _client.close(true); return; @@ -211,7 +198,6 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) #endif char fixedHeader[5]; - Serial.println("CONNECTED CALLBACK"); fixedHeader[0] = AsyncMqttClientInternals::PacketType.CONNECT; fixedHeader[0] = fixedHeader[0] << 4; fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.CONNECT_RESERVED; @@ -226,28 +212,22 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) char connectFlags[1]; connectFlags[0] = 0; - if (_cleanSession) - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION; - if (_username != nullptr) - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME; - if (_password != nullptr) - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD; - if (_willTopic != nullptr) - { + if (_cleanSession) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION; + if (_username != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME; + if (_password != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD; + if (_willTopic != nullptr) { connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL; - if (_willRetain) - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN; - switch (_willQos) - { - case 0: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0; - break; - case 1: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1; - break; - case 2: - connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2; - break; + if (_willRetain) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN; + switch (_willQos) { + case 0: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0; + break; + case 1: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1; + break; + case 2: + connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2; + break; } } @@ -265,14 +245,12 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) char willTopicLengthBytes[2]; uint16_t willPayloadLength = _willPayloadLength; char willPayloadLengthBytes[2]; - if (_willTopic != nullptr) - { + if (_willTopic != nullptr) { willTopicLength = strlen(_willTopic); willTopicLengthBytes[0] = willTopicLength >> 8; willTopicLengthBytes[1] = willTopicLength & 0xFF; - if (_willPayload != nullptr && willPayloadLength == 0) - willPayloadLength = strlen(_willPayload); + if (_willPayload != nullptr && willPayloadLength == 0) willPayloadLength = strlen(_willPayload); willPayloadLengthBytes[0] = willPayloadLength >> 8; willPayloadLengthBytes[1] = willPayloadLength & 0xFF; @@ -280,8 +258,7 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) uint16_t usernameLength = 0; char usernameLengthBytes[2]; - if (_username != nullptr) - { + if (_username != nullptr) { usernameLength = strlen(_username); usernameLengthBytes[0] = usernameLength >> 8; usernameLengthBytes[1] = usernameLength & 0xFF; @@ -289,20 +266,16 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) uint16_t passwordLength = 0; char passwordLengthBytes[2]; - if (_password != nullptr) - { + if (_password != nullptr) { passwordLength = strlen(_password); passwordLengthBytes[0] = passwordLength >> 8; passwordLengthBytes[1] = passwordLength & 0xFF; } - uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present - if (_willTopic != nullptr) - remainingLength += 2 + willTopicLength + 2 + willPayloadLength; - if (_username != nullptr) - remainingLength += 2 + usernameLength; - if (_password != nullptr) - remainingLength += 2 + passwordLength; + uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present + if (_willTopic != nullptr) remainingLength += 2 + willTopicLength + 2 + willPayloadLength; + if (_username != nullptr) remainingLength += 2 + usernameLength; + if (_password != nullptr) remainingLength += 2 + passwordLength; uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1); uint32_t neededSpace = 1 + remainingLengthLength; @@ -313,29 +286,24 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) neededSpace += 2; neededSpace += 2; neededSpace += clientIdLength; - if (_willTopic != nullptr) - { + if (_willTopic != nullptr) { neededSpace += 2; neededSpace += willTopicLength; neededSpace += 2; - if (_willPayload != nullptr) - neededSpace += willPayloadLength; + if (_willPayload != nullptr) neededSpace += willPayloadLength; } - if (_username != nullptr) - { + if (_username != nullptr) { neededSpace += 2; neededSpace += usernameLength; } - if (_password != nullptr) - { + if (_password != nullptr) { neededSpace += 2; neededSpace += passwordLength; } SEMAPHORE_TAKE(); - if (_client.space() < neededSpace) - { + if (_client.space() < neededSpace) { _connectPacketNotEnoughSpace = true; _client.close(true); SEMAPHORE_GIVE(); @@ -350,22 +318,18 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) _client.add(keepAliveBytes, 2); _client.add(clientIdLengthBytes, 2); _client.add(_clientId, clientIdLength); - if (_willTopic != nullptr) - { + if (_willTopic != nullptr) { _client.add(willTopicLengthBytes, 2); _client.add(_willTopic, willTopicLength); _client.add(willPayloadLengthBytes, 2); - if (_willPayload != nullptr) - _client.add(_willPayload, willPayloadLength); + if (_willPayload != nullptr) _client.add(_willPayload, willPayloadLength); } - if (_username != nullptr) - { + if (_username != nullptr) { _client.add(usernameLengthBytes, 2); _client.add(_username, usernameLength); } - if (_password != nullptr) - { + if (_password != nullptr) { _client.add(passwordLengthBytes, 2); _client.add(_password, passwordLength); } @@ -374,152 +338,125 @@ void AsyncMqttClient::_onConnect(AsyncClient *client) SEMAPHORE_GIVE(); } -void AsyncMqttClient::_onDisconnect(AsyncClient *client) -{ - Serial.println("DISCONNECTED CALLBACK, Will set connected to false"); +void AsyncMqttClient::_onDisconnect(AsyncClient* client) { (void)client; - if (!_disconnectFlagged) - { + if (!_disconnectFlagged) { AsyncMqttClientDisconnectReason reason; - if (_connectPacketNotEnoughSpace) - { + if (_connectPacketNotEnoughSpace) { reason = AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE; - } - else if (_tlsBadFingerprint) - { + } else if (_tlsBadFingerprint) { reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT; - } - else - { + } else { reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED; } - for (auto callback : _onDisconnectUserCallbacks) - callback(reason); + for (auto callback : _onDisconnectUserCallbacks) callback(reason); } _clear(); } -void AsyncMqttClient::_onError(AsyncClient *client, int8_t error) -{ +void AsyncMqttClient::_onError(AsyncClient* client, int8_t error) { (void)client; (void)error; // _onDisconnect called anyway } -void AsyncMqttClient::_onTimeout(AsyncClient *client, uint32_t time) -{ +void AsyncMqttClient::_onTimeout(AsyncClient* client, uint32_t time) { (void)client; (void)time; // disconnection will be handled by ping/pong management } -void AsyncMqttClient::_onAck(AsyncClient *client, size_t len, uint32_t time) -{ +void AsyncMqttClient::_onAck(AsyncClient* client, size_t len, uint32_t time) { (void)client; (void)len; (void)time; } -void AsyncMqttClient::_onData(AsyncClient *client, char *data, size_t len) -{ +void AsyncMqttClient::_onData(AsyncClient* client, char* data, size_t len) { (void)client; size_t currentBytePosition = 0; char currentByte; - do - { - switch (_parsingInformation.bufferState) - { - case AsyncMqttClientInternals::BufferState::NONE: - currentByte = data[currentBytePosition++]; - _parsingInformation.packetType = currentByte >> 4; - _parsingInformation.packetFlags = (currentByte << 4) >> 4; - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::REMAINING_LENGTH; - _lastServerActivity = millis(); - switch (_parsingInformation.packetType) - { - case AsyncMqttClientInternals::PacketType.CONNACK: - _currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.PINGRESP: - _currentParsedPacket = new AsyncMqttClientInternals::PingRespPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPingResp, this)); - break; - case AsyncMqttClientInternals::PacketType.SUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::SubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onSubAck, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.UNSUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::UnsubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onUnsubAck, this, std::placeholders::_1)); - break; - case AsyncMqttClientInternals::PacketType.PUBLISH: - _currentParsedPacket = new AsyncMqttClientInternals::PublishPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), std::bind(&AsyncMqttClient::_onPublish, this, std::placeholders::_1, std::placeholders::_2)); - break; - case AsyncMqttClientInternals::PacketType.PUBREL: - _currentParsedPacket = new AsyncMqttClientInternals::PubRelPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRel, this, std::placeholders::_1)); + do { + switch (_parsingInformation.bufferState) { + case AsyncMqttClientInternals::BufferState::NONE: + currentByte = data[currentBytePosition++]; + _parsingInformation.packetType = currentByte >> 4; + _parsingInformation.packetFlags = (currentByte << 4) >> 4; + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::REMAINING_LENGTH; + _lastServerActivity = millis(); + switch (_parsingInformation.packetType) { + case AsyncMqttClientInternals::PacketType.CONNACK: + _currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2)); + break; + case AsyncMqttClientInternals::PacketType.PINGRESP: + _currentParsedPacket = new AsyncMqttClientInternals::PingRespPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPingResp, this)); + break; + case AsyncMqttClientInternals::PacketType.SUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::SubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onSubAck, this, std::placeholders::_1, std::placeholders::_2)); + break; + case AsyncMqttClientInternals::PacketType.UNSUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::UnsubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onUnsubAck, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBLISH: + _currentParsedPacket = new AsyncMqttClientInternals::PublishPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), std::bind(&AsyncMqttClient::_onPublish, this, std::placeholders::_1, std::placeholders::_2)); + break; + case AsyncMqttClientInternals::PacketType.PUBREL: + _currentParsedPacket = new AsyncMqttClientInternals::PubRelPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRel, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBACK: + _currentParsedPacket = new AsyncMqttClientInternals::PubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubAck, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBREC: + _currentParsedPacket = new AsyncMqttClientInternals::PubRecPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRec, this, std::placeholders::_1)); + break; + case AsyncMqttClientInternals::PacketType.PUBCOMP: + _currentParsedPacket = new AsyncMqttClientInternals::PubCompPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubComp, this, std::placeholders::_1)); + break; + default: + break; + } break; - case AsyncMqttClientInternals::PacketType.PUBACK: - _currentParsedPacket = new AsyncMqttClientInternals::PubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubAck, this, std::placeholders::_1)); + case AsyncMqttClientInternals::BufferState::REMAINING_LENGTH: + currentByte = data[currentBytePosition++]; + _remainingLengthBuffer[_remainingLengthBufferPosition++] = currentByte; + if (currentByte >> 7 == 0) { + _parsingInformation.remainingLength = AsyncMqttClientInternals::Helpers::decodeRemainingLength(_remainingLengthBuffer); + _remainingLengthBufferPosition = 0; + if (_parsingInformation.remainingLength > 0) { + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::VARIABLE_HEADER; + } else { + // PINGRESP is a special case where it has no variable header, so the packet ends right here + _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE; + _onPingResp(); + } + } break; - case AsyncMqttClientInternals::PacketType.PUBREC: - _currentParsedPacket = new AsyncMqttClientInternals::PubRecPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRec, this, std::placeholders::_1)); + case AsyncMqttClientInternals::BufferState::VARIABLE_HEADER: + _currentParsedPacket->parseVariableHeader(data, len, ¤tBytePosition); break; - case AsyncMqttClientInternals::PacketType.PUBCOMP: - _currentParsedPacket = new AsyncMqttClientInternals::PubCompPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubComp, this, std::placeholders::_1)); + case AsyncMqttClientInternals::BufferState::PAYLOAD: + _currentParsedPacket->parsePayload(data, len, ¤tBytePosition); break; default: - break; - } - break; - case AsyncMqttClientInternals::BufferState::REMAINING_LENGTH: - currentByte = data[currentBytePosition++]; - _remainingLengthBuffer[_remainingLengthBufferPosition++] = currentByte; - if (currentByte >> 7 == 0) - { - _parsingInformation.remainingLength = AsyncMqttClientInternals::Helpers::decodeRemainingLength(_remainingLengthBuffer); - _remainingLengthBufferPosition = 0; - if (_parsingInformation.remainingLength > 0) - { - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::VARIABLE_HEADER; - } - else - { - // PINGRESP is a special case where it has no variable header, so the packet ends right here - _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE; - _onPingResp(); - } - } - break; - case AsyncMqttClientInternals::BufferState::VARIABLE_HEADER: - _currentParsedPacket->parseVariableHeader(data, len, ¤tBytePosition); - break; - case AsyncMqttClientInternals::BufferState::PAYLOAD: - _currentParsedPacket->parsePayload(data, len, ¤tBytePosition); - break; - default: - currentBytePosition = len; + currentBytePosition = len; } } while (currentBytePosition != len); } -void AsyncMqttClient::_onPoll(AsyncClient *client) -{ - if (!_connected) - return; +void AsyncMqttClient::_onPoll(AsyncClient* client) { + if (!_connected) return; // if there is too much time the client has sent a ping request without a response, disconnect client to avoid half open connections - if (_lastPingRequestTime != 0 && (millis() - _lastPingRequestTime) >= (_keepAlive * 1000 * 2)) - { + if (_lastPingRequestTime != 0 && (millis() - _lastPingRequestTime) >= (_keepAlive * 1000 * 2)) { disconnect(); return; - // send ping to ensure the server will receive at least one message inside keepalive window - } - else if (_lastPingRequestTime == 0 && (millis() - _lastClientActivity) >= (_keepAlive * 1000 * 0.7)) - { + // send ping to ensure the server will receive at least one message inside keepalive window + } else if (_lastPingRequestTime == 0 && (millis() - _lastClientActivity) >= (_keepAlive * 1000 * 0.7)) { _sendPing(); - // send ping to verify if the server is still there (ensure this is not a half connection) - } - else if (_connected && _lastPingRequestTime == 0 && (millis() - _lastServerActivity) >= (_keepAlive * 1000 * 0.7)) - { + // send ping to verify if the server is still there (ensure this is not a half connection) + } else if (_connected && _lastPingRequestTime == 0 && (millis() - _lastServerActivity) >= (_keepAlive * 1000 * 0.7)) { _sendPing(); } @@ -529,113 +466,87 @@ void AsyncMqttClient::_onPoll(AsyncClient *client) // handle disconnect - if (_disconnectFlagged) - { + if (_disconnectFlagged) { _sendDisconnect(); } } /* MQTT */ -void AsyncMqttClient::_onPingResp() -{ +void AsyncMqttClient::_onPingResp() { _freeCurrentParsedPacket(); _lastPingRequestTime = 0; } -void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode) -{ +void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode) { (void)sessionPresent; _freeCurrentParsedPacket(); - if (connectReturnCode == 0) - { - Serial.println("SETTING CONNECTED TO TRUE"); + if (connectReturnCode == 0) { _connected = true; - for (auto callback : _onConnectUserCallbacks) - callback(sessionPresent); - } - else - { - for (auto callback : _onDisconnectUserCallbacks) - callback(static_cast(connectReturnCode)); + for (auto callback : _onConnectUserCallbacks) callback(sessionPresent); + } else { + for (auto callback : _onDisconnectUserCallbacks) callback(static_cast(connectReturnCode)); _disconnectFlagged = true; } } -void AsyncMqttClient::_onSubAck(uint16_t packetId, char status) -{ +void AsyncMqttClient::_onSubAck(uint16_t packetId, char status) { _freeCurrentParsedPacket(); - for (auto callback : _onSubscribeUserCallbacks) - callback(packetId, status); + for (auto callback : _onSubscribeUserCallbacks) callback(packetId, status); } -void AsyncMqttClient::_onUnsubAck(uint16_t packetId) -{ +void AsyncMqttClient::_onUnsubAck(uint16_t packetId) { _freeCurrentParsedPacket(); - for (auto callback : _onUnsubscribeUserCallbacks) - callback(packetId); + for (auto callback : _onUnsubscribeUserCallbacks) callback(packetId); } -void AsyncMqttClient::_onMessage(char *topic, char *payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId) -{ +void AsyncMqttClient::_onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId) { bool notifyPublish = true; - if (qos == 2) - { - for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) - { - if (pendingPubRel.packetId == packetId) - { + if (qos == 2) { + for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) { + if (pendingPubRel.packetId == packetId) { notifyPublish = false; break; } } } - if (notifyPublish) - { + if (notifyPublish) { AsyncMqttClientMessageProperties properties; properties.qos = qos; properties.dup = dup; properties.retain = retain; - for (auto callback : _onMessageUserCallbacks) - callback(topic, payload, properties, len, index, total); + for (auto callback : _onMessageUserCallbacks) callback(topic, payload, properties, len, index, total); } } -void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) -{ +void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) { AsyncMqttClientInternals::PendingAck pendingAck; - if (qos == 1) - { + if (qos == 1) { pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBACK; pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBACK_RESERVED; pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); - } - else if (qos == 2) - { + } else if (qos == 2) { pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBREC; pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBREC_RESERVED; pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); bool pubRelAwaiting = false; - for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) - { - if (pendingPubRel.packetId == packetId) - { + for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) { + if (pendingPubRel.packetId == packetId) { pubRelAwaiting = true; break; } } - if (!pubRelAwaiting) - { + if (!pubRelAwaiting) { AsyncMqttClientInternals::PendingPubRel pendingPubRel; pendingPubRel.packetId = packetId; _pendingPubRels.push_back(pendingPubRel); @@ -647,8 +558,7 @@ void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) _freeCurrentParsedPacket(); } -void AsyncMqttClient::_onPubRel(uint16_t packetId) -{ +void AsyncMqttClient::_onPubRel(uint16_t packetId) { _freeCurrentParsedPacket(); AsyncMqttClientInternals::PendingAck pendingAck; @@ -657,10 +567,8 @@ void AsyncMqttClient::_onPubRel(uint16_t packetId) pendingAck.packetId = packetId; _toSendAcks.push_back(pendingAck); - for (size_t i = 0; i < _pendingPubRels.size(); i++) - { - if (_pendingPubRels[i].packetId == packetId) - { + for (size_t i = 0; i < _pendingPubRels.size(); i++) { + if (_pendingPubRels[i].packetId == packetId) { _pendingPubRels.erase(_pendingPubRels.begin() + i); _pendingPubRels.shrink_to_fit(); } @@ -669,16 +577,13 @@ void AsyncMqttClient::_onPubRel(uint16_t packetId) _sendAcks(); } -void AsyncMqttClient::_onPubAck(uint16_t packetId) -{ +void AsyncMqttClient::_onPubAck(uint16_t packetId) { _freeCurrentParsedPacket(); - for (auto callback : _onPublishUserCallbacks) - callback(packetId); + for (auto callback : _onPublishUserCallbacks) callback(packetId); } -void AsyncMqttClient::_onPubRec(uint16_t packetId) -{ +void AsyncMqttClient::_onPubRec(uint16_t packetId) { _freeCurrentParsedPacket(); AsyncMqttClientInternals::PendingAck pendingAck; @@ -690,16 +595,13 @@ void AsyncMqttClient::_onPubRec(uint16_t packetId) _sendAcks(); } -void AsyncMqttClient::_onPubComp(uint16_t packetId) -{ +void AsyncMqttClient::_onPubComp(uint16_t packetId) { _freeCurrentParsedPacket(); - for (auto callback : _onPublishUserCallbacks) - callback(packetId); + for (auto callback : _onPublishUserCallbacks) callback(packetId); } -bool AsyncMqttClient::_sendPing() -{ +bool AsyncMqttClient::_sendPing() { char fixedHeader[2]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.PINGREQ; fixedHeader[0] = fixedHeader[0] << 4; @@ -709,11 +611,7 @@ bool AsyncMqttClient::_sendPing() size_t neededSpace = 2; SEMAPHORE_TAKE(false); - if (_client.space() < neededSpace) - { - SEMAPHORE_GIVE(); - return false; - } + if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; } _client.add(fixedHeader, 2); _client.send(); @@ -724,15 +622,12 @@ bool AsyncMqttClient::_sendPing() return true; } -void AsyncMqttClient::_sendAcks() -{ +void AsyncMqttClient::_sendAcks() { uint8_t neededAckSpace = 2 + 2; SEMAPHORE_TAKE(); - for (size_t i = 0; i < _toSendAcks.size(); i++) - { - if (_client.space() < neededAckSpace) - break; + for (size_t i = 0; i < _toSendAcks.size(); i++) { + if (_client.space() < neededAckSpace) break; AsyncMqttClientInternals::PendingAck pendingAck = _toSendAcks[i]; @@ -758,20 +653,14 @@ void AsyncMqttClient::_sendAcks() SEMAPHORE_GIVE(); } -bool AsyncMqttClient::_sendDisconnect() -{ - if (!_connected) - return true; +bool AsyncMqttClient::_sendDisconnect() { + if (!_connected) return true; const uint8_t neededSpace = 2; SEMAPHORE_TAKE(false); - if (_client.space() < neededSpace) - { - SEMAPHORE_GIVE(); - return false; - } + if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; } char fixedHeader[2]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.DISCONNECT; @@ -789,68 +678,50 @@ bool AsyncMqttClient::_sendDisconnect() return true; } -uint16_t AsyncMqttClient::_getNextPacketId() -{ +uint16_t AsyncMqttClient::_getNextPacketId() { uint16_t nextPacketId = _nextPacketId; - if (_nextPacketId == 65535) - _nextPacketId = 0; // 0 is forbidden + if (_nextPacketId == 65535) _nextPacketId = 0; // 0 is forbidden _nextPacketId++; return nextPacketId; } -bool AsyncMqttClient::connected() const -{ +bool AsyncMqttClient::connected() const { return _connected; } -void AsyncMqttClient::connect() -{ - if (_connected) - return; +void AsyncMqttClient::connect() { + if (_connected) return; #if ASYNC_TCP_SSL_ENABLED - if (_useIp) - { + if (_useIp) { _client.connect(_ip, _port, _secure); - } - else - { + } else { _client.connect(_host, _port, _secure); } #else - if (_useIp) - { + if (_useIp) { _client.connect(_ip, _port); - } - else - { + } else { _client.connect(_host, _port); } #endif } -void AsyncMqttClient::disconnect(bool force) -{ - if (!_connected) - return; +void AsyncMqttClient::disconnect(bool force) { + if (!_connected) return; - if (force) - { + if (force) { _client.close(true); - } - else - { + } else { _disconnectFlagged = true; _sendDisconnect(); } } -uint16_t AsyncMqttClient::subscribe(const char *topic, uint8_t qos) -{ - if (!_connected) - return 0; +uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) { + if (!_connected) return 0; char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.SUBSCRIBE; @@ -875,11 +746,7 @@ uint16_t AsyncMqttClient::subscribe(const char *topic, uint8_t qos) neededSpace += 1; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) - { - SEMAPHORE_GIVE(); - return 0; - } + if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } uint16_t packetId = _getNextPacketId(); char packetIdBytes[2]; @@ -898,10 +765,8 @@ uint16_t AsyncMqttClient::subscribe(const char *topic, uint8_t qos) return packetId; } -uint16_t AsyncMqttClient::unsubscribe(const char *topic) -{ - if (!_connected) - return 0; +uint16_t AsyncMqttClient::unsubscribe(const char* topic) { + if (!_connected) return 0; char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.UNSUBSCRIBE; @@ -922,11 +787,7 @@ uint16_t AsyncMqttClient::unsubscribe(const char *topic) neededSpace += topicLength; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) - { - SEMAPHORE_GIVE(); - return 0; - } + if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } uint16_t packetId = _getNextPacketId(); char packetIdBytes[2]; @@ -944,32 +805,24 @@ uint16_t AsyncMqttClient::unsubscribe(const char *topic) return packetId; } -uint16_t AsyncMqttClient::publish(const char *topic, uint8_t qos, bool retain, const char *payload, size_t length, bool dup, uint16_t message_id) -{ - if (!_connected) - { - Serial.println("Not connected"); - return 0; - } +uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length, bool dup, uint16_t message_id) { + if (!_connected) return 0; char fixedHeader[5]; fixedHeader[0] = AsyncMqttClientInternals::PacketType.PUBLISH; fixedHeader[0] = fixedHeader[0] << 4; - if (dup) - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP; - if (retain) - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN; - switch (qos) - { - case 0: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0; - break; - case 1: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1; - break; - case 2: - fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2; - break; + if (dup) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP; + if (retain) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN; + switch (qos) { + case 0: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0; + break; + case 1: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1; + break; + case 2: + fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2; + break; } uint16_t topicLength = strlen(topic); @@ -978,41 +831,28 @@ uint16_t AsyncMqttClient::publish(const char *topic, uint8_t qos, bool retain, c topicLengthBytes[1] = topicLength & 0xFF; uint32_t payloadLength = length; - if (payload != nullptr && payloadLength == 0) - payloadLength = strlen(payload); + if (payload != nullptr && payloadLength == 0) payloadLength = strlen(payload); uint32_t remainingLength = 2 + topicLength + payloadLength; - if (qos != 0) - remainingLength += 2; + if (qos != 0) remainingLength += 2; uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1); size_t neededSpace = 0; neededSpace += 1 + remainingLengthLength; neededSpace += 2; neededSpace += topicLength; - if (qos != 0) - neededSpace += 2; - if (payload != nullptr) - neededSpace += payloadLength; + if (qos != 0) neededSpace += 2; + if (payload != nullptr) neededSpace += payloadLength; SEMAPHORE_TAKE(0); - if (_client.space() < neededSpace) - { - SEMAPHORE_GIVE(); - Serial.println("Not enough space for request"); - return 0; - } + if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; } uint16_t packetId = 0; char packetIdBytes[2]; - if (qos != 0) - { - if (dup && message_id > 0) - { + if (qos != 0) { + if (dup && message_id > 0) { packetId = message_id; - } - else - { + } else { packetId = _getNextPacketId(); } @@ -1023,25 +863,15 @@ uint16_t AsyncMqttClient::publish(const char *topic, uint8_t qos, bool retain, c _client.add(fixedHeader, 1 + remainingLengthLength); _client.add(topicLengthBytes, 2); _client.add(topic, topicLength); - if (qos != 0) - _client.add(packetIdBytes, 2); - if (payload != nullptr) - _client.add(payload, payloadLength); + if (qos != 0) _client.add(packetIdBytes, 2); + if (payload != nullptr) _client.add(payload, payloadLength); _client.send(); _lastClientActivity = millis(); SEMAPHORE_GIVE(); - if (qos != 0) - { + if (qos != 0) { return packetId; - } - else - { + } else { return 1; } } - -void AsyncMqttClient::setConnected(bool connected) -{ - _connected = connected; -} \ No newline at end of file diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp index 4663621521..af8332b24e 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp @@ -39,52 +39,46 @@ #include "AsyncMqttClient/Packets/PubCompPacket.hpp" #if ESP32 -#define SEMAPHORE_TAKE(X) \ - if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) \ - { \ - return X; \ - } // Waits max 1000ms +#define SEMAPHORE_TAKE(X) if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) { return X; } // Waits max 1000ms #define SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore); #elif defined(ESP8266) #define SEMAPHORE_TAKE(X) void() #define SEMAPHORE_GIVE() void() #endif -class AsyncMqttClient -{ -public: +class AsyncMqttClient { + public: AsyncMqttClient(); ~AsyncMqttClient(); - AsyncMqttClient &setKeepAlive(uint16_t keepAlive); - AsyncMqttClient &setClientId(const char *clientId); - AsyncMqttClient &setCleanSession(bool cleanSession); - AsyncMqttClient &setMaxTopicLength(uint16_t maxTopicLength); - AsyncMqttClient &setCredentials(const char *username, const char *password = nullptr); - AsyncMqttClient &setWill(const char *topic, uint8_t qos, bool retain, const char *payload = nullptr, size_t length = 0); - AsyncMqttClient &setServer(IPAddress ip, uint16_t port); - AsyncMqttClient &setServer(const char *host, uint16_t port); + AsyncMqttClient& setKeepAlive(uint16_t keepAlive); + AsyncMqttClient& setClientId(const char* clientId); + AsyncMqttClient& setCleanSession(bool cleanSession); + AsyncMqttClient& setMaxTopicLength(uint16_t maxTopicLength); + AsyncMqttClient& setCredentials(const char* username, const char* password = nullptr); + AsyncMqttClient& setWill(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0); + AsyncMqttClient& setServer(IPAddress ip, uint16_t port); + AsyncMqttClient& setServer(const char* host, uint16_t port); #if ASYNC_TCP_SSL_ENABLED - AsyncMqttClient &setSecure(bool secure); - AsyncMqttClient &addServerFingerprint(const uint8_t *fingerprint); + AsyncMqttClient& setSecure(bool secure); + AsyncMqttClient& addServerFingerprint(const uint8_t* fingerprint); #endif - AsyncMqttClient &onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback); - AsyncMqttClient &onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback); - AsyncMqttClient &onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback); - AsyncMqttClient &onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback); - AsyncMqttClient &onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback); - AsyncMqttClient &onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback); + AsyncMqttClient& onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback); + AsyncMqttClient& onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback); + AsyncMqttClient& onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback); + AsyncMqttClient& onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback); + AsyncMqttClient& onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback); + AsyncMqttClient& onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback); bool connected() const; void connect(); void disconnect(bool force = false); - uint16_t subscribe(const char *topic, uint8_t qos); - uint16_t unsubscribe(const char *topic); - uint16_t publish(const char *topic, uint8_t qos, bool retain, const char *payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); - void setConnected(bool connected); + uint16_t subscribe(const char* topic, uint8_t qos); + uint16_t unsubscribe(const char* topic); + uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); -private: + private: AsyncClient _client; bool _connected; @@ -95,9 +89,9 @@ class AsyncMqttClient uint32_t _lastServerActivity; uint32_t _lastPingRequestTime; - char _generatedClientId[13 + 1]; // esp8266abc123 + char _generatedClientId[13 + 1]; // esp8266abc123 IPAddress _ip; - const char *_host; + const char* _host; bool _useIp; #if ASYNC_TCP_SSL_ENABLED bool _secure; @@ -105,11 +99,11 @@ class AsyncMqttClient uint16_t _port; uint16_t _keepAlive; bool _cleanSession; - const char *_clientId; - const char *_username; - const char *_password; - const char *_willTopic; - const char *_willPayload; + const char* _clientId; + const char* _username; + const char* _password; + const char* _willTopic; + const char* _willPayload; uint16_t _willPayloadLength; uint8_t _willQos; bool _willRetain; @@ -126,7 +120,7 @@ class AsyncMqttClient std::vector _onPublishUserCallbacks; AsyncMqttClientInternals::ParsingInformation _parsingInformation; - AsyncMqttClientInternals::Packet *_currentParsedPacket; + AsyncMqttClientInternals::Packet* _currentParsedPacket; uint8_t _remainingLengthBufferPosition; char _remainingLengthBuffer[4]; @@ -144,20 +138,20 @@ class AsyncMqttClient void _freeCurrentParsedPacket(); // TCP - void _onConnect(AsyncClient *client); - void _onDisconnect(AsyncClient *client); - static void _onError(AsyncClient *client, int8_t error); - void _onTimeout(AsyncClient *client, uint32_t time); - static void _onAck(AsyncClient *client, size_t len, uint32_t time); - void _onData(AsyncClient *client, char *data, size_t len); - void _onPoll(AsyncClient *client); + void _onConnect(AsyncClient* client); + void _onDisconnect(AsyncClient* client); + static void _onError(AsyncClient* client, int8_t error); + void _onTimeout(AsyncClient* client, uint32_t time); + static void _onAck(AsyncClient* client, size_t len, uint32_t time); + void _onData(AsyncClient* client, char* data, size_t len); + void _onPoll(AsyncClient* client); // MQTT void _onPingResp(); void _onConnAck(bool sessionPresent, uint8_t connectReturnCode); void _onSubAck(uint16_t packetId, char status); void _onUnsubAck(uint16_t packetId); - void _onMessage(char *topic, char *payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId); + void _onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId); void _onPublish(uint16_t packetId, uint8_t qos); void _onPubRel(uint16_t packetId); void _onPubAck(uint16_t packetId); diff --git a/wled00/util.cpp b/wled00/util.cpp index e4774da2d8..914f09ee35 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -2,73 +2,48 @@ #include "fcn_declare.h" #include "const.h" -// helper to get int value at a position in string -int getNumVal(const String *req, uint16_t pos) + +//helper to get int value at a position in string +int getNumVal(const String* req, uint16_t pos) { - return req->substring(pos + 3).toInt(); + return req->substring(pos+3).toInt(); } -// helper to get int value with in/decrementing support via ~ syntax -void parseNumber(const char *str, byte *val, byte minv, byte maxv) + +//helper to get int value with in/decrementing support via ~ syntax +void parseNumber(const char* str, byte* val, byte minv, byte maxv) { - if (str == nullptr || str[0] == '\0') - return; - if (str[0] == 'r') - { - *val = random8(minv, maxv ? maxv : 255); - return; - } // maxv for random cannot be 0 + if (str == nullptr || str[0] == '\0') return; + if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 bool wrap = false; - if (str[0] == 'w' && strlen(str) > 1) - { - str++; - wrap = true; - } - if (str[0] == '~') - { - int out = atoi(str + 1); - if (out == 0) - { - if (str[1] == '0') - return; - if (str[1] == '-') - { - *val = (int)(*val - 1) < (int)minv ? maxv : min((int)maxv, (*val - 1)); //-1, wrap around + if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;} + if (str[0] == '~') { + int out = atoi(str +1); + if (out == 0) { + if (str[1] == '0') return; + if (str[1] == '-') { + *val = (int)(*val -1) < (int)minv ? maxv : min((int)maxv,(*val -1)); //-1, wrap around + } else { + *val = (int)(*val +1) > (int)maxv ? minv : max((int)minv,(*val +1)); //+1, wrap around } - else - { - *val = (int)(*val + 1) > (int)maxv ? minv : max((int)minv, (*val + 1)); //+1, wrap around - } - } - else - { - if (wrap && *val == maxv && out > 0) - out = minv; - else if (wrap && *val == minv && out < 0) - out = maxv; - else - { + } else { + if (wrap && *val == maxv && out > 0) out = minv; + else if (wrap && *val == minv && out < 0) out = maxv; + else { out += *val; - if (out > maxv) - out = maxv; - if (out < minv) - out = minv; + if (out > maxv) out = maxv; + if (out < minv) out = minv; } *val = out; } return; - } - else if (minv == maxv && minv == 0) - { // limits "unset" i.e. both 0 + } else if (minv == maxv && minv == 0) { // limits "unset" i.e. both 0 byte p1 = atoi(str); - const char *str2 = strchr(str, '~'); // min/max range (for preset cycle, e.g. "1~5~") - if (str2) - { - byte p2 = atoi(++str2); // skip ~ - if (p2 > 0) - { - while (isdigit(*(++str2))) - ; // skip digits + const char* str2 = strchr(str,'~'); // min/max range (for preset cycle, e.g. "1~5~") + if (str2) { + byte p2 = atoi(++str2); // skip ~ + if (p2 > 0) { + while (isdigit(*(++str2))); // skip digits parseNumber(str2, val, p1, p2); return; } @@ -77,96 +52,91 @@ void parseNumber(const char *str, byte *val, byte minv, byte maxv) *val = atoi(str); } -bool getVal(JsonVariant elem, byte *val, byte vmin, byte vmax) -{ - if (elem.is()) - { - if (elem < 0) - return false; // ignore e.g. {"ps":-1} + +bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { + if (elem.is()) { + if (elem < 0) return false; //ignore e.g. {"ps":-1} *val = elem; return true; - } - else if (elem.is()) - { - const char *str = elem; + } else if (elem.is()) { + const char* str = elem; size_t len = strnlen(str, 12); - if (len == 0 || len > 10) - return false; + if (len == 0 || len > 10) return false; parseNumber(str, val, vmin, vmax); return true; } - return false; // key does not exist + return false; //key does not exist } -bool updateVal(const char *req, const char *key, byte *val, byte minv, byte maxv) + +bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv) { const char *v = strstr(req, key); - if (v) - v += strlen(key); - else - return false; + if (v) v += strlen(key); + else return false; parseNumber(v, val, minv, maxv); return true; } -// append a numeric setting to string buffer -void sappend(char stype, const char *key, int val) + +//append a numeric setting to string buffer +void sappend(char stype, const char* key, int val) { char ds[] = "d.Sf."; - switch (stype) + switch(stype) { - case 'c': // checkbox - oappend(ds); - oappend(key); - oappend(".checked="); - oappendi(val); - oappend(";"); - break; - case 'v': // numeric - oappend(ds); - oappend(key); - oappend(".value="); - oappendi(val); - oappend(";"); - break; - case 'i': // selectedIndex - oappend(ds); - oappend(key); - oappend(SET_F(".selectedIndex=")); - oappendi(val); - oappend(";"); - break; + case 'c': //checkbox + oappend(ds); + oappend(key); + oappend(".checked="); + oappendi(val); + oappend(";"); + break; + case 'v': //numeric + oappend(ds); + oappend(key); + oappend(".value="); + oappendi(val); + oappend(";"); + break; + case 'i': //selectedIndex + oappend(ds); + oappend(key); + oappend(SET_F(".selectedIndex=")); + oappendi(val); + oappend(";"); + break; } } -// append a string setting to buffer -void sappends(char stype, const char *key, char *val) + +//append a string setting to buffer +void sappends(char stype, const char* key, char* val) { - switch (stype) + switch(stype) { - case 's': - { // string (we can interpret val as char*) - String buf = val; - // convert "%" to "%%" to make EspAsyncWebServer happy - // buf.replace("%","%%"); - oappend("d.Sf."); - oappend(key); - oappend(".value=\""); - oappend(buf.c_str()); - oappend("\";"); - break; - } - case 'm': // message - oappend(SET_F("d.getElementsByClassName")); - oappend(key); - oappend(SET_F(".innerHTML=\"")); - oappend(val); - oappend("\";"); - break; + case 's': {//string (we can interpret val as char*) + String buf = val; + //convert "%" to "%%" to make EspAsyncWebServer happy + //buf.replace("%","%%"); + oappend("d.Sf."); + oappend(key); + oappend(".value=\""); + oappend(buf.c_str()); + oappend("\";"); + break;} + case 'm': //message + oappend(SET_F("d.getElementsByClassName")); + oappend(key); + oappend(SET_F(".innerHTML=\"")); + oappend(val); + oappend("\";"); + break; } } + bool oappendi(int i) { char s[11]; @@ -174,77 +144,67 @@ bool oappendi(int i) return oappend(s); } -bool oappend(const char *txt) + +bool oappend(const char* txt) { uint16_t len = strlen(txt); - if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) - { // sanity checks + if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks #ifdef WLED_DEBUG DEBUG_PRINT(F("oappend() buffer overflow. Cannot append ")); - DEBUG_PRINT(len); - DEBUG_PRINT(F(" bytes \t\"")); - DEBUG_PRINT(txt); - DEBUG_PRINTLN(F("\"")); + DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\"")); + DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\"")); #endif - return false; // buffer full + return false; // buffer full } strcpy(obuf + olen, txt); olen += len; return true; } -void prepareHostname(char *hostname) + +void prepareHostname(char* hostname) { sprintf_P(hostname, "wled-%*s", 6, escapedMac.c_str() + 6); const char *pC = serverDescription; - uint8_t pos = 5; // keep "wled-" - while (*pC && pos < 24) - { // while !null and not over length - if (isalnum(*pC)) - { // if the current char is alpha-numeric append it to the hostname + uint8_t pos = 5; // keep "wled-" + while (*pC && pos < 24) { // while !null and not over length + if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname hostname[pos] = *pC; pos++; - } - else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') - { + } else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') { hostname[pos] = '-'; pos++; } // else do nothing - no leading hyphens and do not include hyphens for all other characters. pC++; } - // last character must not be hyphen - if (pos > 5) - { - while (pos > 4 && hostname[pos - 1] == '-') - pos--; + //last character must not be hyphen + if (pos > 5) { + while (pos > 4 && hostname[pos -1] == '-') pos--; hostname[pos] = '\0'; // terminate string (leave at least "wled") } } -bool isAsterisksOnly(const char *str, byte maxLen) + +bool isAsterisksOnly(const char* str, byte maxLen) { - for (byte i = 0; i < maxLen; i++) - { - if (str[i] == 0) - break; - if (str[i] != '*') - return false; + for (byte i = 0; i < maxLen; i++) { + if (str[i] == 0) break; + if (str[i] != '*') return false; } - // at this point the password contains asterisks only - return (str[0] != 0); // false on empty string + //at this point the password contains asterisks only + return (str[0] != 0); //false on empty string } -// threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 + +//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 bool requestJSONBufferLock(uint8_t module) { unsigned long now = millis(); - while (jsonBufferLock && millis() - now < 1000) - delay(1); // wait for a second for buffer lock + while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock - if (millis() - now >= 1000) - { + if (millis()-now >= 1000) { DEBUG_PRINT(F("ERROR: Locking JSON buffer failed! (")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); @@ -255,11 +215,12 @@ bool requestJSONBufferLock(uint8_t module) DEBUG_PRINT(F("JSON buffer locked. (")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); - fileDoc = &doc; // used for applying presets (presets.cpp) + fileDoc = &doc; // used for applying presets (presets.cpp) doc.clear(); return true; } + void releaseJSONBufferLock() { DEBUG_PRINT(F("JSON buffer released. (")); @@ -269,70 +230,31 @@ void releaseJSONBufferLock() jsonBufferLock = 0; } -// the same functions but for my new response buffers -bool requestResponseBufferLock(uint8_t module) -{ - unsigned long now = millis(); - - while (responseBufferLock && millis() - now < 1000) - delay(1); // wait for a second for buffer lock - - if (millis() - now >= 1000) - { - DEBUG_PRINT(F("ERROR: Locking response buffer failed! (")); - DEBUG_PRINT(responseBufferLock); - DEBUG_PRINTLN(")"); - return false; // waiting time-outed - } - - responseBufferLock = module ? module : 255; - DEBUG_PRINT(F("Response buffer locked. (")); - DEBUG_PRINT(responseBufferLock); - DEBUG_PRINTLN(")"); - mqttResponseDoc.clear(); // Clear the JSON document - memset(mqttResponseBuffer, 0, JSON_BUFFER_SIZE); // Clear the buffer - return true; -} - -void releaseResponseBufferLock() -{ - DEBUG_PRINT(F("Response buffer released. (")); - DEBUG_PRINT(responseBufferLock); - DEBUG_PRINTLN(")"); - responseBufferLock = 0; -} // extracts effect mode (or palette) name from names serialized string // caller must provide large enough buffer for name (including SR extensions)! uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen) { - if (src == JSON_mode_names || src == nullptr) - { - if (mode < strip.getModeCount()) - { + if (src == JSON_mode_names || src == nullptr) { + if (mode < strip.getModeCount()) { char lineBuffer[256]; - // strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); - strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer) / sizeof(char) - 1); - lineBuffer[sizeof(lineBuffer) / sizeof(char) - 1] = '\0'; // terminate string + //strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); + strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1); + lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string size_t len = strlen(lineBuffer); size_t j = 0; - for (; j < maxLen && j < len; j++) - { - if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') - break; + for (; j < maxLen && j < len; j++) { + if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break; dest[j] = lineBuffer[j]; } dest[j] = 0; // terminate string return strlen(dest); - } - else - return 0; + } else return 0; } - if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) - { - snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255 - mode); - dest[maxLen - 1] = '\0'; + if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) { + snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode); + dest[maxLen-1] = '\0'; return strlen(dest); } @@ -343,144 +265,95 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe size_t len = strlen_P(src); // Find the mode name in JSON - for (size_t i = 0; i < len; i++) - { + for (size_t i = 0; i < len; i++) { singleJsonSymbol = pgm_read_byte_near(src + i); - if (singleJsonSymbol == '\0') - break; - if (singleJsonSymbol == '@' && insideQuotes && qComma == mode) - break; // stop when SR extension encountered - switch (singleJsonSymbol) - { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - if (!insideQuotes) - qComma++; - default: - if (!insideQuotes || (qComma != mode)) + if (singleJsonSymbol == '\0') break; + if (singleJsonSymbol == '@' && insideQuotes && qComma == mode) break; //stop when SR extension encountered + switch (singleJsonSymbol) { + case '"': + insideQuotes = !insideQuotes; + break; + case '[': + case ']': break; - dest[printedChars++] = singleJsonSymbol; + case ',': + if (!insideQuotes) qComma++; + default: + if (!insideQuotes || (qComma != mode)) break; + dest[printedChars++] = singleJsonSymbol; } - if ((qComma > mode) || (printedChars >= maxLen)) - break; + if ((qComma > mode) || (printedChars >= maxLen)) break; } dest[printedChars] = '\0'; return strlen(dest); } + // extracts effect slider data (1st group after @) uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var) { dest[0] = '\0'; // start by clearing buffer - if (mode < strip.getModeCount()) - { + if (mode < strip.getModeCount()) { String lineBuffer = FPSTR(strip.getModeData(mode)); - if (lineBuffer.length() > 0) - { + if (lineBuffer.length() > 0) { int16_t start = lineBuffer.indexOf('@'); - int16_t stop = lineBuffer.indexOf(';', start); - if (start > 0 && stop > 0) - { + int16_t stop = lineBuffer.indexOf(';', start); + if (start>0 && stop>0) { String names = lineBuffer.substring(start, stop); // include @ int16_t nameBegin = 1, nameEnd, nameDefault; - if (slider < 10) - { - for (size_t i = 0; i <= slider; i++) - { + if (slider < 10) { + for (size_t i=0; i<=slider; i++) { const char *tmpstr; - dest[0] = '\0'; // clear dest buffer - if (nameBegin == 0) - break; // there are no more names + dest[0] = '\0'; //clear dest buffer + if (nameBegin == 0) break; // there are no more names nameEnd = names.indexOf(',', nameBegin); - if (i == slider) - { + if (i == slider) { nameDefault = names.indexOf('=', nameBegin); // find default value - if (nameDefault > 0 && var && ((nameEnd > 0 && nameDefault < nameEnd) || nameEnd < 0)) - { - *var = (uint8_t)atoi(names.substring(nameDefault + 1).c_str()); + if (nameDefault > 0 && var && ((nameEnd>0 && nameDefault= 0) - { - nameEnd = names.indexOf(';', nameBegin + 1); - if (!isdigit(names[nameBegin + 1])) - nameBegin = names.indexOf('=', nameBegin + 1); // look for default value - if (nameEnd >= 0 && nameBegin > nameEnd) - nameBegin = -1; - if (nameBegin >= 0 && var) - { - *var = (uint8_t)atoi(names.substring(nameBegin + 1).c_str()); + names = lineBuffer.substring(stop+1); // stop has index of color slot names + nameBegin = names.indexOf(';'); // look for palette + if (nameBegin >= 0) { + nameEnd = names.indexOf(';', nameBegin+1); + if (!isdigit(names[nameBegin+1])) nameBegin = names.indexOf('=', nameBegin+1); // look for default value + if (nameEnd >= 0 && nameBegin > nameEnd) nameBegin = -1; + if (nameBegin >= 0 && var) { + *var = (uint8_t)atoi(names.substring(nameBegin+1).c_str()); } } } // we have slider name (including default value) in the dest buffer - for (size_t i = 0; i < strlen(dest); i++) - if (dest[i] == '=') - { - dest[i] = '\0'; - break; - } // truncate default value - } - else - { + for (size_t i=0; i(); - if (name != nullptr) - len = strlen(name); - if (len > 0 && len < 33) - { - ledmapNames[i - 1] = new char[len + 1]; - if (ledmapNames[i - 1]) - strlcpy(ledmapNames[i - 1], name, 33); + const char *name = doc["n"].as(); + if (name != nullptr) len = strlen(name); + if (len > 0 && len < 33) { + ledmapNames[i-1] = new char[len+1]; + if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33); } } - if (!ledmapNames[i - 1]) - { + if (!ledmapNames[i-1]) { char tmp[33]; snprintf_P(tmp, 32, PSTR("ledmap%d.json"), i); len = strlen(tmp); - ledmapNames[i - 1] = new char[len + 1]; - if (ledmapNames[i - 1]) - strlcpy(ledmapNames[i - 1], tmp, 33); + ledmapNames[i-1] = new char[len+1]; + if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33); } } releaseJSONBufferLock(); } -#endif + #endif } + } } /* * Returns a new, random color wheel index with a minimum distance of 42 from pos. */ -uint8_t get_random_wheel_index(uint8_t pos) -{ +uint8_t get_random_wheel_index(uint8_t pos) { uint8_t r = 0, x = 0, y = 0, d = 0; - while (d < 42) - { + while (d < 42) { r = random8(); x = abs(pos - r); y = 255 - x; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 2dd6830209..8ba6b1a565 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -1,4 +1,4 @@ -#define WLED_DEFINE_GLOBAL_VARS // only in one source file, wled.cpp! +#define WLED_DEFINE_GLOBAL_VARS //only in one source file, wled.cpp! #include "wled.h" #include "wled_ethernet.h" #include @@ -20,13 +20,12 @@ WLED::WLED() void WLED::reset() { briT = 0; -#ifdef WLED_ENABLE_WEBSOCKETS + #ifdef WLED_ENABLE_WEBSOCKETS ws.closeAll(1012); -#endif + #endif unsigned long dly = millis(); - while (millis() - dly < 450) - { - yield(); // enough time to send response to client + while (millis() - dly < 450) { + yield(); // enough time to send response to client } applyBri(); DEBUG_PRINTLN(F("WLED RESET")); @@ -35,36 +34,29 @@ void WLED::reset() void WLED::loop() { - if (otaInProgress) - { - // stop the loop while ota in progress - return; - } -#ifdef WLED_DEBUG + #ifdef WLED_DEBUG static unsigned long lastRun = 0; - unsigned long loopMillis = millis(); - size_t loopDelay = loopMillis - lastRun; - if (lastRun == 0) - loopDelay = 0; // startup - don't have valid data from last run. - if (loopDelay > 2) - DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay); + unsigned long loopMillis = millis(); + size_t loopDelay = loopMillis - lastRun; + if (lastRun == 0) loopDelay=0; // startup - don't have valid data from last run. + if (loopDelay > 2) DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay); static unsigned long maxLoopMillis = 0; - static size_t avgLoopMillis = 0; + static size_t avgLoopMillis = 0; static unsigned long maxUsermodMillis = 0; - static size_t avgUsermodMillis = 0; + static size_t avgUsermodMillis = 0; static unsigned long maxStripMillis = 0; - static size_t avgStripMillis = 0; - unsigned long stripMillis; -#endif + static size_t avgStripMillis = 0; + unsigned long stripMillis; + #endif handleTime(); -#ifndef WLED_DISABLE_INFRARED - handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too -#endif + #ifndef WLED_DISABLE_INFRARED + handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too + #endif handleConnection(); -#ifndef WLED_DISABLE_ESPNOW + #ifndef WLED_DISABLE_ESPNOW handleRemote(); -#endif + #endif handleSerial(); handleImprovWifiScan(); handleNotifications(); @@ -74,146 +66,126 @@ void WLED::loop() #endif userLoop(); -#ifdef WLED_DEBUG + #ifdef WLED_DEBUG unsigned long usermodMillis = millis(); -#endif + #endif usermods.loop(); -#ifdef WLED_DEBUG + #ifdef WLED_DEBUG usermodMillis = millis() - usermodMillis; avgUsermodMillis += usermodMillis; - if (usermodMillis > maxUsermodMillis) - maxUsermodMillis = usermodMillis; -#endif + if (usermodMillis > maxUsermodMillis) maxUsermodMillis = usermodMillis; + #endif yield(); handleIO(); -#ifndef WLED_DISABLE_INFRARED + #ifndef WLED_DISABLE_INFRARED handleIR(); -#endif -#ifndef WLED_DISABLE_ALEXA + #endif + #ifndef WLED_DISABLE_ALEXA handleAlexa(); -#endif + #endif - if (doCloseFile) - { + if (doCloseFile) { closeFile(); yield(); } -#ifdef WLED_DEBUG + #ifdef WLED_DEBUG stripMillis = millis(); -#endif - if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled + #endif + if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled { - if (apActive) - dnsServer.processNextRequest(); -#ifndef WLED_DISABLE_OTA - if (WLED_CONNECTED && aOtaEnabled && !otaLock && correctPIN) - ArduinoOTA.handle(); -#endif + if (apActive) dnsServer.processNextRequest(); + #ifndef WLED_DISABLE_OTA + if (WLED_CONNECTED && aOtaEnabled && !otaLock && correctPIN) ArduinoOTA.handle(); + #endif handleNightlight(); handlePlaylist(); yield(); -#ifndef WLED_DISABLE_HUESYNC + #ifndef WLED_DISABLE_HUESYNC handleHue(); yield(); -#endif + #endif handlePresets(); yield(); if (!offMode || strip.isOffRefreshRequired()) strip.service(); -#ifdef ESP8266 + #ifdef ESP8266 else if (!noWifiSleep) - delay(1); // required to make sure ESP enters modem sleep (see #1184) -#endif + delay(1); //required to make sure ESP enters modem sleep (see #1184) + #endif } -#ifdef WLED_DEBUG + #ifdef WLED_DEBUG stripMillis = millis() - stripMillis; avgStripMillis += stripMillis; - if (stripMillis > maxStripMillis) - maxStripMillis = stripMillis; -#endif + if (stripMillis > maxStripMillis) maxStripMillis = stripMillis; + #endif yield(); #ifdef ESP8266 MDNS.update(); #endif - // millis() rolls over every 50 days - if (lastMqttReconnectAttempt > millis()) - { + //millis() rolls over every 50 days + if (lastMqttReconnectAttempt > millis()) { rolloverMillis++; lastMqttReconnectAttempt = 0; - ntpLastSyncTime = NTP_NEVER; // force new NTP query + ntpLastSyncTime = NTP_NEVER; // force new NTP query strip.restartRuntime(); } - if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) - { // lastMqttReconnectAttempt==0 forces immediate broadcast + if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast lastMqttReconnectAttempt = millis(); -#ifndef WLED_DISABLE_MQTT + #ifndef WLED_DISABLE_MQTT initMqtt(); -#endif + #endif yield(); // refresh WLED nodes list refreshNodeList(); - if (nodeBroadcastEnabled) - sendSysInfoUDP(); + if (nodeBroadcastEnabled) sendSysInfoUDP(); yield(); } // 15min PIN time-out - if (strlen(settingsPIN) > 0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) - { + if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) { correctPIN = false; createEditHandler(false); } - // LED settings have been saved, re-init busses - // This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate! - if (doInitBusses) - { + //LED settings have been saved, re-init busses + //This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate! + if (doInitBusses) { doInitBusses = false; DEBUG_PRINTLN(F("Re-init busses.")); - bool aligned = strip.checkSegmentAlignment(); // see if old segments match old bus(ses) + bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) busses.removeAll(); uint32_t mem = 0, globalBufMem = 0; uint16_t maxlen = 0; - for (uint8_t i = 0; i < WLED_MAX_BUSSES + WLED_MIN_VIRTUAL_BUSSES; i++) - { - if (busConfigs[i] == nullptr) - break; + for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { + if (busConfigs[i] == nullptr) break; mem += BusManager::memUsage(*busConfigs[i]); - if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) - { - maxlen = busConfigs[i]->start + busConfigs[i]->count; - globalBufMem = maxlen * 4; + if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) { + maxlen = busConfigs[i]->start + busConfigs[i]->count; + globalBufMem = maxlen * 4; } - if (mem + globalBufMem <= MAX_LED_MEMORY) - { + if (mem + globalBufMem <= MAX_LED_MEMORY) { busses.add(*busConfigs[i]); } - delete busConfigs[i]; - busConfigs[i] = nullptr; + delete busConfigs[i]; busConfigs[i] = nullptr; } strip.finalizeInit(); // also loads default ledmap if present - if (aligned) - strip.makeAutoSegments(); - else - strip.fixInvalidSegments(); + if (aligned) strip.makeAutoSegments(); + else strip.fixInvalidSegments(); doSerializeConfig = true; } - if (loadLedmap >= 0) - { - if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) - strip.setUpMatrix(); + if (loadLedmap >= 0) { + if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix(); loadLedmap = -1; } yield(); - if (doSerializeConfig) - serializeConfig(); + if (doSerializeConfig) serializeConfig(); yield(); handleWs(); @@ -224,13 +196,12 @@ void WLED::loop() #if WLED_WATCHDOG_TIMEOUT > 0 // we finished our mainloop, reset the watchdog timer static unsigned long lastWDTFeed = 0; - if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT * 500)) - { -#ifdef ARDUINO_ARCH_ESP32 + if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT*500)) { + #ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_reset(); -#else + #else ESP.wdtFeed(); -#endif + #endif lastWDTFeed = millis(); } #endif @@ -241,65 +212,38 @@ void WLED::loop() // DEBUG serial logging (every 30s) #ifdef WLED_DEBUG loopMillis = millis() - loopMillis; - if (loopMillis > 30) - { + if (loopMillis > 30) { DEBUG_PRINTF("Loop took %lums.\n", loopMillis); DEBUG_PRINTF("Usermods took %lums.\n", usermodMillis); DEBUG_PRINTF("Strip took %lums.\n", stripMillis); } avgLoopMillis += loopMillis; - if (loopMillis > maxLoopMillis) - maxLoopMillis = loopMillis; - if (millis() - debugTime > 29999) - { + if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis; + if (millis() - debugTime > 29999) { DEBUG_PRINTLN(F("---DEBUG INFO---")); - DEBUG_PRINT(F("Runtime: ")); - DEBUG_PRINTLN(millis()); - DEBUG_PRINT(F("Unix time: ")); - toki.printTime(toki.getTime()); - DEBUG_PRINT(F("Free heap: ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); -#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) - if (psramFound()) - { - DEBUG_PRINT(F("Total PSRAM: ")); - DEBUG_PRINT(ESP.getPsramSize() / 1024); - DEBUG_PRINTLN("kB"); - DEBUG_PRINT(F("Free PSRAM: ")); - DEBUG_PRINT(ESP.getFreePsram() / 1024); - DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis()); + DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime()); + DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) + if (psramFound()) { + DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); } -#endif - DEBUG_PRINT(F("Wifi state: ")); - DEBUG_PRINTLN(WiFi.status()); + #endif + DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status()); - if (WiFi.status() != lastWifiState) - { + if (WiFi.status() != lastWifiState) { wifiStateChangedTime = millis(); } lastWifiState = WiFi.status(); - DEBUG_PRINT(F("State time: ")); - DEBUG_PRINTLN(wifiStateChangedTime); - DEBUG_PRINT(F("NTP last sync: ")); - DEBUG_PRINTLN(ntpLastSyncTime); - DEBUG_PRINT(F("Client IP: ")); - DEBUG_PRINTLN(Network.localIP()); - if (loops > 0) - { // avoid division by zero - DEBUG_PRINT(F("Loops/sec: ")); - DEBUG_PRINTLN(loops / 30); - DEBUG_PRINT(F("Loop time[ms]: ")); - DEBUG_PRINT(avgLoopMillis / loops); - DEBUG_PRINT("/"); - DEBUG_PRINTLN(maxLoopMillis); - DEBUG_PRINT(F("UM time[ms]: ")); - DEBUG_PRINT(avgUsermodMillis / loops); - DEBUG_PRINT("/"); - DEBUG_PRINTLN(maxUsermodMillis); - DEBUG_PRINT(F("Strip time[ms]: ")); - DEBUG_PRINT(avgStripMillis / loops); - DEBUG_PRINT("/"); - DEBUG_PRINTLN(maxStripMillis); + DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime); + DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime); + DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP()); + if (loops > 0) { // avoid division by zero + DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30); + DEBUG_PRINT(F("Loop time[ms]: ")); DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis); + DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis); + DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis); } strip.printSize(); loops = 0; @@ -312,21 +256,17 @@ void WLED::loop() } loops++; lastRun = millis(); -#endif // WLED_DEBUG +#endif // WLED_DEBUG } -void WLED::enableWatchdog() -{ +void WLED::enableWatchdog() { #if WLED_WATCHDOG_TIMEOUT > 0 #ifdef ARDUINO_ARCH_ESP32 esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true); DEBUG_PRINT(F("Watchdog enabled: ")); - if (watchdog == ESP_OK) - { + if (watchdog == ESP_OK) { DEBUG_PRINTLN(F("OK")); - } - else - { + } else { DEBUG_PRINTLN(watchdog); return; } @@ -337,10 +277,9 @@ void WLED::enableWatchdog() #endif } -void WLED::disableWatchdog() -{ +void WLED::disableWatchdog() { #if WLED_WATCHDOG_TIMEOUT > 0 - DEBUG_PRINTLN(F("Watchdog: disabled")); +DEBUG_PRINTLN(F("Watchdog: disabled")); #ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_delete(NULL); #else @@ -351,25 +290,24 @@ void WLED::disableWatchdog() void WLED::setup() { -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detection -#endif + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detection + #endif -#ifdef ARDUINO_ARCH_ESP32 - pinMode(hardwareRX, INPUT_PULLDOWN); - delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 -#endif + #ifdef ARDUINO_ARCH_ESP32 + pinMode(hardwareRX, INPUT_PULLDOWN); delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 + #endif Serial.begin(115200); -#if !ARDUINO_USB_CDC_ON_BOOT - Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC) -#else -#endif -#if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT) - delay(2500); // allow CDC USB serial to initialise -#endif -#if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT + #if !ARDUINO_USB_CDC_ON_BOOT + Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC) + #else + #endif + #if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT) + delay(2500); // allow CDC USB serial to initialise + #endif + #if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC -#endif + #endif DEBUG_PRINTLN(); DEBUG_PRINT(F("---WLED ")); DEBUG_PRINT(versionString); @@ -379,114 +317,86 @@ void WLED::setup() #ifdef ARDUINO_ARCH_ESP32 DEBUG_PRINT(F("esp32 ")); DEBUG_PRINTLN(ESP.getSdkVersion()); -#if defined(ESP_ARDUINO_VERSION) - // DEBUG_PRINTF(F("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION); - DEBUG_PRINTF("arduino-esp32 v%d.%d.%d\n", int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0 -#else - DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. -#endif - - DEBUG_PRINT(F("CPU: ")); - DEBUG_PRINT(ESP.getChipModel()); - DEBUG_PRINT(F(" rev.")); - DEBUG_PRINT(ESP.getChipRevision()); - DEBUG_PRINT(F(", ")); - DEBUG_PRINT(ESP.getChipCores()); - DEBUG_PRINT(F(" core(s)")); - DEBUG_PRINT(F(", ")); - DEBUG_PRINT(ESP.getCpuFreqMHz()); - DEBUG_PRINTLN(F("MHz.")); - DEBUG_PRINT(F("FLASH: ")); - DEBUG_PRINT((ESP.getFlashChipSize() / 1024) / 1024); - DEBUG_PRINT(F("MB, Mode ")); - DEBUG_PRINT(ESP.getFlashChipMode()); -#ifdef WLED_DEBUG - switch (ESP.getFlashChipMode()) - { - // missing: Octal modes - case FM_QIO: - DEBUG_PRINT(F(" (QIO)")); - break; - case FM_QOUT: - DEBUG_PRINT(F(" (QOUT)")); - break; - case FM_DIO: - DEBUG_PRINT(F(" (DIO)")); - break; - case FM_DOUT: - DEBUG_PRINT(F(" (DOUT)")); - break; - default: - break; - } -#endif - DEBUG_PRINT(F(", speed ")); - DEBUG_PRINT(ESP.getFlashChipSpeed() / 1000000); - DEBUG_PRINTLN(F("MHz.")); + #if defined(ESP_ARDUINO_VERSION) + //DEBUG_PRINTF(F("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION); + DEBUG_PRINTF("arduino-esp32 v%d.%d.%d\n", int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0 + #else + DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. + #endif + + DEBUG_PRINT(F("CPU: ")); DEBUG_PRINT(ESP.getChipModel()); + DEBUG_PRINT(F(" rev.")); DEBUG_PRINT(ESP.getChipRevision()); + DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getChipCores()); DEBUG_PRINT(F(" core(s)")); + DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINTLN(F("MHz.")); + DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); + DEBUG_PRINT(F("MB, Mode ")); DEBUG_PRINT(ESP.getFlashChipMode()); + #ifdef WLED_DEBUG + switch (ESP.getFlashChipMode()) { + // missing: Octal modes + case FM_QIO: DEBUG_PRINT(F(" (QIO)")); break; + case FM_QOUT: DEBUG_PRINT(F(" (QOUT)"));break; + case FM_DIO: DEBUG_PRINT(F(" (DIO)")); break; + case FM_DOUT: DEBUG_PRINT(F(" (DOUT)"));break; + default: break; + } + #endif + DEBUG_PRINT(F(", speed ")); DEBUG_PRINT(ESP.getFlashChipSpeed()/1000000);DEBUG_PRINTLN(F("MHz.")); #else DEBUG_PRINT(F("esp8266 ")); DEBUG_PRINTLN(ESP.getCoreVersion()); #endif - DEBUG_PRINT(F("heap ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) -#if defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) // S3: reserve GPIO 33-37 for "octal" PSRAM - managed_pin_type pins[] = {{33, true}, {34, true}, {35, true}, {36, true}, {37, true}}; - pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); -#elif defined(CONFIG_IDF_TARGET_ESP32S2) + managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} }; + pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); + #elif defined(CONFIG_IDF_TARGET_ESP32S2) // S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation) - managed_pin_type pins[] = {{26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true}}; - pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); -#elif defined(CONFIG_IDF_TARGET_ESP32C3) + managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} }; + pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); + #elif defined(CONFIG_IDF_TARGET_ESP32C3) // C3: reserve GPIO 12-17 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation) - managed_pin_type pins[] = {{12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true}}; - pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); -#else + managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} }; + pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); + #else // GPIO16/GPIO17 reserved for SPI RAM - managed_pin_type pins[] = {{16, true}, {17, true}}; - pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); -#endif -#if defined(WLED_USE_PSRAM) - if (psramFound()) - { - DEBUG_PRINT(F("Total PSRAM: ")); - DEBUG_PRINT(ESP.getPsramSize() / 1024); - DEBUG_PRINTLN("kB"); - DEBUG_PRINT(F("Free PSRAM : ")); - DEBUG_PRINT(ESP.getFreePsram() / 1024); - DEBUG_PRINTLN("kB"); - } -#else - DEBUG_PRINTLN(F("PSRAM not used.")); -#endif + managed_pin_type pins[] = { {16, true}, {17, true} }; + pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); + #endif + #if defined(WLED_USE_PSRAM) + if (psramFound()) { + DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); + } + #else + DEBUG_PRINTLN(F("PSRAM not used.")); + #endif #endif #if defined(ARDUINO_ESP32_PICO) - // special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM) - managed_pin_type pins[] = {{16, true}, {17, true}}; - pinManager.allocateMultiplePins(pins, sizeof(pins) / sizeof(managed_pin_type), PinOwner::SPI_RAM); +// special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM) +managed_pin_type pins[] = { {16, true}, {17, true} }; +pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); #endif - // DEBUG_PRINT(F("LEDs inited. heap usage ~")); - // DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); + //DEBUG_PRINT(F("LEDs inited. heap usage ~")); + //DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); #ifdef WLED_DEBUG pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif -#ifdef WLED_ENABLE_DMX // reserve GPIO2 as hardcoded DMX pin +#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin pinManager.allocatePin(2, true, PinOwner::DMX); #endif DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); - DEBUG_PRINT(F("heap ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); - for (uint8_t i = 1; i < WLED_MAX_BUTTONS; i++) - btnPin[i] = -1; + for (uint8_t i=1; i= 0 - if (!pinManager.isPinAllocated(STATUSLED)) - { +#if defined(STATUSLED) && STATUSLED>=0 + if (!pinManager.isPinAllocated(STATUSLED)) { // NOTE: Special case: The status LED should *NOT* be allocated. // See comments in handleStatusLed(). pinMode(STATUSLED, OUTPUT); @@ -529,62 +436,52 @@ void WLED::setup() DEBUG_PRINTLN(F("Initializing strip")); beginStrip(); - DEBUG_PRINT(F("heap ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINTLN(F("Usermods setup")); userSetup(); usermods.setup(); - DEBUG_PRINT(F("heap ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) showWelcomePage = true; WiFi.persistent(false); -#ifdef WLED_USE_ETHERNET + #ifdef WLED_USE_ETHERNET WiFi.onEvent(WiFiEvent); -#endif + #endif -#ifdef WLED_ENABLE_ADALIGHT - // Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused - // Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused - if (!pinManager.isPinAllocated(hardwareRX) && !pinManager.isPinAllocated(hardwareTX)) - { + #ifdef WLED_ENABLE_ADALIGHT + //Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused + //Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused + if (!pinManager.isPinAllocated(hardwareRX) && !pinManager.isPinAllocated(hardwareTX)) { Serial.println(F("Ada")); } -#endif + #endif // fill in unique mdns default - if (strcmp(cmDNS, "x") == 0) - sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); + if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); #ifndef WLED_DISABLE_MQTT - if (mqttDeviceTopic[0] == 0) - sprintf_P(mqttDeviceTopic, PSTR("lights/%*s"), 6, escapedMac.c_str() + 6); - if (mqttClientID[0] == 0) - sprintf_P(mqttClientID, PSTR("LIGHTS-%*s"), 6, escapedMac.c_str() + 6); - if (mqttResponseTopic[0] == 0) - snprintf_P(mqttResponseTopic, 36, PSTR("%s/r"), mqttDeviceTopic); + if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6); + if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6); #endif #ifdef WLED_ENABLE_ADALIGHT - if (Serial.available() > 0 && Serial.peek() == 'I') - handleImprovPacket(); + if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); #endif #ifndef WLED_DISABLE_OTA - if (aOtaEnabled) - { - ArduinoOTA.onStart([]() - { + if (aOtaEnabled) { + ArduinoOTA.onStart([]() { #ifdef ESP8266 wifi_set_sleep_type(NONE_SLEEP_T); #endif WLED::instance().disableWatchdog(); - DEBUG_PRINTLN(F("Start ArduinoOTA")); }); - ArduinoOTA.onError([](ota_error_t error) - { + DEBUG_PRINTLN(F("Start ArduinoOTA")); + }); + ArduinoOTA.onError([](ota_error_t error) { // reenable watchdog on failed update - WLED::instance().enableWatchdog(); }); + WLED::instance().enableWatchdog(); + }); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); } @@ -594,21 +491,19 @@ void WLED::setup() #endif #ifdef WLED_ENABLE_ADALIGHT - if (Serial.available() > 0 && Serial.peek() == 'I') - handleImprovPacket(); + if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); #endif // HTTP server page init DEBUG_PRINTLN(F("initServer")); initServer(); - DEBUG_PRINT(F("heap ")); - DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); enableWatchdog(); -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); // enable brownout detector -#endif + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector + #endif } void WLED::beginStrip() @@ -619,29 +514,22 @@ void WLED::beginStrip() strip.setBrightness(0); strip.setShowCallback(handleOverlayDraw); - if (turnOnAtBoot) - { - if (briS > 0) - bri = briS; - else if (bri == 0) - bri = 128; - } - else - { + if (turnOnAtBoot) { + if (briS > 0) bri = briS; + else if (bri == 0) bri = 128; + } else { // fix for #3196 - briLast = briS; - bri = 0; + briLast = briS; bri = 0; strip.fill(BLACK); strip.show(); } - if (bootPreset > 0) - { + if (bootPreset > 0) { applyPreset(bootPreset, CALL_MODE_INIT); } colorUpdated(CALL_MODE_INIT); // init relay pin - if (rlyPin >= 0) + if (rlyPin>=0) digitalWrite(rlyPin, (rlyMde ? bri : !bri)); } @@ -650,8 +538,7 @@ void WLED::initAP(bool resetAP) if (apBehavior == AP_BEHAVIOR_BUTTON_ONLY && !resetAP) return; - if (resetAP) - { + if (resetAP) { WLED_SET_AP_SSID(); strcpy_P(apPass, PSTR(WLED_AP_PASS)); } @@ -659,24 +546,21 @@ void WLED::initAP(bool resetAP) DEBUG_PRINTLN(apSSID); WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0)); WiFi.softAP(apSSID, apPass, apChannel, apHide); -#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) + #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WiFi.setTxPower(WIFI_POWER_8_5dBm); -#endif + #endif if (!apActive) // start captive portal if AP active { DEBUG_PRINTLN(F("Init AP interfaces")); server.begin(); - if (udpPort > 0 && udpPort != ntpLocalPort) - { + if (udpPort > 0 && udpPort != ntpLocalPort) { udpConnected = notifierUdp.begin(udpPort); } - if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) - { + if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) { udpRgbConnected = rgbUdp.begin(udpRgbPort); } - if (udpPort2 > 0 && udpPort2 != ntpLocalPort && udpPort2 != udpPort && udpPort2 != udpRgbPort) - { + if (udpPort2 > 0 && udpPort2 != ntpLocalPort && udpPort2 != udpPort && udpPort2 != udpRgbPort) { udp2Connected = notifier2Udp.begin(udpPort2); } e131.begin(false, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT); @@ -694,106 +578,89 @@ bool WLED::initEthernet() static bool successfullyConfiguredEthernet = false; - if (successfullyConfiguredEthernet) - { + if (successfullyConfiguredEthernet) { // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); return false; } - if (ethernetType == WLED_ETH_NONE) - { + if (ethernetType == WLED_ETH_NONE) { return false; } - if (ethernetType >= WLED_NUM_ETH_TYPES) - { - DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); - DEBUG_PRINTLN(ethernetType); + if (ethernetType >= WLED_NUM_ETH_TYPES) { + DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); DEBUG_PRINTLN(ethernetType); return false; } - DEBUG_PRINT(F("initE: Attempting ETH config: ")); - DEBUG_PRINTLN(ethernetType); + DEBUG_PRINT(F("initE: Attempting ETH config: ")); DEBUG_PRINTLN(ethernetType); // Ethernet initialization should only succeed once -- else reboot required ethernet_settings es = ethernetBoards[ethernetType]; managed_pin_type pinsToAllocate[10] = { - // first six pins are non-configurable - esp32_nonconfigurable_ethernet_pins[0], - esp32_nonconfigurable_ethernet_pins[1], - esp32_nonconfigurable_ethernet_pins[2], - esp32_nonconfigurable_ethernet_pins[3], - esp32_nonconfigurable_ethernet_pins[4], - esp32_nonconfigurable_ethernet_pins[5], - {(int8_t)es.eth_mdc, true}, // [6] = MDC is output and mandatory - {(int8_t)es.eth_mdio, true}, // [7] = MDIO is bidirectional and mandatory - {(int8_t)es.eth_power, true}, // [8] = optional pin, not all boards use - {((int8_t)0xFE), false}, // [9] = replaced with eth_clk_mode, mandatory + // first six pins are non-configurable + esp32_nonconfigurable_ethernet_pins[0], + esp32_nonconfigurable_ethernet_pins[1], + esp32_nonconfigurable_ethernet_pins[2], + esp32_nonconfigurable_ethernet_pins[3], + esp32_nonconfigurable_ethernet_pins[4], + esp32_nonconfigurable_ethernet_pins[5], + { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory + { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory + { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use + { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory }; // update the clock pin.... - if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) - { + if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { pinsToAllocate[9].pin = 0; pinsToAllocate[9].isOutput = false; - } - else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) - { + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { pinsToAllocate[9].pin = 0; pinsToAllocate[9].isOutput = true; - } - else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) - { + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { pinsToAllocate[9].pin = 16; pinsToAllocate[9].isOutput = true; - } - else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) - { + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { pinsToAllocate[9].pin = 17; pinsToAllocate[9].isOutput = true; - } - else - { + } else { DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode (")); DEBUG_PRINT(es.eth_clk_mode); DEBUG_PRINTLN(")"); return false; } - if (!pinManager.allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) - { + if (!pinManager.allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); return false; } -/* -For LAN8720 the most correct way is to perform clean reset each time before init -applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) -ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in -/components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) -but ESP_IDF < V4 does not. Lets do it: -[not always needed, might be relevant in some EMI situations at startup and for hot resets] -*/ -#if ESP_IDF_VERSION_MAJOR == 3 - if (es.eth_power > 0 && es.eth_type == ETH_PHY_LAN8720) - { + /* + For LAN8720 the most correct way is to perform clean reset each time before init + applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) + ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in + /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) + but ESP_IDF < V4 does not. Lets do it: + [not always needed, might be relevant in some EMI situations at startup and for hot resets] + */ + #if ESP_IDF_VERSION_MAJOR==3 + if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { pinMode(es.eth_power, OUTPUT); digitalWrite(es.eth_power, 0); delayMicroseconds(150); digitalWrite(es.eth_power, 1); delayMicroseconds(10); } -#endif + #endif if (!ETH.begin( - (uint8_t)es.eth_address, - (int)es.eth_power, - (int)es.eth_mdc, - (int)es.eth_mdio, - (eth_phy_type_t)es.eth_type, - (eth_clock_mode_t)es.eth_clk_mode)) - { + (uint8_t) es.eth_address, + (int) es.eth_power, + (int) es.eth_mdc, + (int) es.eth_mdio, + (eth_phy_type_t) es.eth_type, + (eth_clock_mode_t) es.eth_clk_mode + )) { DEBUG_PRINTLN(F("initC: ETH.begin() failed")); // de-allocate the allocated pins - for (managed_pin_type mpt : pinsToAllocate) - { + for (managed_pin_type mpt : pinsToAllocate) { pinManager.deallocatePin(mpt.pin, PinOwner::Ethernet); } return false; @@ -805,46 +672,37 @@ but ESP_IDF < V4 does not. Lets do it: #else return false; // Ethernet not enabled for build #endif + } void WLED::initConnection() { -#ifdef WLED_ENABLE_WEBSOCKETS + #ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); -#endif + #endif - WiFi.disconnect(true); // close old connections + WiFi.disconnect(true); // close old connections #ifdef ESP8266 WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N); #endif - if (staticIP[0] != 0 && staticGateway[0] != 0) - { + if (staticIP[0] != 0 && staticGateway[0] != 0) { WiFi.config(staticIP, staticGateway, staticSubnet, IPAddress(1, 1, 1, 1)); - } - else - { + } else { WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0)); } lastReconnectAttempt = millis(); - if (!WLED_WIFI_CONFIGURED) - { + if (!WLED_WIFI_CONFIGURED) { DEBUG_PRINTLN(F("No connection configured.")); - if (!apActive) - initAP(); // instantly go to ap mode + if (!apActive) initAP(); // instantly go to ap mode return; - } - else if (!apActive) - { - if (apBehavior == AP_BEHAVIOR_ALWAYS) - { + } else if (!apActive) { + if (apBehavior == AP_BEHAVIOR_ALWAYS) { DEBUG_PRINTLN(F("Access point ALWAYS enabled.")); initAP(); - } - else - { + } else { DEBUG_PRINTLN(F("Access point disabled (init).")); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); @@ -866,9 +724,9 @@ void WLED::initConnection() WiFi.begin(clientSSID, clientPass); #ifdef ARDUINO_ARCH_ESP32 -#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) + #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WiFi.setTxPower(WIFI_POWER_8_5dBm); -#endif + #endif WiFi.setSleep(!noWifiSleep); WiFi.setHostname(hostname); #else @@ -882,8 +740,7 @@ void WLED::initInterfaces() #ifndef WLED_DISABLE_HUESYNC IPAddress ipAddress = Network.localIP(); - if (hueIP[0] == 0) - { + if (hueIP[0] == 0) { hueIP[0] = ipAddress[0]; hueIP[1] = ipAddress[1]; hueIP[2] = ipAddress[2]; @@ -902,8 +759,7 @@ void WLED::initInterfaces() #endif // Set up mDNS responder: - if (strlen(cmDNS) > 0) - { + if (strlen(cmDNS) > 0) { // "end" must be called before "begin" is called a 2nd time // see https://github.com/esp8266/Arduino/issues/7213 MDNS.end(); @@ -916,8 +772,7 @@ void WLED::initInterfaces() } server.begin(); - if (udpPort > 0 && udpPort != ntpLocalPort) - { + if (udpPort > 0 && udpPort != ntpLocalPort) { udpConnected = notifierUdp.begin(udpPort); if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort); @@ -947,26 +802,21 @@ void WLED::handleConnection() if (now < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS)) return; - if (lastReconnectAttempt == 0) - { + if (lastReconnectAttempt == 0) { DEBUG_PRINTLN(F("lastReconnectAttempt == 0")); initConnection(); return; } // reconnect WiFi to clear stale allocations if heap gets too low - if (now - heapTime > 5000) - { + if (now - heapTime > 5000) { uint32_t heap = ESP.getFreeHeap(); - if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) - { + if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap); forceReconnect = true; strip.purgeSegments(true); // remove all but one segments from memory - } - else if (heap < MIN_HEAP_SIZE) - { + } else if (heap < MIN_HEAP_SIZE) { strip.purgeSegments(); } lastHeap = heap; @@ -974,8 +824,7 @@ void WLED::handleConnection() } byte stac = 0; - if (apActive) - { + if (apActive) { #ifdef ESP8266 stac = wifi_softap_get_station_num(); #else @@ -983,22 +832,19 @@ void WLED::handleConnection() esp_wifi_ap_get_sta_list(&stationList); stac = stationList.num; #endif - if (stac != stacO) - { + if (stac != stacO) { stacO = stac; DEBUG_PRINT(F("Connected AP clients: ")); DEBUG_PRINTLN(stac); - if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) - { // trying to connect, but not connected + if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { // trying to connect, but not connected if (stac) - WiFi.disconnect(); // disable search so that AP can work + WiFi.disconnect(); // disable search so that AP can work else - initConnection(); // restart search + initConnection(); // restart search } } } - if (forceReconnect) - { + if (forceReconnect) { DEBUG_PRINTLN(F("Forcing reconnect.")); initConnection(); interfacesInited = false; @@ -1006,45 +852,34 @@ void WLED::handleConnection() wasConnected = false; return; } - if (!Network.isConnected()) - { - if (interfacesInited) - { + if (!Network.isConnected()) { + if (interfacesInited) { DEBUG_PRINTLN(F("Disconnected!")); interfacesInited = false; initConnection(); } - // send improv failed 6 seconds after second init attempt (24 sec. after provisioning) - if (improvActive > 2 && now - lastReconnectAttempt > 6000) - { + //send improv failed 6 seconds after second init attempt (24 sec. after provisioning) + if (improvActive > 2 && now - lastReconnectAttempt > 6000) { sendImprovStateResponse(0x03, true); improvActive = 2; } - if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) - { - if (improvActive == 2) - improvActive = 3; + if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) { + if (improvActive == 2) improvActive = 3; DEBUG_PRINTLN(F("Last reconnect too old.")); initConnection(); } - if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) - { + if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) { DEBUG_PRINTLN(F("Not connected AP.")); initAP(); } - } - else if (!interfacesInited) - { // newly connected + } else if (!interfacesInited) { //newly connected DEBUG_PRINTLN(""); DEBUG_PRINT(F("Connected! IP address: ")); DEBUG_PRINTLN(Network.localIP()); - if (improvActive) - { - if (improvError == 3) - sendImprovStateResponse(0x00, true); + if (improvActive) { + if (improvError == 3) sendImprovStateResponse(0x00, true); sendImprovStateResponse(0x04); - if (improvActive > 1) - sendImprovIPRPCResult(ImprovRPCType::Command_Wifi); + if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi); } initInterfaces(); userConnected(); @@ -1052,8 +887,7 @@ void WLED::handleConnection() lastMqttReconnectAttempt = 0; // force immediate update // shut down AP - if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) - { + if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) { dnsServer.stop(); WiFi.softAPdisconnect(true); apActive = false; @@ -1068,55 +902,45 @@ void WLED::handleConnection() // else turn the status LED off void WLED::handleStatusLED() { -#if defined(STATUSLED) + #if defined(STATUSLED) uint32_t c = 0; -#if STATUSLED >= 0 - if (pinManager.isPinAllocated(STATUSLED)) - { - return; // lower priority if something else uses the same pin + #if STATUSLED>=0 + if (pinManager.isPinAllocated(STATUSLED)) { + return; //lower priority if something else uses the same pin } -#endif + #endif - if (WLED_CONNECTED) - { - c = RGBW32(0, 255, 0, 0); + if (WLED_CONNECTED) { + c = RGBW32(0,255,0,0); ledStatusType = 2; - } - else if (WLED_MQTT_CONNECTED) - { - c = RGBW32(0, 128, 0, 0); + } else if (WLED_MQTT_CONNECTED) { + c = RGBW32(0,128,0,0); ledStatusType = 4; - } - else if (apActive) - { - c = RGBW32(0, 0, 255, 0); + } else if (apActive) { + c = RGBW32(0,0,255,0); ledStatusType = 1; } - if (ledStatusType) - { - if (millis() - ledStatusLastMillis >= (1000 / ledStatusType)) - { + if (ledStatusType) { + if (millis() - ledStatusLastMillis >= (1000/ledStatusType)) { ledStatusLastMillis = millis(); ledStatusState = !ledStatusState; -#if STATUSLED >= 0 + #if STATUSLED>=0 digitalWrite(STATUSLED, ledStatusState); -#else + #else busses.setStatusPixel(ledStatusState ? c : 0); -#endif + #endif } - } - else - { -#if STATUSLED >= 0 -#ifdef STATUSLEDINVERTED - digitalWrite(STATUSLED, HIGH); -#else - digitalWrite(STATUSLED, LOW); -#endif -#else - busses.setStatusPixel(0); -#endif - } -#endif + } else { + #if STATUSLED>=0 + #ifdef STATUSLEDINVERTED + digitalWrite(STATUSLED, HIGH); + #else + digitalWrite(STATUSLED, LOW); + #endif + #else + busses.setStatusPixel(0); + #endif + } + #endif } diff --git a/wled00/wled.h b/wled00/wled.h index aafbd3bf2c..5d4cca4e93 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -10,8 +10,8 @@ // version code in format yymmddb (b = daily build) #define VERSION 2405180 -// uncomment this if you have a "my_config.h" file you'd like to use -// #define WLED_USE_MY_CONFIG +//uncomment this if you have a "my_config.h" file you'd like to use +//#define WLED_USE_MY_CONFIG // ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit. @@ -21,83 +21,83 @@ // Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini // You are required to disable over-the-air updates: -// #define WLED_DISABLE_OTA // saves 14kb +//#define WLED_DISABLE_OTA // saves 14kb // You can choose some of these features to disable: -// #define WLED_DISABLE_ALEXA // saves 11kb -// #define WLED_DISABLE_HUESYNC // saves 4kb -// #define WLED_DISABLE_INFRARED // saves 12kb, there is no pin left for this on ESP8266-01 +//#define WLED_DISABLE_ALEXA // saves 11kb +//#define WLED_DISABLE_HUESYNC // saves 4kb +//#define WLED_DISABLE_INFRARED // saves 12kb, there is no pin left for this on ESP8266-01 #ifndef WLED_DISABLE_MQTT -#define WLED_ENABLE_MQTT // saves 12kb + #define WLED_ENABLE_MQTT // saves 12kb #endif -#ifndef WLED_DISABLE_ADALIGHT // can be used to disable reading commands from serial RX pin (see issue #3128). -#define WLED_ENABLE_ADALIGHT // disable saves 5Kb (uses GPIO3 (RX) for serial). Related serial protocols: Adalight/TPM2, Improv, Serial JSON, Continuous Serial Streaming +#ifndef WLED_DISABLE_ADALIGHT // can be used to disable reading commands from serial RX pin (see issue #3128). + #define WLED_ENABLE_ADALIGHT // disable saves 5Kb (uses GPIO3 (RX) for serial). Related serial protocols: Adalight/TPM2, Improv, Serial JSON, Continuous Serial Streaming #else -#undef WLED_ENABLE_ADALIGHT // disable has priority over enable + #undef WLED_ENABLE_ADALIGHT // disable has priority over enable #endif -// #define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) -#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) +//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) +#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) #ifndef WLED_DISABLE_LOXONE -#define WLED_ENABLE_LOXONE // uses 1.2kb + #define WLED_ENABLE_LOXONE // uses 1.2kb #endif #ifndef WLED_DISABLE_WEBSOCKETS -#define WLED_ENABLE_WEBSOCKETS + #define WLED_ENABLE_WEBSOCKETS #endif -// #define WLED_DISABLE_ESPNOW // Removes dependence on esp now +//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now -#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock +#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock // to toggle usb serial debug (un)comment the following line -// #define WLED_DEBUG +//#define WLED_DEBUG // filesystem specific debugging -// #define WLED_DEBUG_FS +//#define WLED_DEBUG_FS #ifndef WLED_WATCHDOG_TIMEOUT -// 3 seconds should be enough to detect a lockup -// define WLED_WATCHDOG_TIMEOUT=0 to disable watchdog, default -#define WLED_WATCHDOG_TIMEOUT 0 + // 3 seconds should be enough to detect a lockup + // define WLED_WATCHDOG_TIMEOUT=0 to disable watchdog, default + #define WLED_WATCHDOG_TIMEOUT 0 #endif -// optionally disable brownout detector on ESP32. -// This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks -// #define WLED_DISABLE_BROWNOUT_DET +//optionally disable brownout detector on ESP32. +//This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks +//#define WLED_DISABLE_BROWNOUT_DET // Library inclusions. #include #ifdef ESP8266 -#include -#include -#include -#include -extern "C" -{ -#include -} -#ifndef WLED_DISABLE_ESPNOW -#include -#endif -#else // ESP32 -#include // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT) -#include -#include -#include "esp_wifi.h" -#include -#include -#if LOROL_LITTLEFS -#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 -#define CONFIG_LITTLEFS_FOR_IDF_3_2 -#endif -#include -#else -#include -#endif -#include "esp_task_wdt.h" - -#ifndef WLED_DISABLE_ESPNOW -#include -#endif + #include + #include + #include + #include + extern "C" + { + #include + } + #ifndef WLED_DISABLE_ESPNOW + #include + #endif +#else // ESP32 + #include // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT) + #include + #include + #include "esp_wifi.h" + #include + #include + #if LOROL_LITTLEFS + #ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 + #define CONFIG_LITTLEFS_FOR_IDF_3_2 + #endif + #include + #else + #include + #endif + #include "esp_task_wdt.h" + + #ifndef WLED_DISABLE_ESPNOW + #include + #endif #endif #include #include @@ -105,18 +105,18 @@ extern "C" #include "src/dependencies/network/Network.h" #ifdef WLED_USE_MY_CONFIG -#include "my_config.h" + #include "my_config.h" #endif #include #ifdef WLED_ADD_EEPROM_SUPPORT -#include + #include #endif #include #include #ifndef WLED_DISABLE_OTA -#define NO_OTA_PORT -#include + #define NO_OTA_PORT + #include #endif #include #include "src/dependencies/time/TimeLib.h" @@ -124,20 +124,20 @@ extern "C" #include "src/dependencies/toki/Toki.h" #ifndef WLED_DISABLE_ALEXA -#define ESPALEXA_ASYNC -#define ESPALEXA_NO_SUBPAGE -#define ESPALEXA_MAXDEVICES 10 -// #define ESPALEXA_DEBUG -#include "src/dependencies/espalexa/Espalexa.h" -#include "src/dependencies/espalexa/EspalexaDevice.h" + #define ESPALEXA_ASYNC + #define ESPALEXA_NO_SUBPAGE + #define ESPALEXA_MAXDEVICES 10 + // #define ESPALEXA_DEBUG + #include "src/dependencies/espalexa/Espalexa.h" + #include "src/dependencies/espalexa/EspalexaDevice.h" #endif #ifdef WLED_ENABLE_DMX -#ifdef ESP8266 -#include "src/dependencies/dmx/ESPDMX.h" -#else // ESP32 -#include "src/dependencies/dmx/SparkFunDMX.h" -#endif + #ifdef ESP8266 + #include "src/dependencies/dmx/ESPDMX.h" + #else //ESP32 + #include "src/dependencies/dmx/SparkFunDMX.h" + #endif #endif #include "src/dependencies/e131/ESPAsyncE131.h" @@ -155,24 +155,16 @@ extern "C" // There is a code that will still not use PSRAM though: // AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h) #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM) -struct PSRAM_Allocator -{ - void *allocate(size_t size) - { - if (psramFound()) - return ps_malloc(size); // use PSRAM if it exists - else - return malloc(size); // fallback +struct PSRAM_Allocator { + void* allocate(size_t size) { + if (psramFound()) return ps_malloc(size); // use PSRAM if it exists + else return malloc(size); // fallback } - void *reallocate(void *ptr, size_t new_size) - { - if (psramFound()) - return ps_realloc(ptr, new_size); // use PSRAM if it exists - else - return realloc(ptr, new_size); // fallback + void* reallocate(void* ptr, size_t new_size) { + if (psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists + else return realloc(ptr, new_size); // fallback } - void deallocate(void *pointer) - { + void deallocate(void* pointer) { free(pointer); } }; @@ -189,77 +181,77 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #include "FX.h" #ifndef CLIENT_SSID -#define CLIENT_SSID DEFAULT_CLIENT_SSID + #define CLIENT_SSID DEFAULT_CLIENT_SSID #endif #ifndef CLIENT_PASS -#define CLIENT_PASS "" + #define CLIENT_PASS "" #endif #ifndef MDNS_NAME -#define MDNS_NAME DEFAULT_MDNS_NAME + #define MDNS_NAME DEFAULT_MDNS_NAME #endif #if defined(WLED_AP_PASS) && !defined(WLED_AP_SSID) -#error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \ + #error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \ Please change WLED_AP_SSID to something unique. #endif #ifndef WLED_AP_SSID -#define WLED_AP_SSID DEFAULT_AP_SSID + #define WLED_AP_SSID DEFAULT_AP_SSID #endif #ifndef WLED_AP_PASS -#define WLED_AP_PASS DEFAULT_AP_PASS + #define WLED_AP_PASS DEFAULT_AP_PASS #endif #ifndef SPIFFS_EDITOR_AIRCOOOKIE -#error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\ + #error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\ Using upstream puts your WiFi password at risk of being served by the filesystem.\ Comment out this error message to build regardless. #endif #ifndef WLED_DISABLE_INFRARED -#include -#include -#include + #include + #include + #include #endif -// Filesystem to use for preset and config files. SPIFFS or LittleFS on ESP8266, SPIFFS only on ESP32 (now using LITTLEFS port by lorol) +//Filesystem to use for preset and config files. SPIFFS or LittleFS on ESP8266, SPIFFS only on ESP32 (now using LITTLEFS port by lorol) #ifdef ESP8266 -#define WLED_FS LittleFS -#else -#if LOROL_LITTLEFS -#define WLED_FS LITTLEFS + #define WLED_FS LittleFS #else -#define WLED_FS LittleFS -#endif + #if LOROL_LITTLEFS + #define WLED_FS LITTLEFS + #else + #define WLED_FS LittleFS + #endif #endif // GLOBAL VARIABLES // both declared and defined in header (solution from http://www.keil.com/support/docs/1868.htm) // -// e.g. byte test = 2 becomes WLED_GLOBAL byte test _INIT(2); +//e.g. byte test = 2 becomes WLED_GLOBAL byte test _INIT(2); // int arr[]{0,1,2} becomes WLED_GLOBAL int arr[] _INIT_N(({0,1,2})); #ifndef WLED_DEFINE_GLOBAL_VARS -#define WLED_GLOBAL extern -#define _INIT(x) -#define _INIT_N(x) +# define WLED_GLOBAL extern +# define _INIT(x) +# define _INIT_N(x) #else -#define WLED_GLOBAL -#define _INIT(x) = x +# define WLED_GLOBAL +# define _INIT(x) = x -// needed to ignore commas in array definitions -#define UNPACK(...) __VA_ARGS__ -#define _INIT_N(x) UNPACK x +//needed to ignore commas in array definitions +#define UNPACK( ... ) __VA_ARGS__ +# define _INIT_N(x) UNPACK x #endif #define STRINGIFY(X) #X #define TOSTRING(X) STRINGIFY(X) #ifndef WLED_VERSION -#define WLED_VERSION "dev" + #define WLED_VERSION "dev" #endif // Global Variable definitions @@ -267,9 +259,8 @@ WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); #define WLED_CODENAME "Hoshi" // AP and OTA default passwords (for maximum security change them!) -WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); +WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); -WLED_GLOBAL bool otaInProgress _INIT(false); // Hardware and pin config #ifndef BTNPIN @@ -282,7 +273,7 @@ WLED_GLOBAL int8_t rlyPin _INIT(-1); #else WLED_GLOBAL int8_t rlyPin _INIT(RLYPIN); #endif -// Relay mode (1 = active high, 0 = active low, flipped in cfg.json) +//Relay mode (1 = active high, 0 = active low, flipped in cfg.json) #ifndef RLYMDE WLED_GLOBAL bool rlyMde _INIT(true); #else @@ -295,132 +286,132 @@ WLED_GLOBAL int8_t irPin _INIT(IRPIN); #endif #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || (defined(RX) && defined(TX)) -// use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1 -constexpr uint8_t hardwareRX = RX; -constexpr uint8_t hardwareTX = TX; + // use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1 + constexpr uint8_t hardwareRX = RX; + constexpr uint8_t hardwareTX = TX; #else -// use defaults for RX/TX -constexpr uint8_t hardwareRX = 3; -constexpr uint8_t hardwareTX = 1; + // use defaults for RX/TX + constexpr uint8_t hardwareRX = 3; + constexpr uint8_t hardwareTX = 1; #endif -// WLED_GLOBAL byte presetToApply _INIT(0); +//WLED_GLOBAL byte presetToApply _INIT(0); -WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use +WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use // WiFi CONFIG (all these can be changed via web UI, no need to set them here) WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID); WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS); -WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) -WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) -WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) -WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID -WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default -WLED_GLOBAL IPAddress staticIP _INIT_N(((0, 0, 0, 0))); // static IP of ESP -WLED_GLOBAL IPAddress staticGateway _INIT_N(((0, 0, 0, 0))); // gateway (router) IP -WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks +WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) +WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) +WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) +WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID +WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default +WLED_GLOBAL IPAddress staticIP _INIT_N((( 0, 0, 0, 0))); // static IP of ESP +WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP +WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks #ifdef ARDUINO_ARCH_ESP32 -WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues +WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues #else WLED_GLOBAL bool noWifiSleep _INIT(false); #endif WLED_GLOBAL bool force802_3g _INIT(false); #ifdef WLED_USE_ETHERNET -#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified -WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type -#else -WLED_GLOBAL int ethernetType _INIT(WLED_ETH_NONE); // use none for ethernet board type if default not defined -#endif + #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified + WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type + #else + WLED_GLOBAL int ethernetType _INIT(WLED_ETH_NONE); // use none for ethernet board type if default not defined + #endif #endif // LED CONFIG -WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up -WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up +WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up +WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up -// if true, a segment per bus will be created on boot and LED settings save -// if false, only one segment spanning the total LEDs is created, -// but not on LED settings save if there is more than one segment currently -WLED_GLOBAL bool autoSegments _INIT(false); +//if true, a segment per bus will be created on boot and LED settings save +//if false, only one segment spanning the total LEDs is created, +//but not on LED settings save if there is more than one segment currently +WLED_GLOBAL bool autoSegments _INIT(false); #ifdef ESP8266 WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else -WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 +WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 #endif -WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color -WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct -WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors -WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness -WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value +WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color +WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct +WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors +WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness +WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value -WLED_GLOBAL byte col[] _INIT_N(({255, 160, 0, 0})); // current RGB(W) primary color. col[] should be updated if you want to change the color. -WLED_GLOBAL byte colSec[] _INIT_N(({0, 0, 0, 0})); // current RGB(W) secondary color -WLED_GLOBAL byte briS _INIT(128); // default brightness +WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color. +WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color +WLED_GLOBAL byte briS _INIT(128); // default brightness -WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over +WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over WLED_GLOBAL byte nightlightDelayMins _INIT(60); -WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade +WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade -WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) +WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) // User Interface CONFIG #ifndef SERVERNAME -WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use default +WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use default #else -WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name +WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name #endif -WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise -WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI -WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI +WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise +WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI +WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI // Sync CONFIG WLED_GLOBAL NodesMap Nodes; WLED_GLOBAL bool nodeListEnabled _INIT(true); WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true); -WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH}); +WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH}); #if defined(IRTYPE) && defined(IRPIN) -WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver +WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver #else -WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled +WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled #endif -WLED_GLOBAL bool irApplyToAllSelected _INIT(true); // apply IR to all selected segments +WLED_GLOBAL bool irApplyToAllSelected _INIT(true); //apply IR to all selected segments -WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port -WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port +WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port +WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port -WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync groups this instance syncs (bit mapped) -WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) -WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications -WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color -WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup -WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options -WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) -WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API -WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote -WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa -WLED_GLOBAL bool notifyMacro _INIT(false); // send notification for macro -WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes -WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability - -WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo -WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand -WLED_GLOBAL byte alexaNumPresets _INIT(0); // number of presets to expose to Alexa, starting from preset 1, up to 9 - -WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode -WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset -WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP realtime -WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source -WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black +WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync groups this instance syncs (bit mapped) +WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) +WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications +WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color +WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup +WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options +WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) +WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API +WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote +WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa +WLED_GLOBAL bool notifyMacro _INIT(false); // send notification for macro +WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes +WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability + +WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo +WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand +WLED_GLOBAL byte alexaNumPresets _INIT(0); // number of presets to expose to Alexa, starting from preset 1, up to 9 + +WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode +WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset +WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP realtime +WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source +WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black #ifdef WLED_ENABLE_DMX -#ifdef ESP8266 -WLED_GLOBAL DMXESPSerial dmx; -#else // ESP32 -WLED_GLOBAL SparkFunDMX dmx; -#endif -WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled) + #ifdef ESP8266 + WLED_GLOBAL DMXESPSerial dmx; + #else //ESP32 + WLED_GLOBAL SparkFunDMX dmx; + #endif +WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled) #endif WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consecutive universes) WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 @@ -435,36 +426,35 @@ WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze inst WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count number of replies for ArtPoll node report // mqtt -WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too +WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT -#ifndef MQTT_MAX_TOPIC_LEN -#define MQTT_MAX_TOPIC_LEN 32 -#endif -#ifndef MQTT_MAX_SERVER_LEN -#define MQTT_MAX_SERVER_LEN 52 -#endif + #ifndef MQTT_MAX_TOPIC_LEN + #define MQTT_MAX_TOPIC_LEN 32 + #endif + #ifndef MQTT_MAX_SERVER_LEN + #define MQTT_MAX_SERVER_LEN 32 + #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers -WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) -WLED_GLOBAL char mqttResponseTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // MQTT response topic (individual per device, default is lights/mac/r) -WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) -WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) -WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth -WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth -WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID +WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) +WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices) +WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL) +WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth +WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth +WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL uint16_t mqttPort _INIT(1883); -WLED_GLOBAL bool retainMqttMsg _INIT(false); // retain brightness and color +WLED_GLOBAL bool retainMqttMsg _INIT(false); // retain brightness and color #define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected()) #else #define WLED_MQTT_CONNECTED false #endif #ifndef WLED_DISABLE_HUESYNC -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 char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge -WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section) +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 char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge +WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section) WLED_GLOBAL IPAddress hueIP _INIT_N(((0, 0, 0, 0))); // IP address of the bridge WLED_GLOBAL bool hueApplyOnOff _INIT(true); WLED_GLOBAL bool hueApplyBri _INIT(true); @@ -475,53 +465,53 @@ WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 10 #ifndef WLED_DISABLE_ESPNOW WLED_GLOBAL bool enable_espnow_remote _INIT(false); -WLED_GLOBAL char linked_remote[13] _INIT(""); -WLED_GLOBAL char last_signal_src[13] _INIT(""); +WLED_GLOBAL char linked_remote[13] _INIT(""); +WLED_GLOBAL char last_signal_src[13] _INIT(""); #endif // Time CONFIG -WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros -WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format -WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino -WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation +WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros +WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format +WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino +WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation -WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie -WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode +WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie +WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode -WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be -WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel -WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position +WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be +WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel +WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position -WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date -WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits -WLED_GLOBAL byte countdownDay _INIT(1), countdownHour _INIT(0); -WLED_GLOBAL byte countdownMin _INIT(0), countdownSec _INIT(0); +WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date +WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits +WLED_GLOBAL byte countdownDay _INIT(1) , countdownHour _INIT(0); +WLED_GLOBAL byte countdownMin _INIT(0) , countdownSec _INIT(0); -WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over +WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over WLED_GLOBAL byte macroCountdown _INIT(0); WLED_GLOBAL byte macroAlexaOn _INIT(0), macroAlexaOff _INIT(0); -WLED_GLOBAL byte macroButton[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroButton[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); // Security CONFIG -WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks -WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled -WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on -WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages -WLED_GLOBAL bool correctPIN _INIT(true); +WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled +WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on +WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages +WLED_GLOBAL bool correctPIN _INIT(true); WLED_GLOBAL unsigned long lastEditTime _INIT(0); -WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); // available for use in usermod +WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use in usermod #ifdef WLED_ENABLE_DMX - // dmx CONFIG -WLED_GLOBAL byte DMXChannels _INIT(7); // number of channels per fixture -WLED_GLOBAL byte DMXFixtureMap[15] _INIT_N(({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. -WLED_GLOBAL uint16_t DMXGap _INIT(10); // gap between the fixtures. makes addressing easier because you don't have to memorize odd numbers when climbing up onto a rig. -WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture -WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start + // dmx CONFIG + WLED_GLOBAL byte DMXChannels _INIT(7); // number of channels per fixture + WLED_GLOBAL byte DMXFixtureMap[15] _INIT_N(({ 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. + WLED_GLOBAL uint16_t DMXGap _INIT(10); // gap between the fixtures. makes addressing easier because you don't have to memorize odd numbers when climbing up onto a rig. + WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture + WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start #endif // internal global variable declarations @@ -533,18 +523,18 @@ WLED_GLOBAL bool interfacesInited _INIT(false); WLED_GLOBAL bool wasConnected _INIT(false); // color -WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same +WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same // transitions -WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color -WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending -WLED_GLOBAL bool transitionActive _INIT(false); -WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration -WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) +WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color +WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending +WLED_GLOBAL bool transitionActive _INIT(false); +WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration +WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f -WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") -WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f +WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") +WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); @@ -552,26 +542,26 @@ WLED_GLOBAL bool nightlightActiveOld _INIT(false); WLED_GLOBAL uint32_t nightlightDelayMs _INIT(10); WLED_GLOBAL byte nightlightDelayMinsDefault _INIT(nightlightDelayMins); WLED_GLOBAL unsigned long nightlightStartTime; -WLED_GLOBAL byte briNlT _INIT(0); // current nightlight brightness -WLED_GLOBAL byte colNlT[] _INIT_N(({0, 0, 0, 0})); // current nightlight color +WLED_GLOBAL byte briNlT _INIT(0); // current nightlight brightness +WLED_GLOBAL byte colNlT[] _INIT_N(({ 0, 0, 0, 0 })); // current nightlight color // brightness WLED_GLOBAL unsigned long lastOnTime _INIT(0); -WLED_GLOBAL bool offMode _INIT(!turnOnAtBoot); -WLED_GLOBAL byte bri _INIT(briS); // global brightness (set) -WLED_GLOBAL byte briOld _INIT(0); // global brightness while in transition loop (previous iteration) -WLED_GLOBAL byte briT _INIT(0); // global brightness during transition -WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function -WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function +WLED_GLOBAL bool offMode _INIT(!turnOnAtBoot); +WLED_GLOBAL byte bri _INIT(briS); // global brightness (set) +WLED_GLOBAL byte briOld _INIT(0); // global brightness while in transition loop (previous iteration) +WLED_GLOBAL byte briT _INIT(0); // global brightness during transition +WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function +WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function // button -WLED_GLOBAL bool buttonPublishMqtt _INIT(false); -WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); -WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); +WLED_GLOBAL bool buttonPublishMqtt _INIT(false); +WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); +WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL bool disablePullUp _INIT(false); -WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); +WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL bool disablePullUp _INIT(false); +WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); // notifications WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect); @@ -608,25 +598,25 @@ WLED_GLOBAL bool hueStoreAllowed _INIT(false), hueNewKey _INIT(false); WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L); WLED_GLOBAL bool countdownOverTriggered _INIT(true); -// timer -WLED_GLOBAL byte lastTimerMinute _INIT(0); -WLED_GLOBAL byte timerHours[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); -WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); -WLED_GLOBAL byte timerMacro[] _INIT_N(({0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); -// weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity -WLED_GLOBAL byte timerWeekday[] _INIT_N(({255, 255, 255, 255, 255, 255, 255, 255, 255, 255})); -// upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12) -WLED_GLOBAL byte timerMonth[] _INIT_N(({28, 28, 28, 28, 28, 28, 28, 28})); -WLED_GLOBAL byte timerDay[] _INIT_N(({1, 1, 1, 1, 1, 1, 1, 1})); -WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31, 31, 31, 31, 31, 31, 31, 31})); - -// improv -WLED_GLOBAL byte improvActive _INIT(0); // 0: no improv packet received, 1: improv active, 2: provisioning +//timer +WLED_GLOBAL byte lastTimerMinute _INIT(0); +WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); +WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); +WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); +//weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity +WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); +//upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12) +WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28})); +WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1})); +WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31})); + +//improv +WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning WLED_GLOBAL byte improvError _INIT(0); -// playlists +//playlists WLED_GLOBAL int16_t currentPlaylist _INIT(-1); -// still used for "PL=~" HTTP API command +//still used for "PL=~" HTTP API command WLED_GLOBAL byte presetCycCurr _INIT(0); WLED_GLOBAL byte presetCycMin _INIT(1); WLED_GLOBAL byte presetCycMax _INIT(5); @@ -646,8 +636,8 @@ WLED_GLOBAL byte interfaceUpdateCallMode _INIT(CALL_MODE_INIT); // alexa udp WLED_GLOBAL String escapedMac; #ifndef WLED_DISABLE_ALEXA -WLED_GLOBAL Espalexa espalexa; -WLED_GLOBAL EspalexaDevice *espalexaDevice; + WLED_GLOBAL Espalexa espalexa; + WLED_GLOBAL EspalexaDevice* espalexaDevice; #endif // dns server @@ -669,14 +659,14 @@ WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL Toki toki _INIT(Toki()); // Temp buffer -WLED_GLOBAL char *obuf; +WLED_GLOBAL char* obuf; WLED_GLOBAL uint16_t olen _INIT(0); // General filesystem WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0); WLED_GLOBAL unsigned long presetsModifiedTime _INIT(0L); -WLED_GLOBAL JsonDocument *fileDoc; +WLED_GLOBAL JsonDocument* fileDoc; WLED_GLOBAL bool doCloseFile _INIT(false); // presets @@ -687,14 +677,14 @@ WLED_GLOBAL byte errorFlag _INIT(0); WLED_GLOBAL String messageHead, messageSub; WLED_GLOBAL byte optionType; -WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config -WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers -WLED_GLOBAL bool doPublishMqtt _INIT(false); +WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config +WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers +WLED_GLOBAL bool doPublishMqtt _INIT(false); // status led #if defined(STATUSLED) WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0); -WLED_GLOBAL uint8_t ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second +WLED_GLOBAL uint8_t ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second WLED_GLOBAL bool ledStatusState _INIT(false); // the current LED state #endif @@ -703,26 +693,26 @@ 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 AsyncWebHandler *editHandler _INIT(nullptr); // udp interface objects WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp, notifier2Udp; WLED_GLOBAL WiFiUDP ntpUdp; WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet))); -WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet))); +WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet))); WLED_GLOBAL bool e131NewData _INIT(false); // led fx library object WLED_GLOBAL BusManager busses _INIT(BusManager()); WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); -WLED_GLOBAL BusConfig *busConfigs[WLED_MAX_BUSSES + WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); // temporary, to remember values from network callback until after +WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after WLED_GLOBAL bool doInitBusses _INIT(false); WLED_GLOBAL int8_t loadLedmap _INIT(-1); #ifndef ESP8266 -WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS - 1] _INIT_N(({nullptr})); +WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr})); #endif -#if WLED_MAX_LEDMAPS > 16 +#if WLED_MAX_LEDMAPS>16 WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available ledmaps #else WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps @@ -733,134 +723,125 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN -WLED_GLOBAL int8_t i2c_sda _INIT(-1); +WLED_GLOBAL int8_t i2c_sda _INIT(-1); #else -WLED_GLOBAL int8_t i2c_sda _INIT(I2CSDAPIN); +WLED_GLOBAL int8_t i2c_sda _INIT(I2CSDAPIN); #endif // global I2C SCL pin (used for usermods) #ifndef I2CSCLPIN -WLED_GLOBAL int8_t i2c_scl _INIT(-1); +WLED_GLOBAL int8_t i2c_scl _INIT(-1); #else -WLED_GLOBAL int8_t i2c_scl _INIT(I2CSCLPIN); +WLED_GLOBAL int8_t i2c_scl _INIT(I2CSCLPIN); #endif // global SPI DATA/MOSI pin (used for usermods) #ifndef SPIMOSIPIN -WLED_GLOBAL int8_t spi_mosi _INIT(-1); +WLED_GLOBAL int8_t spi_mosi _INIT(-1); #else -WLED_GLOBAL int8_t spi_mosi _INIT(SPIMOSIPIN); +WLED_GLOBAL int8_t spi_mosi _INIT(SPIMOSIPIN); #endif // global SPI DATA/MISO pin (used for usermods) #ifndef SPIMISOPIN -WLED_GLOBAL int8_t spi_miso _INIT(-1); +WLED_GLOBAL int8_t spi_miso _INIT(-1); #else -WLED_GLOBAL int8_t spi_miso _INIT(SPIMISOPIN); +WLED_GLOBAL int8_t spi_miso _INIT(SPIMISOPIN); #endif // global SPI CLOCK/SCLK pin (used for usermods) #ifndef SPISCLKPIN -WLED_GLOBAL int8_t spi_sclk _INIT(-1); +WLED_GLOBAL int8_t spi_sclk _INIT(-1); #else -WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); +WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); #endif // global ArduinoJson buffer WLED_GLOBAL StaticJsonDocument doc; WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0); -// global buffers for mqtt responses -WLED_GLOBAL StaticJsonDocument mqttResponseDoc; -WLED_GLOBAL char mqttResponseBuffer[JSON_BUFFER_SIZE] _INIT(""); -WLED_GLOBAL volatile uint8_t responseBufferLock _INIT(0); - // enable additional debug output #if defined(WLED_DEBUG_HOST) -#include "net_debug.h" -// On the host side, use netcat to receive the log statements: nc -l 7868 -u -// use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes -#define DEBUGOUT NetDebug -WLED_GLOBAL bool netDebugEnabled _INIT(true); -WLED_GLOBAL char netDebugPrintHost[33] _INIT(WLED_DEBUG_HOST); -#ifndef WLED_DEBUG_PORT -#define WLED_DEBUG_PORT 7868 -#endif -WLED_GLOBAL int netDebugPrintPort _INIT(WLED_DEBUG_PORT); + #include "net_debug.h" + // On the host side, use netcat to receive the log statements: nc -l 7868 -u + // use -D WLED_DEBUG_HOST='"192.168.xxx.xxx"' or FQDN within quotes + #define DEBUGOUT NetDebug + WLED_GLOBAL bool netDebugEnabled _INIT(true); + WLED_GLOBAL char netDebugPrintHost[33] _INIT(WLED_DEBUG_HOST); + #ifndef WLED_DEBUG_PORT + #define WLED_DEBUG_PORT 7868 + #endif + WLED_GLOBAL int netDebugPrintPort _INIT(WLED_DEBUG_PORT); #else -#define DEBUGOUT Serial + #define DEBUGOUT Serial #endif #ifdef WLED_DEBUG -#ifndef ESP8266 -#include -#endif -#define DEBUG_PRINT(x) DEBUGOUT.print(x) -#define DEBUG_PRINTLN(x) DEBUGOUT.println(x) -#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) + #ifndef ESP8266 + #include + #endif + #define DEBUG_PRINT(x) DEBUGOUT.print(x) + #define DEBUG_PRINTLN(x) DEBUGOUT.println(x) + #define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) #else -#define DEBUG_PRINT(x) -#define DEBUG_PRINTLN(x) -#define DEBUG_PRINTF(x...) + #define DEBUG_PRINT(x) + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINTF(x...) #endif #ifdef WLED_DEBUG_FS -#define DEBUGFS_PRINT(x) DEBUGOUT.print(x) -#define DEBUGFS_PRINTLN(x) DEBUGOUT.println(x) -#define DEBUGFS_PRINTF(x...) DEBUGOUT.printf(x) + #define DEBUGFS_PRINT(x) DEBUGOUT.print(x) + #define DEBUGFS_PRINTLN(x) DEBUGOUT.println(x) + #define DEBUGFS_PRINTF(x...) DEBUGOUT.printf(x) #else -#define DEBUGFS_PRINT(x) -#define DEBUGFS_PRINTLN(x) -#define DEBUGFS_PRINTF(x...) + #define DEBUGFS_PRINT(x) + #define DEBUGFS_PRINTLN(x) + #define DEBUGFS_PRINTF(x...) #endif // debug macro variable definitions #ifdef WLED_DEBUG -WLED_GLOBAL unsigned long debugTime _INIT(0); -WLED_GLOBAL int lastWifiState _INIT(3); -WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0); -WLED_GLOBAL unsigned long loops _INIT(0); + WLED_GLOBAL unsigned long debugTime _INIT(0); + WLED_GLOBAL int lastWifiState _INIT(3); + WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0); + WLED_GLOBAL unsigned long loops _INIT(0); #endif #ifdef ARDUINO_ARCH_ESP32 -#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) + #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) #else -#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) + #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) #endif #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #ifndef WLED_AP_SSID_UNIQUE -#define WLED_SET_AP_SSID() \ - do \ - { \ + #define WLED_SET_AP_SSID() do { \ strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ - } while (0) + } while(0) #else -#define WLED_SET_AP_SSID() \ - do \ - { \ - strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ - snprintf_P( \ - apSSID + strlen(WLED_AP_SSID), \ - sizeof(apSSID) - strlen(WLED_AP_SSID), \ - PSTR("-%*s"), \ - 6, \ - escapedMac.c_str() + 6); \ - } while (0) -#endif - -// macro to convert F to const -#define SET_F(x) (const char *)F(x) - -// color mangling macros -#define RGBW32(r, g, b, w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) + #define WLED_SET_AP_SSID() do { \ + strcpy_P(apSSID, PSTR(WLED_AP_SSID)); \ + snprintf_P(\ + apSSID+strlen(WLED_AP_SSID), \ + sizeof(apSSID)-strlen(WLED_AP_SSID), \ + PSTR("-%*s"), \ + 6, \ + escapedMac.c_str() + 6\ + ); \ + } while(0) +#endif + +//macro to convert F to const +#define SET_F(x) (const char*)F(x) + +//color mangling macros +#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #define R(c) (byte((c) >> 16)) #define G(c) (byte((c) >> 8)) #define B(c) (byte(c)) #define W(c) (byte((c) >> 24)) -class WLED -{ +class WLED { public: WLED(); - static WLED &instance() + static WLED& instance() { static WLED instance; return instance; @@ -882,4 +863,4 @@ class WLED void enableWatchdog(); void disableWatchdog(); }; -#endif // WLED_H +#endif // WLED_H From c5c2a9b991bd4261c178796363ad4ea87df41bba Mon Sep 17 00:00:00 2001 From: JacobK5 Date: Sat, 21 Sep 2024 10:24:34 -0600 Subject: [PATCH 3/3] Redid changes without formatter That was really dumb earlier, my bad --- wled00/fcn_declare.h | 2 + wled00/mqtt.cpp | 216 ++++++++++++++++++ .../async-mqtt-client/AsyncMqttClient.cpp | 5 + .../async-mqtt-client/AsyncMqttClient.hpp | 1 + wled00/util.cpp | 33 +++ wled00/wled.cpp | 11 +- wled00/wled.h | 11 +- 7 files changed, 275 insertions(+), 4 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index c65f7a90b4..0833b4ac2e 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -347,6 +347,8 @@ void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); void releaseJSONBufferLock(); +bool requestResponseBufferLock(uint8_t module = 255); +void releaseResponseBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr); int16_t extractModeDefaults(uint8_t mode, const char *segVar); diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a5caaf472e..a50d2dc52c 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -1,4 +1,5 @@ #include "wled.h" +#include /* * MQTT communication protocol for home automation @@ -7,6 +8,9 @@ #ifdef WLED_ENABLE_MQTT #define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds +// declaring this function up here +void otaUpdate(String url); + void parseMQTTBriPayload(char* payload) { if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} @@ -33,6 +37,9 @@ void onMqttConnect(bool sessionPresent) strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/update")); + mqtt->subscribe(subuf, 0); } if (mqttGroupTopic[0] != 0) { @@ -58,6 +65,9 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties DEBUG_PRINT(F("MQTT msg: ")); DEBUG_PRINTLN(topic); + // set connected to true. If we got a message, we must be connected (this fixes a lot of issues with AsyncMqttClient) + mqtt->setConnected(true); // note that setConnected is a function that I added to AsyncMqttClient + // paranoia check to avoid npe if no payload if (payload==nullptr) { DEBUG_PRINTLN(F("no payload -> leave")); @@ -117,6 +127,63 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties handleSet(nullptr, apireq); } releaseJSONBufferLock(); + } else if (strcmp_P(topic, PSTR("/update")) == 0) + { + // get the json buffer lock + if (!requestJSONBufferLock(15)) + { + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // deserialize the request + deserializeJson(doc, payloadStr); + JsonObject obj = doc.as(); + + // make sure the request has a url + if (!obj.containsKey("url") || !obj["url"].is()) + { + DEBUG_PRINTLN("No url in request, won't update. Returning."); + // release the json buffer lock + releaseJSONBufferLock(); + // clear out the payload string + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // get the url + String url = obj["url"].as(); + + // request the response buffer lock + if (!requestResponseBufferLock()) + { + DEBUG_PRINTLN("Failed to get response buffer lock, returning."); + // release the json buffer lock + releaseJSONBufferLock(); + // clear out the payload string + delete[] payloadStr; + payloadStr = nullptr; + return; + } + + // make the response + mqttResponseDoc["id"] = obj["id"]; + mqttResponseDoc["update"] = "Starting update, do not power off the device."; + serializeJson(mqttResponseDoc, mqttResponseBuffer); + + // release the json buffer lock + releaseJSONBufferLock(); + + // send the response + mqtt->publish(mqttResponseTopic, 1, false, mqttResponseBuffer); + + // release the response buffer lock + releaseResponseBufferLock(); + + // do the update + return otaUpdate(url); } else if (strlen(topic) != 0) { // non standard topic, check with usermods usermods.onMqttMessage(topic, payloadStr); @@ -166,6 +233,14 @@ void publishMqtt() bool initMqtt() { + DEBUG_PRINTLN(F("Initializing MQTT")); + // set the important variables + mqttEnabled = true; + strlcpy(mqttServer, "server address here", MQTT_MAX_SERVER_LEN + 1); + mqttPort = 1883; + strlcpy(mqttUser, "username here", 41); + strlcpy(mqttPass, "password here", 65); + if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; if (mqtt == nullptr) { @@ -195,4 +270,145 @@ bool initMqtt() mqtt->connect(); return true; } + +void otaUpdate(String url) +{ + DEBUG_PRINT(F("OTA update from URL: ")); + DEBUG_PRINTLN(url); + + // make client for HTTP request + HTTPClient http; + http.begin(url); + http.setTimeout(3000000); // 5 minute timeout, may change + + // do a get request to get the update binary + int httpCode = http.GET(); + // make sure the request was successful + if (httpCode != HTTP_CODE_OK) + { + DEBUG_PRINT(F("HTTP GET failed, code: ")); + DEBUG_PRINTLN(httpCode); + http.end(); + return; + } + + // disable the watchdog + WLED::instance().disableWatchdog(); + otaInProgress = true; // I've tried both with and without this, neither seems to work + + // get the size of the update + int len = http.getSize(); + DEBUG_PRINT(F("Update size: ")); + DEBUG_PRINTLN(len); + + // make a buffer for reading + WiFiClient *stream = http.getStreamPtr(); + + DEBUG_PRINTLN("Got stream"); + + // Initialize Update + if (!Update.begin(len)) + { + DEBUG_PRINTLN(F("Update.begin failed, most likely not enough space")); + http.end(); + WLED::instance().enableWatchdog(); + otaInProgress = false; + return; + } + + DEBUG_PRINTLN("Update.begin succeeded"); + DEBUG_PRINTLN("Is the stream null?"); + DEBUG_PRINTLN(stream == nullptr); + DEBUG_PRINT(F("Free Heap: ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); + + // write the update to the device + size_t written = 0; + int bufferSize = 512; + uint8_t buffer[bufferSize]; + // size_t written = Update.writeStream(*stream); + while (http.connected() && written < len) + { + if (stream->available()) + { + int bytesRead = stream->readBytes(buffer, bufferSize); + if (bytesRead == 0) + { + DEBUG_PRINTLN("No bytes read"); + } + written += Update.write(buffer, bytesRead); + DEBUG_PRINT("Bytes written: "); + DEBUG_PRINTLN(written); + if (ESP.getFreeHeap() < 80000) + { + DEBUG_PRINT(F("Free Heap below 80000: ")); + DEBUG_PRINTLN(ESP.getFreeHeap()); + } + if (http.connected() != 1) + { + DEBUG_PRINT("http Connection status: "); + DEBUG_PRINTLN(http.connected()); + } + if (WiFi.status() != 3) + { + DEBUG_PRINT("Wifi status: "); + DEBUG_PRINTLN(WiFi.status()); + } + } + else + { + DEBUG_PRINTLN("No bytes available"); + } + delay(10); + } + + DEBUG_PRINTLN("Wrote stream"); + + // check if the update was successful + if (written == len) + { + DEBUG_PRINTLN(F("Written to flash successfully")); + } + else + { + DEBUG_PRINT(F("Update failed, only wrote : ")); + DEBUG_PRINT(written); + DEBUG_PRINTLN(F(" bytes")); + http.end(); + WLED::instance().enableWatchdog(); + otaInProgress = false; + return; + } + + // End the update process + if (Update.end()) + { + if (Update.isFinished()) + { + DEBUG_PRINTLN(F("Update finished successfully, restarting now")); + http.end(); + delay(1000); + ESP.restart(); + } + else + { + DEBUG_PRINTLN(F("Update not finished, something went wrong!")); + } + } + else + { + DEBUG_PRINT(F("OTA Error Occurred. Error: ")); + DEBUG_PRINT(Update.errorString()); + DEBUG_PRINT(" Code: "); + DEBUG_PRINTLN(Update.getError()); + } + + // reenable the watchdog + WLED::instance().enableWatchdog(); + // end the http request + http.end(); + // set ota in progress to false + otaInProgress = false; +} + #endif diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp index d0c44cb6ba..197d33a1cc 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp @@ -875,3 +875,8 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c return 1; } } + +void AsyncMqttClient::setConnected(bool connected) +{ + _connected = connected; +} \ No newline at end of file diff --git a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp index af8332b24e..ca5e84b909 100644 --- a/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp +++ b/wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp @@ -77,6 +77,7 @@ class AsyncMqttClient { uint16_t subscribe(const char* topic, uint8_t qos); uint16_t unsubscribe(const char* topic); uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); + void setConnected(bool connected); private: AsyncClient _client; diff --git a/wled00/util.cpp b/wled00/util.cpp index 914f09ee35..20e1d2dcc1 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -230,6 +230,39 @@ void releaseJSONBufferLock() jsonBufferLock = 0; } +// the same functions but for my new response buffers +bool requestResponseBufferLock(uint8_t module) +{ + unsigned long now = millis(); + + while (responseBufferLock && millis() - now < 1000) + delay(1); // wait for a second for buffer lock + + if (millis() - now >= 1000) + { + DEBUG_PRINT(F("ERROR: Locking response buffer failed! (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + return false; // waiting time-outed + } + + responseBufferLock = module ? module : 255; + DEBUG_PRINT(F("Response buffer locked. (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + mqttResponseDoc.clear(); // Clear the JSON document + memset(mqttResponseBuffer, 0, JSON_BUFFER_SIZE); // Clear the buffer + return true; +} + +void releaseResponseBufferLock() +{ + DEBUG_PRINT(F("Response buffer released. (")); + DEBUG_PRINT(responseBufferLock); + DEBUG_PRINTLN(")"); + responseBufferLock = 0; +} + // extracts effect mode (or palette) name from names serialized string // caller must provide large enough buffer for name (including SR extensions)! diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 8ba6b1a565..917cfe648b 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -34,6 +34,11 @@ void WLED::reset() void WLED::loop() { + if (otaInProgress) + { + // stop the loop while ota in progress + return; + } #ifdef WLED_DEBUG static unsigned long lastRun = 0; unsigned long loopMillis = millis(); @@ -461,8 +466,10 @@ pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), Pin // fill in unique mdns default if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); #ifndef WLED_DISABLE_MQTT - if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6); - if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6); + if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("lights/%*s"), 6, escapedMac.c_str() + 6); + if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("LIGHTS-%*s"), 6, escapedMac.c_str() + 6); + if (mqttResponseTopic[0] == 0) + snprintf_P(mqttResponseTopic, 36, PSTR("%s/r"), mqttDeviceTopic); #endif #ifdef WLED_ENABLE_ADALIGHT diff --git a/wled00/wled.h b/wled00/wled.h index 5d4cca4e93..acad45da34 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -261,6 +261,7 @@ WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); // AP and OTA default passwords (for maximum security change them!) WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); +WLED_GLOBAL bool otaInProgress _INIT(false); // Hardware and pin config #ifndef BTNPIN @@ -432,12 +433,13 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other #define MQTT_MAX_TOPIC_LEN 32 #endif #ifndef MQTT_MAX_SERVER_LEN - #define MQTT_MAX_SERVER_LEN 32 + #define MQTT_MAX_SERVER_LEN 52 #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers -WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) +WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is lights/mac) +WLED_GLOBAL char mqttResponseTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // MQTT response topic (individual per device, default is lights/mac/r) WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth @@ -757,6 +759,11 @@ WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); WLED_GLOBAL StaticJsonDocument doc; WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0); +// global buffers for mqtt responses +WLED_GLOBAL StaticJsonDocument mqttResponseDoc; +WLED_GLOBAL char mqttResponseBuffer[JSON_BUFFER_SIZE] _INIT(""); +WLED_GLOBAL volatile uint8_t responseBufferLock _INIT(0); + // enable additional debug output #if defined(WLED_DEBUG_HOST) #include "net_debug.h"