Error you are not using the aircoookie fork of the espasyncwebserver library

Control WS2812B and many more types of digital RGB LEDs with an ESP8266 or ESP32 over WiFi! - WLED/wled.h at main · Aircoookie/WLED
#ifndef WLED_H #define WLED_H /* Main sketch, global variable declarations @title WLED project sketch @version 0.14.0-b2 @author Christian Schwinne */ // version code in format yymmddb (b = daily build) #define VERSION 2302080 //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. // ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS). // 2-step OTA may still be possible: https://github.com/Aircoookie/WLED/issues/2040#issuecomment-981111096 // Uncomment some of the following lines to disable features: // 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 // You can choose some of these features to disable: //#define WLED_DISABLE_ALEXA // saves 11kb //#define WLED_DISABLE_BLYNK // saves 6kb //#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 #endif #define WLED_ENABLE_ADALIGHT // saves 500b only (uses GPIO3 (RX) for serial) //#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 #endif #ifndef WLED_DISABLE_WEBSOCKETS #define WLED_ENABLE_WEBSOCKETS #endif #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 // filesystem specific debugging //#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 #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 // Library inclusions. #include <Arduino.h> #ifdef ESP8266 #include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <ESPAsyncTCP.h> #include <LittleFS.h> extern «C« { #include <user_interface.h> } #else // ESP32 #include <HardwareSerial.h> // ensure we have the correct «Serial» on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT) #include <WiFi.h> #include <ETH.h> #include «esp_wifi.h« #include <ESPmDNS.h> #include <AsyncTCP.h> #if LOROL_LITTLEFS #ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 #define CONFIG_LITTLEFS_FOR_IDF_3_2 #endif #include <LITTLEFS.h> #else #include <LittleFS.h> #endif #include «esp_task_wdt.h« #endif #include <Wire.h> #include <SPI.h> #include «src/dependencies/network/Network.h« #ifdef WLED_USE_MY_CONFIG #include «my_config.h« #endif #include <ESPAsyncWebServer.h> #ifdef WLED_ADD_EEPROM_SUPPORT #include <EEPROM.h> #endif #include <WiFiUdp.h> #include <DNSServer.h> #ifndef WLED_DISABLE_OTA #define NO_OTA_PORT #include <ArduinoOTA.h> #endif #include <SPIFFSEditor.h> #include «src/dependencies/time/TimeLib.h« #include «src/dependencies/timezone/Timezone.h« #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« #endif #ifndef WLED_DISABLE_BLYNK #include «src/dependencies/blynk/BlynkSimpleEsp.h« #endif #ifdef WLED_ENABLE_DMX #ifdef ESP8266 #include «src/dependencies/dmx/ESPDMX.h« #else //ESP32 #include «src/dependencies/dmx/SparkFunDMX.h« #endif #endif #include «src/dependencies/e131/ESPAsyncE131.h« #ifdef WLED_ENABLE_MQTT #include «src/dependencies/async-mqtt-client/AsyncMqttClient.h« #endif #define ARDUINOJSON_DECODE_UNICODE 0 #include «src/dependencies/json/AsyncJson-v6.h« #include «src/dependencies/json/ArduinoJson-v6.h« // ESP32-WROVER features SPI RAM (aka PSRAM) which can be allocated using ps_malloc() // we can create custom PSRAMDynamicJsonDocument to use such feature (replacing DynamicJsonDocument) // The following is a construct to enable code to compile without it. // There is a code thet will still not use PSRAM though: // AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h) #if defined(ARDUINO_ARCH_ESP32) && 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 } void deallocate(void* pointer) { free(pointer); } }; using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>; #else #define PSRAMDynamicJsonDocument DynamicJsonDocument #endif #include «const.h« #include «fcn_declare.h« #include «NodeStruct.h« #include «pin_manager.h« #include «bus_manager.h« #include «FX.h« #ifndef CLIENT_SSID #define CLIENT_SSID DEFAULT_CLIENT_SSID #endif #ifndef CLIENT_PASS #define CLIENT_PASS «« #endif #if defined(WLED_AP_PASS) && !defined(WLED_AP_SSID) #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 #endif #ifndef WLED_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. 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 <IRremoteESP8266.h> #include <IRrecv.h> #include <IRutils.h> #endif //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 #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); // 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) #else # define WLED_GLOBAL # define _INIT(x) = 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« #endif // Global Variable definitions 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 otaPass[33] _INIT(DEFAULT_OTA_PASS); // Hardware and pin config #ifndef BTNPIN WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({0}); #else WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({BTNPIN}); #endif #ifndef RLYPIN 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) #ifndef RLYMDE WLED_GLOBAL bool rlyMde _INIT(true); #else WLED_GLOBAL bool rlyMde _INIT(RLYMDE); #endif #ifndef IRPIN WLED_GLOBAL int8_t irPin _INIT(-1); #else 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; #else // use defaults for RX/TX constexpr uint8_t hardwareRX = 3; constexpr uint8_t hardwareTX = 1; #endif //WLED_GLOBAL byte presetToApply _INIT(0); 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(«x«); // mDNS address (placeholder, is replaced by wledXXXXXX.local) 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 #else WLED_GLOBAL bool noWifiSleep _INIT(false); #endif #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 #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 //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); 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 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 nightlightDelayMins _INIT(60); WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms 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 #else 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 // 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}); #if defined(IRTYPE) && defined(IRPIN) WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver #else WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled #endif 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 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 #ifndef WLED_DISABLE_BLYNK WLED_GLOBAL char blynkApiKey[36] _INIT(««); // Auth token for Blynk server. If empty, no connection will be made WLED_GLOBAL char blynkHost[33] _INIT(«blynk-cloud.com«); // Default Blynk host WLED_GLOBAL uint16_t blynkPort _INIT(80); // Default Blynk port #endif 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) #endif WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes) WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.) WLED_GLOBAL uint16_t DMXAddress _INIT(1); // DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol] WLED_GLOBAL uint16_t DMXSegmentSpacing _INIT(0); // Number of void/unused channels between each segments DMX channels WLED_GLOBAL byte e131LastSequenceNumber[E131_MAX_UNIVERSE_COUNT]; // to detect packet loss WLED_GLOBAL bool e131Multicast _INIT(false); // multicast or unicast WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze instead of flickering 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 #ifndef WLED_DISABLE_MQTT 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[33] _INIT(««); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttGroupTopic[33] _INIT(«wled/all«); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttServer[33] _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); #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 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); WLED_GLOBAL bool hueApplyColor _INIT(true); #endif WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 100 // 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 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 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 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}); // 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 unsigned long lastEditTime _INIT(0); 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 #endif // internal global variable declarations // wifi WLED_GLOBAL bool apActive _INIT(false); WLED_GLOBAL bool forceReconnect _INIT(false); WLED_GLOBAL uint32_t lastReconnectAttempt _INIT(0); 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 // transitions WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelayDefault _INIT(transitionDelay); // default transition time (storec in cfg.json) WLED_GLOBAL uint16_t transitionDelayTemp _INIT(transitionDelay); // actual transition duration (overrides transitionDelay in certain cases) 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») // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); 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 // 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 brightnes 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 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); // notifications WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect); WLED_GLOBAL bool receiveNotifications _INIT(true); WLED_GLOBAL unsigned long notificationSentTime _INIT(0); WLED_GLOBAL byte notificationSentCallMode _INIT(CALL_MODE_INIT); WLED_GLOBAL uint8_t notificationCount _INIT(0); // effects WLED_GLOBAL byte effectCurrent _INIT(0); WLED_GLOBAL byte effectSpeed _INIT(128); WLED_GLOBAL byte effectIntensity _INIT(128); WLED_GLOBAL byte effectPalette _INIT(0); WLED_GLOBAL bool stateChanged _INIT(false); // network WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false); // ui style WLED_GLOBAL bool showWelcomePage _INIT(false); // hue WLED_GLOBAL byte hueError _INIT(HUE_ERROR_INACTIVE); // WLED_GLOBAL uint16_t hueFailCount _INIT(0); WLED_GLOBAL float hueXLast _INIT(0), hueYLast _INIT(0); WLED_GLOBAL uint16_t hueHueLast _INIT(0), hueCtLast _INIT(0); WLED_GLOBAL byte hueSatLast _INIT(0), hueBriLast _INIT(0); WLED_GLOBAL unsigned long hueLastRequestSent _INIT(0); WLED_GLOBAL bool hueAuthRequired _INIT(false); WLED_GLOBAL bool hueReceived _INIT(false); WLED_GLOBAL bool hueStoreAllowed _INIT(false), hueNewKey _INIT(false); // countdown 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})); // blynk WLED_GLOBAL bool blynkEnabled _INIT(false); //improv WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning WLED_GLOBAL byte improvError _INIT(0); //playlists WLED_GLOBAL int16_t currentPlaylist _INIT(-1); //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); // realtime WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE); WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE); WLED_GLOBAL IPAddress realtimeIP _INIT_N(((0, 0, 0, 0))); WLED_GLOBAL unsigned long realtimeTimeout _INIT(0); WLED_GLOBAL uint8_t tpmPacketCount _INIT(0); WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0); WLED_GLOBAL bool useMainSegmentOnly _INIT(false); WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0); 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; #endif // dns server WLED_GLOBAL DNSServer dnsServer; // network time WLED_GLOBAL bool ntpConnected _INIT(false); WLED_GLOBAL time_t localTime _INIT(0); WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L); WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L); WLED_GLOBAL IPAddress ntpServerIP; WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390); WLED_GLOBAL uint16_t rolloverMillis _INIT(0); WLED_GLOBAL float longitude _INIT(0.0); WLED_GLOBAL float latitude _INIT(0.0); WLED_GLOBAL time_t sunrise _INIT(0); WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL Toki toki _INIT(Toki()); // Temp buffer 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 bool doCloseFile _INIT(false); // presets WLED_GLOBAL byte currentPreset _INIT(0); 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); // 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 bool ledStatusState _INIT(false); // the current LED state #endif // server library objects 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 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 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 bool doInitBusses _INIT(false); WLED_GLOBAL int8_t loadLedmap _INIT(-1); WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps // Usermod manager WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN WLED_GLOBAL int8_t i2c_sda _INIT(-1); #else 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); #else 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); #else 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); #else 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); #else WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); #endif // global ArduinoJson buffer WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> doc; WLED_GLOBAL volatile uint8_t jsonBufferLock _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); #else #define DEBUGOUT Serial #endif #ifdef WLED_DEBUG #ifndef ESP8266 #include <rom/rtc.h> #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…) #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) #else #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); #endif #ifdef ARDUINO_ARCH_ESP32 #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) #else #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 { strcpy_P(apSSID, PSTR(WLED_AP_SSID)); } 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 R(c) (byte((c) >> 16)) #define G(c) (byte((c) >> 8)) #define B(c) (byte(c)) #define W(c) (byte((c) >> 24)) class WLED { public: WLED(); static WLED& instance() { static WLED instance; return instance; } // boot starts here void setup(); void loop(); void reset(); void beginStrip(); void handleConnection(); bool initEthernet(); // result is informational void initAP(bool resetAP = false); void initConnection(); void initInterfaces(); void handleStatusLED(); void enableWatchdog(); void disableWatchdog(); }; #endif // WLED_H

ESPAsyncWebServer (Aircoookie Fork for WLED)

Build Status Codacy Badge

For help and support Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer

Async HTTP and WebSocket Server for ESP8266 Arduino

For ESP8266 it requires ESPAsyncTCP
To use this library you might need to have the latest git versions of ESP8266 Arduino Core

For ESP32 it requires AsyncTCP to work
To use this library you might need to have the latest git versions of ESP32 Arduino Core

Table of contents

  • ESPAsyncWebServer
    • Table of contents
    • Installation
      • Using PlatformIO
    • Why should you care
    • Important things to remember
    • Principles of operation
      • The Async Web server
      • Request Life Cycle
      • Rewrites and how do they work
      • Handlers and how do they work
      • Responses and how do they work
      • Template processing
    • Libraries and projects that use AsyncWebServer
    • Request Variables
      • Common Variables
      • Headers
      • GET, POST and FILE parameters
      • FILE Upload handling
      • Body data handling
      • JSON body handling with ArduinoJson
    • Responses
      • Redirect to another URL
      • Basic response with HTTP Code
      • Basic response with HTTP Code and extra headers
      • Basic response with string content
      • Basic response with string content and extra headers
      • Send large webpage from PROGMEM
      • Send large webpage from PROGMEM and extra headers
      • Send large webpage from PROGMEM containing templates
      • Send large webpage from PROGMEM containing templates and extra headers
      • Send binary content from PROGMEM
      • Respond with content coming from a Stream
      • Respond with content coming from a Stream and extra headers
      • Respond with content coming from a Stream containing templates
      • Respond with content coming from a Stream containing templates and extra headers
      • Respond with content coming from a File
      • Respond with content coming from a File and extra headers
      • Respond with content coming from a File containing templates
      • Respond with content using a callback
      • Respond with content using a callback and extra headers
      • Respond with content using a callback containing templates
      • Respond with content using a callback containing templates and extra headers
      • Chunked Response
      • Chunked Response containing templates
      • Print to response
      • ArduinoJson Basic Response
      • ArduinoJson Advanced Response
    • Serving static files
      • Serving specific file by name
      • Serving files in directory
      • Serving static files with authentication
      • Specifying Cache-Control header
      • Specifying Date-Modified header
      • Specifying Template Processor callback
    • Param Rewrite With Matching
    • Using filters
      • Serve different site files in AP mode
      • Rewrite to different index on AP
      • Serving different hosts
      • Determine interface inside callbacks
    • Bad Responses
      • Respond with content using a callback without content length to HTTP/1.0 clients
    • Async WebSocket Plugin
      • Async WebSocket Event
      • Methods for sending data to a socket client
      • Direct access to web socket message buffer
      • Limiting the number of web socket clients
    • Async Event Source Plugin
      • Setup Event Source on the server
      • Setup Event Source in the browser
    • Scanning for available WiFi Networks
    • Remove handlers and rewrites
    • Setting up the server
      • Setup global and class functions as request handlers
      • Methods for controlling websocket connections
      • Adding Default Headers

Installation

Using PlatformIO

PlatformIO is an open source ecosystem for IoT development with cross platform build system, library manager and full support for Espressif ESP8266/ESP32 development. It works on the popular host OS: Mac OS X, Windows, Linux 32/64, Linux ARM (like Raspberry Pi, BeagleBone, CubieBoard).

  1. Install PlatformIO IDE
  2. Create new project using «PlatformIO Home > New Project»
  3. Update dev/platform to staging version:
    • Instruction for Espressif 8266
    • Instruction for Espressif 32
  4. Add «ESP Async WebServer» to project using Project Configuration File platformio.ini and lib_deps option:
[env:myboard]
platform = espressif...
board = ...
framework = arduino

# using the latest stable version
lib_deps = ESP Async WebServer

# or using GIT Url (the latest development version)
lib_deps = https://github.com/me-no-dev/ESPAsyncWebServer.git
  1. Happy coding with PlatformIO!

Why should you care

  • Using asynchronous network means that you can handle more than one connection at the same time
  • You are called once the request is ready and parsed
  • When you send the response, you are immediately ready to handle other connections
    while the server is taking care of sending the response in the background
  • Speed is OMG
  • Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse
  • Easily extendible to handle any type of content
  • Supports Continue 100
  • Async WebSocket plugin offering different locations without extra servers or ports
  • Async EventSource (Server-Sent Events) plugin to send events to the browser
  • URL Rewrite plugin for conditional and permanent url rewrites
  • ServeStatic plugin that supports cache, Last-Modified, default index and more
  • Simple template processing engine to handle templates

Important things to remember

  • This is fully asynchronous server and as such does not run on the loop thread.
  • You can not use yield or delay or any function that uses them inside the callbacks
  • The server is smart enough to know when to close the connection and free resources
  • You can not send more than one response to a single request

Principles of operation

The Async Web server

  • Listens for connections
  • Wraps the new clients into Request
  • Keeps track of clients and cleans memory
  • Manages Rewrites and apply them on the request url
  • Manages Handlers and attaches them to Requests

Request Life Cycle

  • TCP connection is received by the server
  • The connection is wrapped inside Request object
  • When the request head is received (type, url, get params, http version and host),
    the server goes through all Rewrites (in the order they were added) to rewrite the url and inject query parameters,
    next, it goes through all attached Handlers(in the order they were added) trying to find one
    that canHandle the given request. If none are found, the default(catch-all) handler is attached.
  • The rest of the request is received, calling the handleUpload or handleBody methods of the Handler if they are needed (POST+File/Body)
  • When the whole request is parsed, the result is given to the handleRequest method of the Handler and is ready to be responded to
  • In the handleRequest method, to the Request is attached a Response object (see below) that will serve the response data back to the client
  • When the Response is sent, the client is closed and freed from the memory

Rewrites and how do they work

  • The Rewrites are used to rewrite the request url and/or inject get parameters for a specific request url path.
  • All Rewrites are evaluated on the request in the order they have been added to the server.
  • The Rewrite will change the request url only if the request url (excluding get parameters) is fully match
    the rewrite url, and when the optional Filter callback return true.
  • Setting a Filter to the Rewrite enables to control when to apply the rewrite, decision can be based on
    request url, http version, request host/port/target host, get parameters or the request client’s localIP or remoteIP.
  • Two filter callbacks are provided: ON_AP_FILTER to execute the rewrite when request is made to the AP interface,
    ON_STA_FILTER to execute the rewrite when request is made to the STA interface.
  • The Rewrite can specify a target url with optional get parameters, e.g. /to-url?with=params

Handlers and how do they work

  • The Handlers are used for executing specific actions to particular requests
  • One Handler instance can be attached to any request and lives together with the server
  • Setting a Filter to the Handler enables to control when to apply the handler, decision can be based on
    request url, http version, request host/port/target host, get parameters or the request client’s localIP or remoteIP.
  • Two filter callbacks are provided: ON_AP_FILTER to execute the rewrite when request is made to the AP interface,
    ON_STA_FILTER to execute the rewrite when request is made to the STA interface.
  • The canHandle method is used for handler specific control on whether the requests can be handled
    and for declaring any interesting headers that the Request should parse. Decision can be based on request
    method, request url, http version, request host/port/target host and get parameters
  • Once a Handler is attached to given Request (canHandle returned true)
    that Handler takes care to receive any file/data upload and attach a Response
    once the Request has been fully parsed
  • Handlers are evaluated in the order they are attached to the server. The canHandle is called only
    if the Filter that was set to the Handler return true.
  • The first Handler that can handle the request is selected, not further Filter and canHandle are called.

Responses and how do they work

  • The Response objects are used to send the response data back to the client
  • The Response object lives with the Request and is freed on end or disconnect
  • Different techniques are used depending on the response type to send the data in packets
    returning back almost immediately and sending the next packet when this one is received.
    Any time in between is spent to run the user loop and handle other network packets
  • Responding asynchronously is probably the most difficult thing for most to understand
  • Many different options exist for the user to make responding a background task

Template processing

  • ESPAsyncWebserver contains simple template processing engine.
  • Template processing can be added to most response types.
  • Currently it supports only replacing template placeholders with actual values. No conditional processing, cycles, etc.
  • Placeholders are delimited with % symbols. Like this: %TEMPLATE_PLACEHOLDER%.
  • It works by extracting placeholder name from response text and passing it to user provided function which should return actual value to be used instead of placeholder.
  • Since it’s user provided function, it is possible for library users to implement conditional processing and cycles themselves.
  • Since it’s impossible to know the actual response size after template processing step in advance (and, therefore, to include it in response headers), the response becomes chunked.

Libraries and projects that use AsyncWebServer

  • WebSocketToSerial — Debug serial devices through the web browser
  • Sattrack — Track the ISS with ESP8266
  • ESP Radio — Icecast radio based on ESP8266 and VS1053
  • VZero — the Wireless zero-config controller for volkszaehler.org
  • ESPurna — ESPurna («spark» in Catalan) is a custom C firmware for ESP8266 based smart switches. It was originally developed with the ITead Sonoff in mind.
  • fauxmoESP — Belkin WeMo emulator library for ESP8266.
  • ESP-RFID — MFRC522 RFID Access Control Management project for ESP8266.

Request Variables

Common Variables

request->version();       // uint8_t: 0 = HTTP/1.0, 1 = HTTP/1.1
request->method();        // enum:    HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS
request->url();           // String:  URL of the request (not including host, port or GET parameters)
request->host();          // String:  The requested host (can be used for virtual hosting)
request->contentType();   // String:  ContentType of the request (not avaiable in Handler::canHandle)
request->contentLength(); // size_t:  ContentLength of the request (not avaiable in Handler::canHandle)
request->multipart();     // bool:    True if the request has content type "multipart"

Headers

//List all collected headers
int headers = request->headers();
int i;
for(i=0;i<headers;i++){
  AsyncWebHeader* h = request->getHeader(i);
  Serial.printf("HEADER[%s]: %sn", h->name().c_str(), h->value().c_str());
}

//get specific header by name
if(request->hasHeader("MyHeader")){
  AsyncWebHeader* h = request->getHeader("MyHeader");
  Serial.printf("MyHeader: %sn", h->value().c_str());
}

//List all collected headers (Compatibility)
int headers = request->headers();
int i;
for(i=0;i<headers;i++){
  Serial.printf("HEADER[%s]: %sn", request->headerName(i).c_str(), request->header(i).c_str());
}

//get specific header by name (Compatibility)
if(request->hasHeader("MyHeader")){
  Serial.printf("MyHeader: %sn", request->header("MyHeader").c_str());
}

GET, POST and FILE parameters

//List all parameters
int params = request->params();
for(int i=0;i<params;i++){
  AsyncWebParameter* p = request->getParam(i);
  if(p->isFile()){ //p->isPost() is also true
    Serial.printf("FILE[%s]: %s, size: %un", p->name().c_str(), p->value().c_str(), p->size());
  } else if(p->isPost()){
    Serial.printf("POST[%s]: %sn", p->name().c_str(), p->value().c_str());
  } else {
    Serial.printf("GET[%s]: %sn", p->name().c_str(), p->value().c_str());
  }
}

//Check if GET parameter exists
if(request->hasParam("download"))
  AsyncWebParameter* p = request->getParam("download");

//Check if POST (but not File) parameter exists
if(request->hasParam("download", true))
  AsyncWebParameter* p = request->getParam("download", true);

//Check if FILE was uploaded
if(request->hasParam("download", true, true))
  AsyncWebParameter* p = request->getParam("download", true, true);

//List all parameters (Compatibility)
int args = request->args();
for(int i=0;i<args;i++){
  Serial.printf("ARG[%s]: %sn", request->argName(i).c_str(), request->arg(i).c_str());
}

//Check if parameter exists (Compatibility)
if(request->hasArg("download"))
  String arg = request->arg("download");

FILE Upload handling

void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
  if(!index){
    Serial.printf("UploadStart: %sn", filename.c_str());
  }
  for(size_t i=0; i<len; i++){
    Serial.write(data[i]);
  }
  if(final){
    Serial.printf("UploadEnd: %s, %u Bn", filename.c_str(), index+len);
  }
}

Body data handling

void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
  if(!index){
    Serial.printf("BodyStart: %u Bn", total);
  }
  for(size_t i=0; i<len; i++){
    Serial.write(data[i]);
  }
  if(index + len == total){
    Serial.printf("BodyEnd: %u Bn", total);
  }
}

If needed, the _tempObject field on the request can be used to store a pointer to temporary data (e.g. from the body) associated with the request. If assigned, the pointer will automatically be freed along with the request.

JSON body handling with ArduinoJson

Endpoints which consume JSON can use a special handler to get ready to use JSON data in the request callback:

#include "AsyncJson.h"
#include "ArduinoJson.h"

AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint", [](AsyncWebServerRequest *request, JsonVariant &json) {
  JsonObject& jsonObj = json.as<JsonObject>();
  // ...
});
server.addHandler(handler);

Responses

Redirect to another URL

//to local url
request->redirect("/login");

//to external url
request->redirect("http://esp8266.com");

Basic response with HTTP Code

request->send(404); //Sends 404 File Not Found

Basic response with HTTP Code and extra headers

AsyncWebServerResponse *response = request->beginResponse(404); //Sends 404 File Not Found
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Basic response with string content

request->send(200, "text/plain", "Hello World!");

Basic response with string content and extra headers

AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello World!");
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Send large webpage from PROGMEM

const char index_html[] PROGMEM = "..."; // large char array, tested with 14k
request->send_P(200, "text/html", index_html);

Send large webpage from PROGMEM and extra headers

const char index_html[] PROGMEM = "..."; // large char array, tested with 14k
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Send large webpage from PROGMEM containing templates

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

const char index_html[] PROGMEM = "..."; // large char array, tested with 14k
request->send_P(200, "text/html", index_html, processor);

Send large webpage from PROGMEM containing templates and extra headers

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

const char index_html[] PROGMEM = "..."; // large char array, tested with 14k
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html, processor);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Send binary content from PROGMEM

//File: favicon.ico.gz, Size: 726
#define favicon_ico_gz_len 726
const uint8_t favicon_ico_gz[] PROGMEM = {
 0x1F, 0x8B, 0x08, 0x08, 0x0B, 0x87, 0x90, 0x57, 0x00, 0x03, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6F,
 0x6E, 0x2E, 0x69, 0x63, 0x6F, 0x00, 0xCD, 0x53, 0x5F, 0x48, 0x9A, 0x51, 0x14, 0xBF, 0x62, 0x6D,
 0x86, 0x96, 0xA9, 0x64, 0xD3, 0xFE, 0xA8, 0x99, 0x65, 0x1A, 0xB4, 0x8A, 0xA8, 0x51, 0x54, 0x23,
 0xA8, 0x11, 0x49, 0x51, 0x8A, 0x34, 0x62, 0x93, 0x85, 0x31, 0x58, 0x44, 0x12, 0x45, 0x2D, 0x58,
 0xF5, 0x52, 0x41, 0x10, 0x23, 0x82, 0xA0, 0x20, 0x98, 0x2F, 0xC1, 0x26, 0xED, 0xA1, 0x20, 0x89,
 0x04, 0xD7, 0x83, 0x58, 0x20, 0x28, 0x04, 0xAB, 0xD1, 0x9B, 0x8C, 0xE5, 0xC3, 0x60, 0x32, 0x64,
 0x0E, 0x56, 0xBF, 0x9D, 0xEF, 0xF6, 0x30, 0x82, 0xED, 0xAD, 0x87, 0xDD, 0x8F, 0xF3, 0xDD, 0x8F,
 0x73, 0xCF, 0xEF, 0x9C, 0xDF, 0x39, 0xBF, 0xFB, 0x31, 0x26, 0xA2, 0x27, 0x37, 0x97, 0xD1, 0x5B,
 0xCF, 0x9E, 0x67, 0x30, 0xA6, 0x66, 0x8C, 0x99, 0xC9, 0xC8, 0x45, 0x9E, 0x6B, 0x3F, 0x5F, 0x74,
 0xA6, 0x94, 0x5E, 0xDB, 0xFF, 0xB2, 0xE6, 0xE7, 0xE7, 0xF9, 0xDE, 0xD6, 0xD6, 0x96, 0xDB, 0xD8,
 0xD8, 0x78, 0xBF, 0xA1, 0xA1, 0xC1, 0xDA, 0xDC, 0xDC, 0x2C, 0xEB, 0xED, 0xED, 0x15, 0x9B, 0xCD,
 0xE6, 0x4A, 0x83, 0xC1, 0xE0, 0x2E, 0x29, 0x29, 0x99, 0xD6, 0x6A, 0xB5, 0x4F, 0x75, 0x3A, 0x9D,
 0x61, 0x75, 0x75, 0x95, 0xB5, 0xB7, 0xB7, 0xDF, 0xC8, 0xD1, 0xD4, 0xD4, 0xF4, 0xB0, 0xBA, 0xBA,
 0xFA, 0x83, 0xD5, 0x6A, 0xFD, 0x5A, 0x5E, 0x5E, 0x9E, 0x28, 0x2D, 0x2D, 0x0D, 0x10, 0xC6, 0x4B,
 0x98, 0x78, 0x5E, 0x5E, 0xDE, 0x95, 0x42, 0xA1, 0x40, 0x4E, 0x4E, 0xCE, 0x65, 0x76, 0x76, 0xF6,
 0x47, 0xB5, 0x5A, 0x6D, 0x4F, 0x26, 0x93, 0xA2, 0xD6, 0xD6, 0x56, 0x8E, 0x6D, 0x69, 0x69, 0xD1,
 0x11, 0x36, 0x62, 0xB1, 0x58, 0x60, 0x32, 0x99, 0xA0, 0xD7, 0xEB, 0x51, 0x58, 0x58, 0x88, 0xFC,
 0xFC, 0x7C, 0x10, 0x16, 0x02, 0x56, 0x2E, 0x97, 0x43, 0x2A, 0x95, 0x42, 0x2C, 0x16, 0x23, 0x33,
 0x33, 0x33, 0xAE, 0x52, 0xA9, 0x1E, 0x64, 0x65, 0x65, 0x71, 0x7C, 0x7D, 0x7D, 0xBD, 0x93, 0xEA,
 0xFE, 0x30, 0x1A, 0x8D, 0xE8, 0xEC, 0xEC, 0xC4, 0xE2, 0xE2, 0x22, 0x6A, 0x6A, 0x6A, 0x40, 0x39,
 0x41, 0xB5, 0x38, 0x4E, 0xC8, 0x33, 0x3C, 0x3C, 0x0C, 0x87, 0xC3, 0xC1, 0x6B, 0x54, 0x54, 0x54,
 0xBC, 0xE9, 0xEB, 0xEB, 0x93, 0x5F, 0x5C, 0x5C, 0x30, 0x8A, 0x9D, 0x2E, 0x2B, 0x2B, 0xBB, 0xA2,
 0x3E, 0x41, 0xBD, 0x21, 0x1E, 0x8F, 0x63, 0x6A, 0x6A, 0x0A, 0x81, 0x40, 0x00, 0x94, 0x1B, 0x3D,
 0x3D, 0x3D, 0x42, 0x3C, 0x96, 0x96, 0x96, 0x70, 0x7E, 0x7E, 0x8E, 0xE3, 0xE3, 0x63, 0xF8, 0xFD,
 0xFE, 0xB4, 0xD7, 0xEB, 0xF5, 0x8F, 0x8F, 0x8F, 0x5B, 0x68, 0x5E, 0x6F, 0x05, 0xCE, 0xB4, 0xE3,
 0xE8, 0xE8, 0x08, 0x27, 0x27, 0x27, 0xD8, 0xDF, 0xDF, 0xC7, 0xD9, 0xD9, 0x19, 0x6C, 0x36, 0x1B,
 0x36, 0x36, 0x36, 0x38, 0x9F, 0x85, 0x85, 0x05, 0xAC, 0xAF, 0xAF, 0x23, 0x1A, 0x8D, 0x22, 0x91,
 0x48, 0x20, 0x16, 0x8B, 0xFD, 0xDA, 0xDA, 0xDA, 0x7A, 0x41, 0x33, 0x7E, 0x57, 0x50, 0x50, 0x80,
 0x89, 0x89, 0x09, 0x84, 0xC3, 0x61, 0x6C, 0x6F, 0x6F, 0x23, 0x12, 0x89, 0xE0, 0xE0, 0xE0, 0x00,
 0x43, 0x43, 0x43, 0x58, 0x5E, 0x5E, 0xE6, 0x9C, 0x7D, 0x3E, 0x1F, 0x46, 0x47, 0x47, 0x79, 0xBE,
 0xBD, 0xBD, 0x3D, 0xE1, 0x3C, 0x1D, 0x0C, 0x06, 0x9F, 0x10, 0xB7, 0xC7, 0x84, 0x4F, 0xF6, 0xF7,
 0xF7, 0x63, 0x60, 0x60, 0x00, 0x83, 0x83, 0x83, 0x18, 0x19, 0x19, 0xC1, 0xDC, 0xDC, 0x1C, 0x8F,
 0x17, 0x7C, 0xA4, 0x27, 0xE7, 0x34, 0x39, 0x39, 0x89, 0x9D, 0x9D, 0x1D, 0x6E, 0x54, 0xE3, 0x13,
 0xE5, 0x34, 0x11, 0x37, 0x49, 0x51, 0x51, 0xD1, 0x4B, 0xA5, 0x52, 0xF9, 0x45, 0x26, 0x93, 0x5D,
 0x0A, 0xF3, 0x92, 0x48, 0x24, 0xA0, 0x6F, 0x14, 0x17, 0x17, 0xA3, 0xB6, 0xB6, 0x16, 0x5D, 0x5D,
 0x5D, 0x7C, 0x1E, 0xBB, 0xBB, 0xBB, 0x9C, 0xD7, 0xE1, 0xE1, 0x21, 0x42, 0xA1, 0xD0, 0x6B, 0xD2,
 0x45, 0x4C, 0x33, 0x12, 0x34, 0xCC, 0xA0, 0x19, 0x54, 0x92, 0x56, 0x0E, 0xD2, 0xD9, 0x43, 0xF8,
 0xCF, 0x82, 0x56, 0xC2, 0xDC, 0xEB, 0xEA, 0xEA, 0x38, 0x7E, 0x6C, 0x6C, 0x4C, 0xE0, 0xFE, 0x9D,
 0xB8, 0xBF, 0xA7, 0xFA, 0xAF, 0x56, 0x56, 0x56, 0xEE, 0x6D, 0x6E, 0x6E, 0xDE, 0xB8, 0x47, 0x55,
 0x55, 0x55, 0x6C, 0x66, 0x66, 0x46, 0x44, 0xDA, 0x3B, 0x34, 0x1A, 0x4D, 0x94, 0xB0, 0x3F, 0x09,
 0x7B, 0x45, 0xBD, 0xA5, 0x5D, 0x2E, 0x57, 0x8C, 0x7A, 0x73, 0xD9, 0xED, 0xF6, 0x3B, 0x84, 0xFF,
 0xE7, 0x7D, 0xA6, 0x3A, 0x2C, 0x95, 0x4A, 0xB1, 0x8E, 0x8E, 0x0E, 0x6D, 0x77, 0x77, 0xB7, 0xCD,
 0xE9, 0x74, 0x3E, 0x73, 0xBB, 0xDD, 0x8F, 0x3C, 0x1E, 0x8F, 0xE6, 0xF4, 0xF4, 0x94, 0xAD, 0xAD,
 0xAD, 0xDD, 0xDE, 0xCF, 0x73, 0x0B, 0x0B, 0xB8, 0xB6, 0xE0, 0x5D, 0xC6, 0x66, 0xC5, 0xE4, 0x10,
 0x4C, 0xF4, 0xF7, 0xD8, 0x59, 0xF2, 0x7F, 0xA3, 0xB8, 0xB4, 0xFC, 0x0F, 0xEE, 0x37, 0x70, 0xEC,
 0x16, 0x4A, 0x7E, 0x04, 0x00, 0x00
};

AsyncWebServerResponse *response = request->beginResponse_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);

Respond with content coming from a Stream

//read 12 bytes from Serial and send them as Content Type text/plain
request->send(Serial, "text/plain", 12);

Respond with content coming from a Stream and extra headers

//read 12 bytes from Serial and send them as Content Type text/plain
AsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Respond with content coming from a Stream containing templates

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

//read 12 bytes from Serial and send them as Content Type text/plain
request->send(Serial, "text/plain", 12, processor);

Respond with content coming from a Stream containing templates and extra headers

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

//read 12 bytes from Serial and send them as Content Type text/plain
AsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12, processor);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Respond with content coming from a File

//Send index.htm with default content type
request->send(SPIFFS, "/index.htm");

//Send index.htm as text
request->send(SPIFFS, "/index.htm", "text/plain");

//Download index.htm
request->send(SPIFFS, "/index.htm", String(), true);

Respond with content coming from a File and extra headers

//Send index.htm with default content type
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm");

//Send index.htm as text
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", "text/plain");

//Download index.htm
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", String(), true);

response->addHeader("Server","ESP Async Web Server");
request->send(response);

Respond with content coming from a File containing templates

Internally uses Chunked Response.

Index.htm contents:

Somewhere in source files:

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

//Send index.htm with template processor function
request->send(SPIFFS, "/index.htm", String(), false, processor);

Respond with content using a callback

//send 128 bytes as plain text
request->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will not be asked for more bytes once the content length has been reached.
  //Keep in mind that you can not delay or yield waiting for more data!
  //Send what you currently have and you will be asked for more again
  return mySource.read(buffer, maxLen);
});

Respond with content using a callback and extra headers

//send 128 bytes as plain text
AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will not be asked for more bytes once the content length has been reached.
  //Keep in mind that you can not delay or yield waiting for more data!
  //Send what you currently have and you will be asked for more again
  return mySource.read(buffer, maxLen);
});
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Respond with content using a callback containing templates

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

//send 128 bytes as plain text
request->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will not be asked for more bytes once the content length has been reached.
  //Keep in mind that you can not delay or yield waiting for more data!
  //Send what you currently have and you will be asked for more again
  return mySource.read(buffer, maxLen);
}, processor);

Respond with content using a callback containing templates and extra headers

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

//send 128 bytes as plain text
AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will not be asked for more bytes once the content length has been reached.
  //Keep in mind that you can not delay or yield waiting for more data!
  //Send what you currently have and you will be asked for more again
  return mySource.read(buffer, maxLen);
}, processor);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Chunked Response

Used when content length is unknown. Works best if the client supports HTTP/1.1

AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will be asked for more data until 0 is returned
  //Keep in mind that you can not delay or yield waiting for more data!
  return mySource.read(buffer, maxLen);
});
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Chunked Response containing templates

Used when content length is unknown. Works best if the client supports HTTP/1.1

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //index equals the amount of bytes that have been already sent
  //You will be asked for more data until 0 is returned
  //Keep in mind that you can not delay or yield waiting for more data!
  return mySource.read(buffer, maxLen);
}, processor);
response->addHeader("Server","ESP Async Web Server");
request->send(response);

Print to response

AsyncResponseStream *response = request->beginResponseStream("text/html");
response->addHeader("Server","ESP Async Web Server");
response->printf("<!DOCTYPE html><html><head><title>Webpage at %s</title></head><body>", request->url().c_str());

response->print("<h2>Hello ");
response->print(request->client()->remoteIP());
response->print("</h2>");

response->print("<h3>General</h3>");
response->print("<ul>");
response->printf("<li>Version: HTTP/1.%u</li>", request->version());
response->printf("<li>Method: %s</li>", request->methodToString());
response->printf("<li>URL: %s</li>", request->url().c_str());
response->printf("<li>Host: %s</li>", request->host().c_str());
response->printf("<li>ContentType: %s</li>", request->contentType().c_str());
response->printf("<li>ContentLength: %u</li>", request->contentLength());
response->printf("<li>Multipart: %s</li>", request->multipart()?"true":"false");
response->print("</ul>");

response->print("<h3>Headers</h3>");
response->print("<ul>");
int headers = request->headers();
for(int i=0;i<headers;i++){
  AsyncWebHeader* h = request->getHeader(i);
  response->printf("<li>%s: %s</li>", h->name().c_str(), h->value().c_str());
}
response->print("</ul>");

response->print("<h3>Parameters</h3>");
response->print("<ul>");
int params = request->params();
for(int i=0;i<params;i++){
  AsyncWebParameter* p = request->getParam(i);
  if(p->isFile()){
    response->printf("<li>FILE[%s]: %s, size: %u</li>", p->name().c_str(), p->value().c_str(), p->size());
  } else if(p->isPost()){
    response->printf("<li>POST[%s]: %s</li>", p->name().c_str(), p->value().c_str());
  } else {
    response->printf("<li>GET[%s]: %s</li>", p->name().c_str(), p->value().c_str());
  }
}
response->print("</ul>");

response->print("</body></html>");
//send the response last
request->send(response);

ArduinoJson Basic Response

This way of sending Json is great for when the result is below 4KB

#include "AsyncJson.h"
#include "ArduinoJson.h"


AsyncResponseStream *response = request->beginResponseStream("application/json");
DynamicJsonBuffer jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
root["heap"] = ESP.getFreeHeap();
root["ssid"] = WiFi.SSID();
root.printTo(*response);
request->send(response);

ArduinoJson Advanced Response

This response can handle really large Json objects (tested to 40KB)
There isn’t any noticeable speed decrease for small results with the method above
Since ArduinoJson does not allow reading parts of the string, the whole Json has to
be passed every time a chunks needs to be sent, which shows speed decrease proportional
to the resulting json packets

#include "AsyncJson.h"
#include "ArduinoJson.h"


AsyncJsonResponse * response = new AsyncJsonResponse();
response->addHeader("Server","ESP Async Web Server");
JsonObject& root = response->getRoot();
root["heap"] = ESP.getFreeHeap();
root["ssid"] = WiFi.SSID();
response->setLength();
request->send(response);

Serving static files

In addition to serving files from SPIFFS as described above, the server provide a dedicated handler that optimize the
performance of serving files from SPIFFS — AsyncStaticWebHandler. Use server.serveStatic() function to
initialize and add a new instance of AsyncStaticWebHandler to the server.
The Handler will not handle the request if the file does not exists, e.g. the server will continue to look for another
handler that can handle the request.
Notice that you can chain setter functions to setup the handler, or keep a pointer to change it at a later time.

Serving specific file by name

// Serve the file "/www/page.htm" when request url is "/page.htm"
server.serveStatic("/page.htm", SPIFFS, "/www/page.htm");

Serving files in directory

To serve files in a directory, the path to the files should specify a directory in SPIFFS and ends with «/».

// Serve files in directory "/www/" when request url starts with "/"
// Request to the root or none existing files will try to server the defualt
// file name "index.htm" if exists
server.serveStatic("/", SPIFFS, "/www/");

// Server with different default file
server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("default.html");

Serving static files with authentication

server
    .serveStatic("/", SPIFFS, "/www/")
    .setDefaultFile("default.html")
    .setAuthentication("user", "pass");

Specifying Cache-Control header

It is possible to specify Cache-Control header value to reduce the number of calls to the server once the client loaded
the files. For more information on Cache-Control values see Cache-Control

// Cache responses for 10 minutes (600 seconds)
server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600");

//*** Change Cache-Control after server setup ***

// During setup - keep a pointer to the handler
AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600");

// At a later event - change Cache-Control
handler->setCacheControl("max-age=30");

Specifying Date-Modified header

It is possible to specify Date-Modified header to enable the server to return Not-Modified (304) response for requests
with «If-Modified-Since» header with the same value, instead of responding with the actual file content.

// Update the date modified string every time files are updated
server.serveStatic("/", SPIFFS, "/www/").setLastModified("Mon, 20 Jun 2016 14:00:00 GMT");

//*** Chage last modified value at a later stage ***

// During setup - read last modified value from config or EEPROM
String date_modified = loadDateModified();
AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/");
handler->setLastModified(date_modified);

// At a later event when files are updated
String date_modified = getNewDateModfied();
saveDateModified(date_modified); // Save for next reset
handler->setLastModified(date_modified);

Specifying Template Processor callback

It is possible to specify template processor for static files. For information on template processor see
Respond with content coming from a File containing templates.

String processor(const String& var)
{
  if(var == "HELLO_FROM_TEMPLATE")
    return F("Hello world!");
  return String();
}

// ...

server.serveStatic("/", SPIFFS, "/www/").setTemplateProcessor(processor);

Param Rewrite With Matching

It is possible to rewrite the request url with parameter matchg. Here is an example with one parameter:
Rewrite for example «/radio/{frequence}» -> «/radio?f={frequence}»

class OneParamRewrite : public AsyncWebRewrite
{
  protected:
    String _urlPrefix;
    int _paramIndex;
    String _paramsBackup;

  public:
  OneParamRewrite(const char* from, const char* to)
    : AsyncWebRewrite(from, to) {

      _paramIndex = _from.indexOf('{');

      if( _paramIndex >=0 && _from.endsWith("}")) {
        _urlPrefix = _from.substring(0, _paramIndex);
        int index = _params.indexOf('{');
        if(index >= 0) {
          _params = _params.substring(0, index);
        }
      } else {
        _urlPrefix = _from;
      }
      _paramsBackup = _params;
  }

  bool match(AsyncWebServerRequest *request) override {
    if(request->url().startsWith(_urlPrefix)) {
      if(_paramIndex >= 0) {
        _params = _paramsBackup + request->url().substring(_paramIndex);
      } else {
        _params = _paramsBackup;
      }
    return true;

    } else {
      return false;
    }
  }
};

Usage:

  server.addRewrite( new OneParamRewrite("/radio/{frequence}", "/radio?f={frequence}") );

Using filters

Filters can be set to Rewrite or Handler in order to control when to apply the rewrite and consider the handler.
A filter is a callback function that evaluates the request and return a boolean true to include the item
or false to exclude it.
Two filter callback are provided for convince:

  • ON_STA_FILTER — return true when requests are made to the STA (station mode) interface.
  • ON_AP_FILTER — return true when requests are made to the AP (access point) interface.

Serve different site files in AP mode

server.serveStatic("/", SPIFFS, "/www/").setFilter(ON_STA_FILTER);
server.serveStatic("/", SPIFFS, "/ap/").setFilter(ON_AP_FILTER);

Rewrite to different index on AP

// Serve the file "/www/index-ap.htm" in AP, and the file "/www/index.htm" on STA
server.rewrite("/", "index.htm");
server.rewrite("/index.htm", "index-ap.htm").setFilter(ON_AP_FILTER);
server.serveStatic("/", SPIFFS, "/www/");

Serving different hosts

// Filter callback using request host
bool filterOnHost1(AsyncWebServerRequest *request) { return request->host() == "host1"; }

// Server setup: server files in "/host1/" to requests for "host1", and files in "/www/" otherwise.
server.serveStatic("/", SPIFFS, "/host1/").setFilter(filterOnHost1);
server.serveStatic("/", SPIFFS, "/www/");

Determine interface inside callbacks

  String RedirectUrl = "http://";
  if (ON_STA_FILTER(request)) {
    RedirectUrl += WiFi.localIP().toString();
  } else {
    RedirectUrl += WiFi.softAPIP().toString();
  }
  RedirectUrl += "/index.htm";
  request->redirect(RedirectUrl);

Bad Responses

Some responses are implemented, but you should not use them, because they do not conform to HTTP.
The following example will lead to unclean close of the connection and more time wasted
than providing the length of the content

Respond with content using a callback without content length to HTTP/1.0 clients

//This is used as fallback for chunked responses to HTTP/1.0 Clients
request->send("text/plain", 0, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
  //Write up to "maxLen" bytes into "buffer" and return the amount written.
  //You will be asked for more data until 0 is returned
  //Keep in mind that you can not delay or yield waiting for more data!
  return mySource.read(buffer, maxLen);
});

Async WebSocket Plugin

The server includes a web socket plugin which lets you define different WebSocket locations to connect to
without starting another listening service or using different port

Async WebSocket Event

void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
  if(type == WS_EVT_CONNECT){
    //client connected
    os_printf("ws[%s][%u] connectn", server->url(), client->id());
    client->printf("Hello Client %u :)", client->id());
    client->ping();
  } else if(type == WS_EVT_DISCONNECT){
    //client disconnected
    os_printf("ws[%s][%u] disconnect: %un", server->url(), client->id());
  } else if(type == WS_EVT_ERROR){
    //error was received from the other end
    os_printf("ws[%s][%u] error(%u): %sn", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
  } else if(type == WS_EVT_PONG){
    //pong message was received (in response to a ping request maybe)
    os_printf("ws[%s][%u] pong[%u]: %sn", server->url(), client->id(), len, (len)?(char*)data:"");
  } else if(type == WS_EVT_DATA){
    //data packet
    AwsFrameInfo * info = (AwsFrameInfo*)arg;
    if(info->final && info->index == 0 && info->len == len){
      //the whole message is in a single frame and we got all of it's data
      os_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
      if(info->opcode == WS_TEXT){
        data[len] = 0;
        os_printf("%sn", (char*)data);
      } else {
        for(size_t i=0; i < info->len; i++){
          os_printf("%02x ", data[i]);
        }
        os_printf("n");
      }
      if(info->opcode == WS_TEXT)
        client->text("I got your text message");
      else
        client->binary("I got your binary message");
    } else {
      //message is comprised of multiple frames or the frame is split into multiple packets
      if(info->index == 0){
        if(info->num == 0)
          os_printf("ws[%s][%u] %s-message startn", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
        os_printf("ws[%s][%u] frame[%u] start[%llu]n", server->url(), client->id(), info->num, info->len);
      }

      os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
      if(info->message_opcode == WS_TEXT){
        data[len] = 0;
        os_printf("%sn", (char*)data);
      } else {
        for(size_t i=0; i < len; i++){
          os_printf("%02x ", data[i]);
        }
        os_printf("n");
      }

      if((info->index + len) == info->len){
        os_printf("ws[%s][%u] frame[%u] end[%llu]n", server->url(), client->id(), info->num, info->len);
        if(info->final){
          os_printf("ws[%s][%u] %s-message endn", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
          if(info->message_opcode == WS_TEXT)
            client->text("I got your text message");
          else
            client->binary("I got your binary message");
        }
      }
    }
  }
}

Methods for sending data to a socket client

//Server methods
AsyncWebSocket ws("/ws");
//printf to a client
ws.printf((uint32_t)client_id, arguments...);
//printf to all clients
ws.printfAll(arguments...);
//printf_P to a client
ws.printf_P((uint32_t)client_id, PSTR(format), arguments...);
//printfAll_P to all clients
ws.printfAll_P(PSTR(format), arguments...);
//send text to a client
ws.text((uint32_t)client_id, (char*)text);
ws.text((uint32_t)client_id, (uint8_t*)text, (size_t)len);
//send text from PROGMEM to a client
ws.text((uint32_t)client_id, PSTR("text"));
const char flash_text[] PROGMEM = "Text to send"
ws.text((uint32_t)client_id, FPSTR(flash_text));
//send text to all clients
ws.textAll((char*)text);
ws.textAll((uint8_t*)text, (size_t)len);
//send binary to a client
ws.binary((uint32_t)client_id, (char*)binary);
ws.binary((uint32_t)client_id, (uint8_t*)binary, (size_t)len);
//send binary from PROGMEM to a client
const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 };
ws.binary((uint32_t)client_id, flash_binary, 4);
//send binary to all clients
ws.binaryAll((char*)binary);
ws.binaryAll((uint8_t*)binary, (size_t)len);
//HTTP Authenticate before switch to Websocket protocol
ws.setAuthentication("user", "pass");

//client methods
AsyncWebSocketClient * client;
//printf
client->printf(arguments...);
//printf_P
client->printf_P(PSTR(format), arguments...);
//send text
client->text((char*)text);
client->text((uint8_t*)text, (size_t)len);
//send text from PROGMEM
client->text(PSTR("text"));
const char flash_text[] PROGMEM = "Text to send";
client->text(FPSTR(flash_text));
//send binary
client->binary((char*)binary);
client->binary((uint8_t*)binary, (size_t)len);
//send binary from PROGMEM
const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 };
client->binary(flash_binary, 4);

Direct access to web socket message buffer

When sending a web socket message using the above methods a buffer is created. Under certain circumstances you might want to manipulate or populate this buffer directly from your application, for example to prevent unnecessary duplications of the data. This example below shows how to create a buffer and print data to it from an ArduinoJson object then send it.

void sendDataWs(AsyncWebSocketClient * client)
{
    DynamicJsonBuffer jsonBuffer;
    JsonObject& root = jsonBuffer.createObject();
    root["a"] = "abc";
    root["b"] = "abcd";
    root["c"] = "abcde";
    root["d"] = "abcdef";
    root["e"] = "abcdefg";
    size_t len = root.measureLength();
    AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer(len); //  creates a buffer (len + 1) for you.
    if (buffer) {
        root.printTo((char *)buffer->get(), len + 1);
        if (client) {
            client->text(buffer);
        } else {
            ws.textAll(buffer);
        }
    }
}

Limiting the number of web socket clients

Browsers sometimes do not correctly close the websocket connection, even when the close() function is called in javascript. This will eventually exhaust the web server’s resources and will cause the server to crash. Periodically calling the cleanClients() function from the main loop() function limits the number of clients by closing the oldest client when the maximum number of clients has been exceeded. This can called be every cycle, however, if you wish to use less power, then calling as infrequently as once per second is sufficient.

void loop(){
  ws.cleanupClients();
}

Async Event Source Plugin

The server includes EventSource (Server-Sent Events) plugin which can be used to send short text events to the browser.
Difference between EventSource and WebSockets is that EventSource is single direction, text-only protocol.

Setup Event Source on the server

AsyncWebServer server(80);
AsyncEventSource events("/events");

void setup(){
  // setup ......
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it gat is: %un", client->lastId());
    }
    //send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!",NULL,millis(),1000);
  });
  //HTTP Basic authentication
  events.setAuthentication("user", "pass");
  server.addHandler(&events);
  // setup ......
}

void loop(){
  if(eventTriggered){ // your logic here
    //send event "myevent"
    events.send("my event content","myevent",millis());
  }
}

Setup Event Source in the browser

if (!!window.EventSource) {
  var source = new EventSource('/events');

  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);

  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('message', function(e) {
    console.log("message", e.data);
  }, false);

  source.addEventListener('myevent', function(e) {
    console.log("myevent", e.data);
  }, false);
}

Scanning for available WiFi Networks

//First request will return 0 results unless you start scan from somewhere else (loop/setup)
//Do not request more often than 3-5 seconds
server.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){
  String json = "[";
  int n = WiFi.scanComplete();
  if(n == -2){
    WiFi.scanNetworks(true);
  } else if(n){
    for (int i = 0; i < n; ++i){
      if(i) json += ",";
      json += "{";
      json += ""rssi":"+String(WiFi.RSSI(i));
      json += ","ssid":""+WiFi.SSID(i)+""";
      json += ","bssid":""+WiFi.BSSIDstr(i)+""";
      json += ","channel":"+String(WiFi.channel(i));
      json += ","secure":"+String(WiFi.encryptionType(i));
      json += ","hidden":"+String(WiFi.isHidden(i)?"true":"false");
      json += "}";
    }
    WiFi.scanDelete();
    if(WiFi.scanComplete() == -2){
      WiFi.scanNetworks(true);
    }
  }
  json += "]";
  request->send(200, "application/json", json);
  json = String();
});

Remove handlers and rewrites

Server goes through handlers in same order as they were added. You can’t simple add handler with same path to override them.
To remove handler:

// save callback for particular URL path
auto handler = server.on("/some/path", [](AsyncWebServerRequest *request){
  //do something useful
});
// when you don't need handler anymore remove it
server.removeHandler(&handler);

// same with rewrites
server.removeRewrite(&someRewrite);

server.onNotFound([](AsyncWebServerRequest *request){
  request->send(404);
});

// remove server.onNotFound handler
server.onNotFound(NULL);

// remove all rewrites, handlers and onNotFound/onFileUpload/onRequestBody callbacks
server.reset();

Setting up the server

#include "ESPAsyncTCP.h"
#include "ESPAsyncWebServer.h"

AsyncWebServer server(80);
AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws
AsyncEventSource events("/events"); // event source (Server-Sent events)

const char* ssid = "your-ssid";
const char* password = "your-pass";
const char* http_username = "admin";
const char* http_password = "admin";

//flag to use from web update to reboot the ESP
bool shouldReboot = false;

void onRequest(AsyncWebServerRequest *request){
  //Handle Unknown Request
  request->send(404);
}

void onBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
  //Handle body
}

void onUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
  //Handle upload
}

void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
  //Handle WebSocket event
}

void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.printf("WiFi Failed!n");
    return;
  }

  // attach AsyncWebSocket
  ws.onEvent(onEvent);
  server.addHandler(&ws);

  // attach AsyncEventSource
  server.addHandler(&events);

  // respond to GET requests on URL /heap
  server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", String(ESP.getFreeHeap()));
  });

  // upload a file to /upload
  server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request){
    request->send(200);
  }, onUpload);

  // send a file when /index is requested
  server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.htm");
  });

  // HTTP basic authentication
  server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request){
    if(!request->authenticate(http_username, http_password))
        return request->requestAuthentication();
    request->send(200, "text/plain", "Login Success!");
  });

  // Simple Firmware Update Form
  server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>");
  });
  server.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){
    shouldReboot = !Update.hasError();
    AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot?"OK":"FAIL");
    response->addHeader("Connection", "close");
    request->send(response);
  },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
    if(!index){
      Serial.printf("Update Start: %sn", filename.c_str());
      Update.runAsync(true);
      if(!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)){
        Update.printError(Serial);
      }
    }
    if(!Update.hasError()){
      if(Update.write(data, len) != len){
        Update.printError(Serial);
      }
    }
    if(final){
      if(Update.end(true)){
        Serial.printf("Update Success: %uBn", index+len);
      } else {
        Update.printError(Serial);
      }
    }
  });

  // attach filesystem root at URL /fs
  server.serveStatic("/fs", SPIFFS, "/");

  // Catch-All Handlers
  // Any request that can not find a Handler that canHandle it
  // ends in the callbacks below.
  server.onNotFound(onRequest);
  server.onFileUpload(onUpload);
  server.onRequestBody(onBody);

  server.begin();
}

void loop(){
  if(shouldReboot){
    Serial.println("Rebooting...");
    delay(100);
    ESP.restart();
  }
  static char temp[128];
  sprintf(temp, "Seconds since boot: %u", millis()/1000);
  events.send(temp, "time"); //send event "time"
}

Setup global and class functions as request handlers

#include <Arduino.h>
#include <ESPAsyncWebserver.h>
#include <Hash.h>
#include <functional>

void handleRequest(AsyncWebServerRequest *request){}

class WebClass {
public :
  AsyncWebServer classWebServer = AsyncWebServer(81);

  WebClass(){};

  void classRequest (AsyncWebServerRequest *request){}

  void begin(){
    // attach global request handler
    classWebServer.on("/example", HTTP_ANY, handleRequest);

    // attach class request handler
    classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
  }
};

AsyncWebServer globalWebServer(80);
WebClass webClassInstance;

void setup() {
  // attach global request handler
  globalWebServer.on("/example", HTTP_ANY, handleRequest);

  // attach class request handler
  globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
}

void loop() {

}

Methods for controlling websocket connections

  // Disable client connections if it was activated
  if ( ws.enabled() )
    ws.enable(false);

  // enable client connections if it was disabled
  if ( !ws.enabled() )
    ws.enable(true);

Example of OTA code

  // OTA callbacks
  ArduinoOTA.onStart([]() {
    // Clean SPIFFS
    SPIFFS.end();

    // Disable client connections    
    ws.enable(false);

    // Advertise connected clients what's going on
    ws.textAll("OTA Update Started");

    // Close them
    ws.closeAll();

  });

Adding Default Headers

In some cases, such as when working with CORS, or with some sort of custom authentication system,
you might need to define a header that should get added to all responses (including static, websocket and EventSource).
The DefaultHeaders singleton allows you to do this.

Example:

DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
webServer.begin();

NOTE: You will still need to respond to the OPTIONS method for CORS pre-flight in most cases. (unless you are only using GET)

This is one option:

webServer.onNotFound([](AsyncWebServerRequest *request) {
  if (request->method() == HTTP_OPTIONS) {
    request->send(200);
  } else {
    request->send(404);
  }
});

Recommend Projects

  • React photo

    React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo

    Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo

    Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo

    TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo

    Django

    The Web framework for perfectionists with deadlines.

  • Laravel photo

    Laravel

    A PHP framework for web artisans

  • D3 photo

    D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Visualization

    Some thing interesting about visualization, use data art

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo

    Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo

    Microsoft

    Open source projects and samples from Microsoft.

  • Google photo

    Google

    Google ❤️ Open Source for everyone.

  • Alibaba photo

    Alibaba

    Alibaba Open Source for everyone

  • D3 photo

    D3

    Data-Driven Documents codes.

  • Tencent photo

    Tencent

    China tencent open source team.

JoKeR_13


  • #1

Доброго!
Поделитесь рабочим примером, как со страницы отправить json и обработать его в прошивке.
На стороне прошивки пробую так:

AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/post-message", [](AsyncWebServerRequest *request, JsonVariant &json) {
  Serial.println("JSON");
  JsonObject jsonObj = json.as<JsonObject>();
  String response;
  serializeJson(jsonObj, response);
  request->send(200, "application/json", response);
  Serial.println(response);
});

  server.addHandler(handler);

Из HTML вот так отправляю:

 $.ajax({
        url: '/post-message',
        type: 'POST',
        data: JSON.stringify(json),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        success: function(msg) {
            alert(msg);
        }
    });

Но я не попадаю в эту часть кода.

Буду признателен за помощь

  • #2

@JoKeR_13, есть готовый фреймворк берущий на себя весь обмен, берите, изучайте, пользуйтесь. Ну либо читайте исходники для понимания как организован обмен туда-сюда. На этом фреймворке сделана лампа, в теме можете поглядеть как интерфейс выглядит. Ну и ессно все крутится на ESPAsyncWebServer, при этом сам фреймворк работает как на есп8266, так и на есп32.

JoKeR_13


  • #3

@JoKeR_13, есть готовый фреймворк берущий на себя весь обмен, берите, изучайте, пользуйтесь. Ну либо читайте исходники для понимания как организован обмен туда-сюда. На этом фреймворке сделана лампа, в теме можете поглядеть как интерфейс выглядит. Ну и ессно все крутится на ESPAsyncWebServer, при этом сам фреймворк работает как на есп8266, так и на есп32.

Пробую example из библиотеки и после прошивки получаю циклическую перезагрузку
wdt reset
load 0x4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
Starting test…
UI: Creating system vars
UI CREATE key: (hostname) value: () RAM: 37656
UI CREATE key: (APonly) value: (false) RAM: 37656
UI CREATE key: (APpwd) value: () RAM: 37656
UI CREATE key: (m_host) value: () RAM: 37656
UI CREATE key: (m_port) value: () RAM: 37656
UI CREATE key: (m_user) value: () RAM: 37656
UI CREATE key: (m_pass) value: () RAM: 37656
UI CREATE key: (m_pref) value: () RAM: 37656
UI CREATE key: (m_tupd) value: (30) RAM: 37656
UI CREATE key: (TZSET) value: () RAM: 37656
UI CREATE key: (userntp) value: () RAM: 37656

ets Jan 8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
Starting test…

  • #4

@JoKeR_13, с какого бренча брали фреймворк? Работает ли второй пример? Записали ли ФС предварительно?

Проверил на дев-ветке, без ФС:

rd␀d��|␀�l�|␃␄␌␄�␄$�␄c|��␃�␒�;�c�␄c��g'�lng���␌b␜x��l;l{l8�g�␐␃␌␄�␄l␌Ĝ␄␌␌b␌'�|␃�l�␌�b��og�␀l��l`␃�␛␛go␌d`␂␎␃gs�ۓo␌␄#␃$`␃␏;��g␄␌c␃l`␃�c␄␌�␜␃�$r�`␂��n�␃Starting test...
UI: Creating system vars
UI CREATE key: (hostname) value: () RAM: 45888
UI CREATE key: (APonly) value: (false) RAM: 45888
UI CREATE key: (APpwd) value: () RAM: 45888
UI CREATE key: (m_host) value: () RAM: 45888
UI CREATE key: (m_port) value: () RAM: 45888
UI CREATE key: (m_user) value: () RAM: 45888
UI CREATE key: (m_pass) value: () RAM: 45888
UI CREATE key: (m_pref) value: () RAM: 45888
UI CREATE key: (m_tupd) value: (30) RAM: 45888
UI CREATE key: (TZSET) value: () RAM: 45888
UI CREATE key: (userntp) value: () RAM: 45888
UI: Creating application vars
UI: Creating webui vars
UI CREATE key: (lang) value: (0) RAM: 45888
UI REGISTER: settings
UI REGISTER: sh_netw
UI REGISTER: sh_time
UI REGISTER: set_wifi
UI REGISTER: set_wifiAP
UI REGISTER: set_mqtt
UI REGISTER: set_time
UI REGISTER: lang
UI CREATE key: (v1) value: () RAM: 45568
UI REGISTER: demo
UI REGISTER: do_demo
UI CONFIG: {"hostname":"","APonly":"false","APpwd":"","m_host":"","m_port":"","m_user":"","m_pass":"","m_pref":"","m_tupd":"30","TZSET":"","userntp":"","lang":"0","v1":""}
UI READ: key (TZSET) value ()
UI READ: key (userntp) value ()
UI READ: key (hostname) value ()
UI READ: key (APpwd) value ()
UI MAC ID:3C728E
UI WRITE: key (hostname) value (EmbUI-3C728E) UI FREE: 1729
UI WiFi: set AP params to SSID:EmbUI-3C728E, pwd:
UI READ: key (APonly) value (false)
UI WiFi: start in AP/STA mode
UI WiFi: STA reconecting...
UI: Save default main config file
UI: AutoSave

Точка доступа создается и к ней без проблем подключаюсь, при переходе на 192.168.4.1 — Not found (так и должно быть)
Распаковываю ProjectsEmbUIresourcesdata.zip в PlatformIOProjectsEmbUIexamplesex_genericdata , собираю ФС, заливаю в контроллер — UI доступен.

1611929357553.png

JoKeR_13


  • #5

Сорри, я уже сделал. Не то запускалось. Сижу штудирую

  • #6

Да без проблем, баги не исключены, в том числе и в примерах, поскольку редко туда заглядываем. :)

JoKeR_13


  • #7

А можно простой пример как вывести на страничку переменную, скажем с температурой, что бы она обновлялась? Я так понял есть 2 пути сделать в html свой объект с id и указать его в программе, как сделано с часами, версией и памятью, а можно и программно вывести. Интересно програмно

  • #8

А можно простой пример как вывести на страничку переменную, скажем с температурой, что бы она обновлялась? Я так понял есть 2 пути сделать в html свой объект с id и указать его в программе, как сделано с часами, версией и памятью, а можно и программно вывести. Интересно програмно

Поглядите как выводится % обновления по ОТА в лампе и сделайте аналогично. Ну или еще вариант в той же лампе — отложенная загрузка имен эффектов сделана так, что значения контрола лукапа подменяются на другие через 10 секунд. Если по простому — то нужно попросту передать повторно требуемую секцию с контролами и она будет обновлена.

* Накидал простейший пример, где предполагается что функция periodicCall() дергается с некоторой периодичностью.

void show_info(Interface *interf, JsonObject *data);

void periodicCall(){
    DynamicJsonDocument doc(256);
    JsonObject obj = doc.to<JsonObject>();

    obj["param"] = String("value to show: ") + String(millis());
    CALL_INTF_OBJ(show_info);
}

void show_info(Interface *interf, JsonObject *data){
    if (!interf) return;
    
    interf->json_frame_interface();
        interf->json_section_content();
            interf->comment("Comment");
            interf->text("id", (*data)["param"]);
        interf->json_section_end();
    interf->json_frame_flush();
}

Изменено: 4 Фев 2021

You want to add custom features to WLED, use non-default pins, or add in a usermod? You’ve found the right place!

Tip

Only want to build the code with some custom defines to e.g. enable a usermod?
Unless you want to do changes yourself, you don’t necessarily have to install the development environment.
In the WLED Discord server, there is the WBLD bot which will build your custom PIO environemt with the ./build custom command.

WLED has come to rely on so many dependencies in the latest versions that building with the Arduino IDE is no longer recommended.
Instead, installing Visual Studio Code and its PlatformIO (PIO) extension is easier, as it will install the ESP Arduino core, all the required libraries and the correct compilation settings for you automatically.

Installation guide (PlatformIO, recommended)

  1. Make sure Git client is installed on your system. If it isn’t, you can get it here.
  2. Download and install the free Visual Studio Code by Microsoft.
  3. Open VS Code and go to the Extensions manager (the icon with the stacked blocks in the left bar)
  4. Search for platformio ide and install the PlatformIO extension
  5. Download the WLED source code by executing git clone https://github.com/Aircoookie/WLED.git in some folder.
    (You can also use GitHub Desktop or download the latest source code from https://github.com/Aircoookie/WLED under the Code dropdown menu as a .zip file.)
    Alternatively fork the WLED project first and download it from your fork.

  6. Go to File -> Open Folder and open that root WLED folder (the one that contains platformio.ini, NOT the wled00 folder)


Compilation guide (PlatformIO)

Tip

Make sure Git Client is installed on your system. You can get it here.

  1. In VS Code, open the file platformio.ini.
  2. Add a semicolon in front of the line that says default_envs = travis_esp8266, travis_esp32 to comment it out.
  3. Select your build environment by un-commenting one of the lines starting with ; default_envs =.
    Please remove BOTH the ; and the whitespace behind it to correctly uncomment the line.
    For most ESP8266 boards, the d1_mini environment is best.
  4. In the blue bottom bar, hit the checkmark to compile WLED or the arrow pointing right to compile and upload!

Picture Guide

Success!

If you get one of these two errors, hit the checkmark icon once again to compile and that time the code should build without problems!

  • error: wled00wled00.ino.cpp: No such file or directory
  • FileNotFoundError: [WinError 2] The system cannot find the file specified: '[...].sconsign37.dblite'

Making a custom environment

Once you’ve confirmed VSCode with Platformio is set up correctly, you can add/define overrides to allow you to use non-default pins, add a usermod, or add other custom features.

  1. Copy and paste the contents of platformio_override.ini.sample into a new file called platformio_override.ini. Make sure platformio_override.ini is in the same folder as platformio.ini.
  2. Replace the line default_envs = WLED_tasmota_1M with the line you uncommented in platformio.ini in the previous steps (from Compilation guide (PlatformIO)). Example: default_envs = d1_mini
  3. In platformio.ini scroll down until you see
    #--------------------
    # WLED BUILDS
    #--------------------
  4. Find the section that matches the build environment you selected in previous steps. Example: [env:d1_mini]
  5. Select the whole section (including the first line in brackets [ ] ), and copy and paste it into platformio_override.ini overwriting the build environment section that was already there.
  6. Add a new line under the the line that starts with build_flags =
  7. Put your -D overrides on this new line, giving each -D it’s own new line.
  8. Compile your freshly customized WLED image!

Flashing the compiled binary

Tip

This step is optional and only recommended if you want to install the same binary to multiple boards. For testing, it is easiest to upload directly from PlatformIO

The .bin file is located in the subfolder /build_output/firmware in your WLED folder. The binary will have the same name as your environment.

All that’s left to do is flash this .bin file onto your ESP board and then connect it to WiFi.

Compilation guide (Arduino IDE, not recommended)

Warning

This method is outdated. The source is no longer officially checked to be buildable with the Arduino IDE. Using PlatformIO is strongly advised.

  • Follow a guide to setup your Arduino IDE (I am using version 1.8.9) with the ESP8266 libraries.
    For current compiles I recommend the latest Arduino core version 2.7.4. If you do not wish to install all libraries manually it is recommended to download the PlatformIO extension for VS Code (see above).

  • You will need to install a few libraries:

Library Name Platform
NeoPixelBus (2.6.0) All
FastLED All
ESPAsyncWebServer Aircoookie fork (2.0.0) All
IRRemoteESP8266 All
ESPAsyncTCP ESP8266 only
ESPAsyncUDP ESP8266 only
AsyncTCP for ESP32 ESP32 only
LITTLEFS_esp32* ESP32 only

* Please see the installation guide. You might need to enable a define in the library code.

All other dependencies are included with WLED for convenience.

  • Now compile and flash the software! Make sure you erase everything when you flash! (If your board config does not provide this option, you can Sketch -> Export compiled Binary and upload with any ESP flashing tool.)

Compilation settings (Arduino IDE)

ESP8266:

  • Arduino Core v2.7.4
  • Board: NodeMCU 1.0 (ESP-12E module) (or select your ESP board)
  • CPU frequency: 80 MHz
  • Flash size : 4MB (1MB SPIFFS)
  • LwIP variant: v1.4 Higher Bandwidth (try 2 if you experience issues)
  • Upload speed: Any, 921600 recommended

ESP8266-07 (External Antenna):

  • Variants have 512kB or 1MB flash
  • Be sure to use DOUT mode when flashing
  • Flash Size 1MB (128k SPIFFS)
  • 512kB variant no longer compatible

ESP-07s (External Antenna):

  • Variant has 4MB flash
  • Settings as for NodeMCU or Wemos

ESP32:

  • Arduino Core v1.0.6

wolfrose

Posts: 7
Joined: Mon Oct 26, 2020 2:58 pm

ESPAsyncWebServer.h: No such file or directory

Hi,

I’m trying to compile an example in this website.

https://shawnhymel.com/1882/how-to-crea … n-arduino/

But I get this error. I have downloaded both ESPAsyncWebServer.h and AsyncTCP.h and put them in ESP32 libraries folder but I get the same error ! What to do now ?

I read in this page:
https://github.com/me-no-dev/ESPAsyncWebServer

This:

For ESP8266 it requires ESPAsyncTCP To use this library you might need to have the latest git versions of ESP8266 Arduino Core

For ESP32 it requires AsyncTCP to work To use this library you might need to have the latest git versions of ESP32 Arduino Core

So I did what it tells and put:
ESPAsyncWebServer with ESPAsyncTCP in ESP8266 folder
AsyncTCP with ESPAsyncWebServer in ESP32 folder

But same error !


lbernstone

Posts: 311
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESPAsyncWebServer.h: No such file or directory

Postby lbernstone » Mon Oct 26, 2020 5:23 pm

The Arduino library folder is <home>/Arduino/libraries. This is where libraries downloaded using the library manager end up.
Do not put anything in .arduino15/packages/esp32/**. This is the built-in board specific libraries and will be removed/updated with the board.


wolfrose

Posts: 7
Joined: Mon Oct 26, 2020 2:58 pm

Re: ESPAsyncWebServer.h: No such file or directory

Postby wolfrose » Wed Oct 28, 2020 4:19 pm

Yep, you’re right. They must be in this path.

OK, now I’ve got another problem. I can’t run the ESP32 to connect to my wifi as the same example with the esp8266. I’ve done the esp8266 webserver example without problems. The esp32 isn’t responding.


Who is online

Users browsing this forum: No registered users and 15 guests

Понравилась статья? Поделить с друзьями:
  • Error xml parser perl module is required for intltool
  • Error xhr request timed out
  • Error xhr request aborted by browser
  • Error xgen searched path includes
  • Error x3000 unrecognized identifier