├── .gitignore ├── .travis.yml ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── include └── README ├── lib ├── ESPAsyncWebServer │ ├── .github │ │ ├── scripts │ │ │ ├── install-arduino-core-esp32.sh │ │ │ ├── install-arduino-core-esp8266.sh │ │ │ ├── install-arduino-ide.sh │ │ │ ├── install-platformio.sh │ │ │ └── on-push.sh │ │ ├── stale.yml │ │ └── workflows │ │ │ └── push.yml │ ├── .gitignore │ ├── .travis.yml │ ├── CMakeLists.txt │ ├── README.md │ ├── _config.yml │ ├── component.mk │ ├── examples │ │ ├── CaptivePortal │ │ │ └── CaptivePortal.ino │ │ ├── ESP_AsyncFSBrowser │ │ │ ├── ESP_AsyncFSBrowser.ino │ │ │ └── data │ │ │ │ ├── .exclude.files │ │ │ │ ├── ace.js.gz │ │ │ │ ├── ext-searchbox.js.gz │ │ │ │ ├── favicon.ico │ │ │ │ ├── index.htm │ │ │ │ ├── mode-css.js.gz │ │ │ │ ├── mode-html.js.gz │ │ │ │ ├── mode-javascript.js.gz │ │ │ │ └── worker-html.js.gz │ │ ├── regex_patterns │ │ │ ├── .test.build_flags │ │ │ └── regex_patterns.ino │ │ └── simple_server │ │ │ └── simple_server.ino │ ├── keywords.txt │ ├── library.json │ ├── library.properties │ └── src │ │ ├── AsyncEventSource.cpp │ │ ├── AsyncEventSource.h │ │ ├── AsyncJson.h │ │ ├── AsyncWebSocket.cpp │ │ ├── AsyncWebSocket.h │ │ ├── AsyncWebSynchronization.h │ │ ├── ESPAsyncWebServer.h │ │ ├── SPIFFSEditor.cpp │ │ ├── SPIFFSEditor.h │ │ ├── StringArray.h │ │ ├── WebAuthentication.cpp │ │ ├── WebAuthentication.h │ │ ├── WebHandlerImpl.h │ │ ├── WebHandlers.cpp │ │ ├── WebRequest.cpp │ │ ├── WebResponseImpl.h │ │ ├── WebResponses.cpp │ │ ├── WebServer.cpp │ │ └── edit.htm ├── README └── TB6612FNG_ESP32 │ ├── .gitignore │ ├── .travis.yml │ ├── README.md │ ├── examples │ ├── main.cpp │ └── motors │ │ └── motors.ino │ ├── lib │ └── readme.txt │ ├── library.properties │ ├── platformio.ini │ └── src │ ├── TB6612_ESP32.cpp │ └── TB6612_ESP32.h ├── main.cpp ├── platformio.ini ├── src ├── config.h ├── main.cpp └── web.h ├── test └── README └── web_smars.html /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | homewifi.cpp 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 Wifi Tank web control code 2 | 3 | Esp32 webserver robot tank control. Uses only one Jostick to control the movement. Based on TB6612FNG motor driver and smars project robot, uses async HTML protocol. 4 | 5 | ## Configuration 6 | 7 | You need to modify your password and SSID to a personal one, and set your TB6612FNG Driver pins. 8 | 9 | src/config.h contains the setup. 10 | 11 | ## More info 12 | 13 | You can find more detailed info about how it works and hoy to modify it in the following [blog post](https://nkmakes.github.io/2020/09/02/esp32-tank-robot-joystick-http-web-control/), and see it in action in the following [youtube video](https://www.youtube.com/watch?v=uIImwilvI2s). 14 | 15 | 16 | ## Used Libraries and acknowledgements 17 | 18 | Uses the following libraries and couldn't be done withouth the following posts 19 | - [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) 20 | - [TB6612_ESP32](https://github.com/pablopeza/TB6612FNG_ESP32) 21 | - [jostick JS library from bobbotek](https://github.com/bobboteck/JoyStick) 22 | - [Differential control](https://www.impulseadventure.com/elec/robot-differential-steering.html) 23 | - [Async service](https://github.com/neonious/lowjs_esp32_examples/blob/master/neonious_one/cellphone_controlled_rc_car/www/index.html) 24 | - [web baker](https://gchq.github.io/CyberChef/#recipe=Gzip('Dynamic%20Huffman%20Coding','index.html.gz','',false)To_Hex('0x',0)Split('0x',',0x')) 25 | 26 | Huge thanks to the authors, feel free to donate them! -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export ARDUINO_ESP32_PATH="$ARDUINO_USR_PATH/hardware/espressif/esp32" 4 | if [ ! -d "$ARDUINO_ESP32_PATH" ]; then 5 | echo "Installing ESP32 Arduino Core ..." 6 | script_init_path="$PWD" 7 | mkdir -p "$ARDUINO_USR_PATH/hardware/espressif" 8 | cd "$ARDUINO_USR_PATH/hardware/espressif" 9 | 10 | echo "Installing Python Serial ..." 11 | pip install pyserial > /dev/null 12 | 13 | if [ "$OS_IS_WINDOWS" == "1" ]; then 14 | echo "Installing Python Requests ..." 15 | pip install requests > /dev/null 16 | fi 17 | 18 | if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then 19 | echo "Linking Core..." 20 | ln -s $GITHUB_WORKSPACE esp32 21 | else 22 | echo "Cloning Core Repository..." 23 | git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1 24 | fi 25 | 26 | echo "Updating Submodules ..." 27 | cd esp32 28 | git submodule update --init --recursive > /dev/null 2>&1 29 | 30 | echo "Installing Platform Tools ..." 31 | cd tools && python get.py 32 | cd $script_init_path 33 | 34 | echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'" 35 | echo "" 36 | fi 37 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Installing ESP8266 Arduino Core ..." 4 | script_init_path="$PWD" 5 | mkdir -p "$ARDUINO_USR_PATH/hardware/esp8266com" 6 | cd "$ARDUINO_USR_PATH/hardware/esp8266com" 7 | 8 | echo "Installing Python Serial ..." 9 | pip install pyserial > /dev/null 10 | 11 | if [ "$OS_IS_WINDOWS" == "1" ]; then 12 | echo "Installing Python Requests ..." 13 | pip install requests > /dev/null 14 | fi 15 | 16 | echo "Cloning Core Repository ..." 17 | git clone https://github.com/esp8266/Arduino.git esp8266 > /dev/null 2>&1 18 | 19 | echo "Updating submodules ..." 20 | cd esp8266 21 | git submodule update --init --recursive > /dev/null 2>&1 22 | 23 | echo "Installing Platform Tools ..." 24 | cd tools 25 | python get.py > /dev/null 26 | cd $script_init_path 27 | 28 | echo "ESP8266 Arduino has been installed in '$ARDUINO_USR_PATH/hardware/esp8266com'" 29 | echo "" 30 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #OSTYPE: 'linux-gnu', ARCH: 'x86_64' => linux64 4 | #OSTYPE: 'msys', ARCH: 'x86_64' => win32 5 | #OSTYPE: 'darwin18', ARCH: 'i386' => macos 6 | 7 | OSBITS=`arch` 8 | if [[ "$OSTYPE" == "linux"* ]]; then 9 | export OS_IS_LINUX="1" 10 | ARCHIVE_FORMAT="tar.xz" 11 | if [[ "$OSBITS" == "i686" ]]; then 12 | OS_NAME="linux32" 13 | elif [[ "$OSBITS" == "x86_64" ]]; then 14 | OS_NAME="linux64" 15 | elif [[ "$OSBITS" == "armv7l" || "$OSBITS" == "aarch64" ]]; then 16 | OS_NAME="linuxarm" 17 | else 18 | OS_NAME="$OSTYPE-$OSBITS" 19 | echo "Unknown OS '$OS_NAME'" 20 | exit 1 21 | fi 22 | elif [[ "$OSTYPE" == "darwin"* ]]; then 23 | export OS_IS_MACOS="1" 24 | ARCHIVE_FORMAT="zip" 25 | OS_NAME="macosx" 26 | elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then 27 | export OS_IS_WINDOWS="1" 28 | ARCHIVE_FORMAT="zip" 29 | OS_NAME="windows" 30 | else 31 | OS_NAME="$OSTYPE-$OSBITS" 32 | echo "Unknown OS '$OS_NAME'" 33 | exit 1 34 | fi 35 | export OS_NAME 36 | 37 | ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp" 38 | ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" 39 | 40 | if [ "$OS_IS_MACOS" == "1" ]; then 41 | export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java" 42 | export ARDUINO_USR_PATH="$HOME/Documents/Arduino" 43 | elif [ "$OS_IS_WINDOWS" == "1" ]; then 44 | export ARDUINO_IDE_PATH="$HOME/arduino_ide" 45 | export ARDUINO_USR_PATH="$HOME/Documents/Arduino" 46 | else 47 | export ARDUINO_IDE_PATH="$HOME/arduino_ide" 48 | export ARDUINO_USR_PATH="$HOME/Arduino" 49 | fi 50 | 51 | if [ ! -d "$ARDUINO_IDE_PATH" ]; then 52 | echo "Installing Arduino IDE on $OS_NAME ..." 53 | echo "Downloading 'arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..." 54 | if [ "$OS_IS_LINUX" == "1" ]; then 55 | wget -O "arduino.$ARCHIVE_FORMAT" "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1 56 | echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..." 57 | tar xf "arduino.$ARCHIVE_FORMAT" > /dev/null 58 | mv arduino-nightly "$ARDUINO_IDE_PATH" 59 | else 60 | curl -o "arduino.$ARCHIVE_FORMAT" -L "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1 61 | echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..." 62 | unzip "arduino.$ARCHIVE_FORMAT" > /dev/null 63 | if [ "$OS_IS_MACOS" == "1" ]; then 64 | mv "Arduino.app" "/Applications/Arduino.app" 65 | else 66 | mv arduino-nightly "$ARDUINO_IDE_PATH" 67 | fi 68 | fi 69 | rm -rf "arduino.$ARCHIVE_FORMAT" 70 | 71 | mkdir -p "$ARDUINO_USR_PATH/libraries" 72 | mkdir -p "$ARDUINO_USR_PATH/hardware" 73 | 74 | echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'" 75 | echo "" 76 | fi 77 | 78 | function build_sketch(){ # build_sketch [extra-options] 79 | if [ "$#" -lt 2 ]; then 80 | echo "ERROR: Illegal number of parameters" 81 | echo "USAGE: build_sketch [extra-options]" 82 | return 1 83 | fi 84 | 85 | local fqbn="$1" 86 | local sketch="$2" 87 | local build_flags="$3" 88 | local xtra_opts="$4" 89 | local win_opts="" 90 | if [ "$OS_IS_WINDOWS" == "1" ]; then 91 | local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"` 92 | local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"` 93 | win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version" 94 | fi 95 | 96 | echo "" 97 | echo "Compiling '"$(basename "$sketch")"' ..." 98 | mkdir -p "$ARDUINO_BUILD_DIR" 99 | mkdir -p "$ARDUINO_CACHE_DIR" 100 | $ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \ 101 | -fqbn=$fqbn \ 102 | -warnings="all" \ 103 | -tools "$ARDUINO_IDE_PATH/tools-builder" \ 104 | -tools "$ARDUINO_IDE_PATH/tools" \ 105 | -built-in-libraries "$ARDUINO_IDE_PATH/libraries" \ 106 | -hardware "$ARDUINO_IDE_PATH/hardware" \ 107 | -hardware "$ARDUINO_USR_PATH/hardware" \ 108 | -libraries "$ARDUINO_USR_PATH/libraries" \ 109 | -build-cache "$ARDUINO_CACHE_DIR" \ 110 | -build-path "$ARDUINO_BUILD_DIR" \ 111 | -prefs=compiler.cpp.extra_flags="$build_flags" \ 112 | $win_opts $xtra_opts "$sketch" 113 | } 114 | 115 | function count_sketches() # count_sketches 116 | { 117 | local examples="$1" 118 | rm -rf sketches.txt 119 | if [ ! -d "$examples" ]; then 120 | touch sketches.txt 121 | return 0 122 | fi 123 | local sketches=$(find $examples -name *.ino) 124 | local sketchnum=0 125 | for sketch in $sketches; do 126 | local sketchdir=$(dirname $sketch) 127 | local sketchdirname=$(basename $sketchdir) 128 | local sketchname=$(basename $sketch) 129 | if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then 130 | continue 131 | fi; 132 | if [[ -f "$sketchdir/.test.skip" ]]; then 133 | continue 134 | fi 135 | echo $sketch >> sketches.txt 136 | sketchnum=$(($sketchnum + 1)) 137 | done 138 | return $sketchnum 139 | } 140 | 141 | function build_sketches() # build_sketches [extra-options] 142 | { 143 | local fqbn=$1 144 | local examples=$2 145 | local chunk_idex=$3 146 | local chunks_num=$4 147 | local xtra_opts=$5 148 | 149 | if [ "$#" -lt 2 ]; then 150 | echo "ERROR: Illegal number of parameters" 151 | echo "USAGE: build_sketches [ ] [extra-options]" 152 | return 1 153 | fi 154 | 155 | if [ "$#" -lt 4 ]; then 156 | chunk_idex="0" 157 | chunks_num="1" 158 | xtra_opts=$3 159 | fi 160 | 161 | if [ "$chunks_num" -le 0 ]; then 162 | echo "ERROR: Chunks count must be positive number" 163 | return 1 164 | fi 165 | if [ "$chunk_idex" -ge "$chunks_num" ]; then 166 | echo "ERROR: Chunk index must be less than chunks count" 167 | return 1 168 | fi 169 | 170 | set +e 171 | count_sketches "$examples" 172 | local sketchcount=$? 173 | set -e 174 | local sketches=$(cat sketches.txt) 175 | rm -rf sketches.txt 176 | 177 | local chunk_size=$(( $sketchcount / $chunks_num )) 178 | local all_chunks=$(( $chunks_num * $chunk_size )) 179 | if [ "$all_chunks" -lt "$sketchcount" ]; then 180 | chunk_size=$(( $chunk_size + 1 )) 181 | fi 182 | 183 | local start_index=$(( $chunk_idex * $chunk_size )) 184 | if [ "$sketchcount" -le "$start_index" ]; then 185 | echo "Skipping job" 186 | return 0 187 | fi 188 | 189 | local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size )) 190 | if [ "$end_index" -gt "$sketchcount" ]; then 191 | end_index=$sketchcount 192 | fi 193 | 194 | local start_num=$(( $start_index + 1 )) 195 | echo "Found $sketchcount Sketches"; 196 | echo "Chunk Count : $chunks_num" 197 | echo "Chunk Size : $chunk_size" 198 | echo "Start Sketch: $start_num" 199 | echo "End Sketch : $end_index" 200 | 201 | local sketchnum=0 202 | for sketch in $sketches; do 203 | local sketchdir=$(dirname $sketch) 204 | local sketchdirname=$(basename $sketchdir) 205 | local sketchname=$(basename $sketch) 206 | if [ "${sketchdirname}.ino" != "$sketchname" ] \ 207 | || [ -f "$sketchdir/.test.skip" ]; then 208 | continue 209 | fi 210 | sketchnum=$(($sketchnum + 1)) 211 | if [ "$sketchnum" -le "$start_index" ] \ 212 | || [ "$sketchnum" -gt "$end_index" ]; then 213 | continue 214 | fi 215 | local sketchBuildFlags="" 216 | if [ -f "$sketchdir/.test.build_flags" ]; then 217 | while read line; do 218 | sketchBuildFlags="$sketchBuildFlags $line" 219 | done < "$sketchdir/.test.build_flags" 220 | fi 221 | build_sketch "$fqbn" "$sketch" "$sketchBuildFlags" "$xtra_opts" 222 | local result=$? 223 | if [ $result -ne 0 ]; then 224 | return $result 225 | fi 226 | done 227 | return 0 228 | } 229 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Installing Python Wheel ..." 4 | pip install wheel > /dev/null 2>&1 5 | 6 | echo "Installing PlatformIO ..." 7 | pip install -U platformio > /dev/null 2>&1 8 | 9 | echo "PlatformIO has been installed" 10 | echo "" 11 | 12 | 13 | function build_pio_sketch(){ # build_pio_sketch 14 | if [ "$#" -lt 3 ]; then 15 | echo "ERROR: Illegal number of parameters" 16 | echo "USAGE: build_pio_sketch " 17 | return 1 18 | fi 19 | 20 | local board="$1" 21 | local sketch="$2" 22 | local buildFlags="$3" 23 | local sketch_dir=$(dirname "$sketch") 24 | echo "" 25 | echo "Compiling '"$(basename "$sketch")"' ..." 26 | python -m platformio ci -l '.' --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv" --project-option="build_flags=$buildFlags" 27 | } 28 | 29 | function count_sketches() # count_sketches 30 | { 31 | local examples="$1" 32 | rm -rf sketches.txt 33 | if [ ! -d "$examples" ]; then 34 | touch sketches.txt 35 | return 0 36 | fi 37 | local sketches=$(find $examples -name *.ino) 38 | local sketchnum=0 39 | for sketch in $sketches; do 40 | local sketchdir=$(dirname $sketch) 41 | local sketchdirname=$(basename $sketchdir) 42 | local sketchname=$(basename $sketch) 43 | if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then 44 | continue 45 | fi; 46 | if [[ -f "$sketchdir/.test.skip" ]]; then 47 | continue 48 | fi 49 | echo $sketch >> sketches.txt 50 | sketchnum=$(($sketchnum + 1)) 51 | done 52 | return $sketchnum 53 | } 54 | 55 | function build_pio_sketches() # build_pio_sketches 56 | { 57 | if [ "$#" -lt 2 ]; then 58 | echo "ERROR: Illegal number of parameters" 59 | echo "USAGE: build_pio_sketches [ ]" 60 | return 1 61 | fi 62 | 63 | local board=$1 64 | local examples=$2 65 | local chunk_idex=$3 66 | local chunks_num=$4 67 | 68 | if [ "$#" -lt 4 ]; then 69 | chunk_idex="0" 70 | chunks_num="1" 71 | fi 72 | 73 | if [ "$chunks_num" -le 0 ]; then 74 | echo "ERROR: Chunks count must be positive number" 75 | return 1 76 | fi 77 | if [ "$chunk_idex" -ge "$chunks_num" ]; then 78 | echo "ERROR: Chunk index must be less than chunks count" 79 | return 1 80 | fi 81 | 82 | set +e 83 | count_sketches "$examples" 84 | local sketchcount=$? 85 | set -e 86 | local sketches=$(cat sketches.txt) 87 | rm -rf sketches.txt 88 | 89 | local chunk_size=$(( $sketchcount / $chunks_num )) 90 | local all_chunks=$(( $chunks_num * $chunk_size )) 91 | if [ "$all_chunks" -lt "$sketchcount" ]; then 92 | chunk_size=$(( $chunk_size + 1 )) 93 | fi 94 | 95 | local start_index=$(( $chunk_idex * $chunk_size )) 96 | if [ "$sketchcount" -le "$start_index" ]; then 97 | echo "Skipping job" 98 | return 0 99 | fi 100 | 101 | local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size )) 102 | if [ "$end_index" -gt "$sketchcount" ]; then 103 | end_index=$sketchcount 104 | fi 105 | 106 | local start_num=$(( $start_index + 1 )) 107 | echo "Found $sketchcount Sketches"; 108 | echo "Chunk Count : $chunks_num" 109 | echo "Chunk Size : $chunk_size" 110 | echo "Start Sketch: $start_num" 111 | echo "End Sketch : $end_index" 112 | 113 | local sketchnum=0 114 | for sketch in $sketches; do 115 | local sketchdir=$(dirname $sketch) 116 | local sketchdirname=$(basename $sketchdir) 117 | local sketchname=$(basename $sketch) 118 | if [ "${sketchdirname}.ino" != "$sketchname" ] \ 119 | || [ -f "$sketchdir/.test.skip" ]; then 120 | continue 121 | fi 122 | local sketchBuildFlags="" 123 | if [ -f "$sketchdir/.test.build_flags" ]; then 124 | while read line; do 125 | sketchBuildFlags="$sketchBuildFlags $line" 126 | done < "$sketchdir/.test.build_flags" 127 | fi 128 | sketchnum=$(($sketchnum + 1)) 129 | if [ "$sketchnum" -le "$start_index" ] \ 130 | || [ "$sketchnum" -gt "$end_index" ]; then 131 | continue 132 | fi 133 | build_pio_sketch "$board" "$sketch" "$sketchBuildFlags" 134 | local result=$? 135 | if [ $result -ne 0 ]; then 136 | return $result 137 | fi 138 | done 139 | return 0 140 | } 141 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/scripts/on-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ ! -z "$TRAVIS_BUILD_DIR" ]; then 6 | export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR" 7 | export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG" 8 | elif [ -z "$GITHUB_WORKSPACE" ]; then 9 | export GITHUB_WORKSPACE="$PWD" 10 | export GITHUB_REPOSITORY="me-no-dev/ESPAsyncWebServer" 11 | fi 12 | 13 | TARGET_PLATFORM="$1" 14 | CHUNK_INDEX=$2 15 | CHUNKS_CNT=$3 16 | BUILD_PIO=0 17 | if [ "$#" -lt 1 ]; then 18 | TARGET_PLATFORM="esp32" 19 | fi 20 | if [ "$#" -lt 3 ] || [ "$CHUNKS_CNT" -le 0 ]; then 21 | CHUNK_INDEX=0 22 | CHUNKS_CNT=1 23 | elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then 24 | CHUNK_INDEX=$CHUNKS_CNT 25 | elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then 26 | BUILD_PIO=1 27 | fi 28 | 29 | if [ "$BUILD_PIO" -eq 0 ]; then 30 | # ArduinoIDE Test 31 | source ./.github/scripts/install-arduino-ide.sh 32 | 33 | echo "Installing ESPAsyncWebServer ..." 34 | cp -rf "$GITHUB_WORKSPACE" "$ARDUINO_USR_PATH/libraries/ESPAsyncWebServer" 35 | echo "Installing ArduinoJson ..." 36 | git clone https://github.com/bblanchon/ArduinoJson "$ARDUINO_USR_PATH/libraries/ArduinoJson" > /dev/null 2>&1 37 | 38 | if [[ "$TARGET_PLATFORM" == "esp32" ]]; then 39 | echo "Installing AsyncTCP ..." 40 | git clone https://github.com/me-no-dev/AsyncTCP "$ARDUINO_USR_PATH/libraries/AsyncTCP" > /dev/null 2>&1 41 | FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" 42 | source ./.github/scripts/install-arduino-core-esp32.sh 43 | echo "BUILDING ESP32 EXAMPLES" 44 | else 45 | echo "Installing ESPAsyncTCP ..." 46 | git clone https://github.com/me-no-dev/ESPAsyncTCP "$ARDUINO_USR_PATH/libraries/ESPAsyncTCP" > /dev/null 2>&1 47 | FQBN="esp8266com:esp8266:generic:eesz=4M1M,ip=lm2f" 48 | source ./.github/scripts/install-arduino-core-esp8266.sh 49 | echo "BUILDING ESP8266 EXAMPLES" 50 | fi 51 | build_sketches "$FQBN" "$GITHUB_WORKSPACE/examples" "$CHUNK_INDEX" "$CHUNKS_CNT" 52 | else 53 | # PlatformIO Test 54 | source ./.github/scripts/install-platformio.sh 55 | 56 | python -m platformio lib --storage-dir "$GITHUB_WORKSPACE" install 57 | echo "Installing ArduinoJson ..." 58 | python -m platformio lib -g install https://github.com/bblanchon/ArduinoJson.git > /dev/null 2>&1 59 | if [[ "$TARGET_PLATFORM" == "esp32" ]]; then 60 | BOARD="esp32dev" 61 | echo "Installing AsyncTCP ..." 62 | python -m platformio lib -g install https://github.com/me-no-dev/AsyncTCP.git > /dev/null 2>&1 63 | echo "BUILDING ESP32 EXAMPLES" 64 | else 65 | BOARD="esp12e" 66 | echo "Installing ESPAsyncTCP ..." 67 | python -m platformio lib -g install https://github.com/me-no-dev/ESPAsyncTCP.git > /dev/null 2>&1 68 | echo "BUILDING ESP8266 EXAMPLES" 69 | fi 70 | build_pio_sketches "$BOARD" "$GITHUB_WORKSPACE/examples" 71 | fi 72 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | daysUntilStale: 60 4 | daysUntilClose: 14 5 | limitPerRun: 30 6 | staleLabel: stale 7 | exemptLabels: 8 | - pinned 9 | - security 10 | - "to be implemented" 11 | - "for reference" 12 | - "move to PR" 13 | - "enhancement" 14 | 15 | only: issues 16 | onlyLabels: [] 17 | exemptProjects: false 18 | exemptMilestones: false 19 | exemptAssignees: false 20 | 21 | markComment: > 22 | [STALE_SET] This issue has been automatically marked as stale because it has not had 23 | recent activity. It will be closed in 14 days if no further activity occurs. Thank you 24 | for your contributions. 25 | 26 | unmarkComment: > 27 | [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future. 28 | 29 | closeComment: > 30 | [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions. 31 | 32 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: ESP Async Web Server CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - release/* 8 | pull_request: 9 | 10 | jobs: 11 | 12 | build-arduino: 13 | name: Arduino for ${{ matrix.board }} on ${{ matrix.os }} 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, windows-latest, macOS-latest] 18 | board: [esp32, esp8266] 19 | steps: 20 | - uses: actions/checkout@v1 21 | - name: Build Tests 22 | run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 0 1 23 | 24 | build-pio: 25 | name: PlatformIO for ${{ matrix.board }} on ${{ matrix.os }} 26 | runs-on: ${{ matrix.os }} 27 | strategy: 28 | matrix: 29 | os: [ubuntu-latest, windows-latest, macOS-latest] 30 | board: [esp32, esp8266] 31 | steps: 32 | - uses: actions/checkout@v1 33 | - name: Build Tests 34 | run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 1 1 35 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | os: 6 | - linux 7 | 8 | git: 9 | depth: false 10 | 11 | stages: 12 | - build 13 | 14 | jobs: 15 | include: 16 | 17 | - name: "Build Arduino ESP32" 18 | if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) 19 | stage: build 20 | script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32 21 | 22 | - name: "Build Arduino ESP8266" 23 | if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) 24 | stage: build 25 | script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266 26 | 27 | - name: "Build Platformio ESP32" 28 | if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) 29 | stage: build 30 | script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32 1 1 31 | 32 | - name: "Build Platformio ESP8266" 33 | if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) 34 | stage: build 35 | script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266 1 1 36 | 37 | notifications: 38 | email: 39 | on_success: change 40 | on_failure: change 41 | webhooks: 42 | urls: 43 | - https://webhooks.gitter.im/e/60e65d0c78ea0a920347 44 | on_success: change # options: [always|never|change] default: always 45 | on_failure: always # options: [always|never|change] default: always 46 | on_start: never # options: [always|never|change] default: always 47 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCDIRS 2 | "src" 3 | ) 4 | 5 | set(COMPONENT_ADD_INCLUDEDIRS 6 | "src" 7 | ) 8 | 9 | set(COMPONENT_REQUIRES 10 | "arduino-esp32" 11 | "AsyncTCP" 12 | ) 13 | 14 | register_component() 15 | 16 | target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DESP32) 17 | target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti) 18 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS := src 2 | COMPONENT_SRCDIRS := src 3 | CXXFLAGS += -fno-rtti 4 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef ESP32 3 | #include 4 | #include 5 | #elif defined(ESP8266) 6 | #include 7 | #include 8 | #endif 9 | #include "ESPAsyncWebServer.h" 10 | 11 | DNSServer dnsServer; 12 | AsyncWebServer server(80); 13 | 14 | class CaptiveRequestHandler : public AsyncWebHandler { 15 | public: 16 | CaptiveRequestHandler() {} 17 | virtual ~CaptiveRequestHandler() {} 18 | 19 | bool canHandle(AsyncWebServerRequest *request){ 20 | //request->addInterestingHeader("ANY"); 21 | return true; 22 | } 23 | 24 | void handleRequest(AsyncWebServerRequest *request) { 25 | AsyncResponseStream *response = request->beginResponseStream("text/html"); 26 | response->print("Captive Portal"); 27 | response->print("

This is out captive portal front page.

"); 28 | response->printf("

You were trying to reach: http://%s%s

", request->host().c_str(), request->url().c_str()); 29 | response->printf("

Try opening this link instead

", WiFi.softAPIP().toString().c_str()); 30 | response->print(""); 31 | request->send(response); 32 | } 33 | }; 34 | 35 | 36 | void setup(){ 37 | //your other setup stuff... 38 | WiFi.softAP("esp-captive"); 39 | dnsServer.start(53, "*", WiFi.softAPIP()); 40 | server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP 41 | //more handlers... 42 | server.begin(); 43 | } 44 | 45 | void loop(){ 46 | dnsServer.processNextRequest(); 47 | } 48 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef ESP32 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #elif defined(ESP8266) 9 | #include 10 | #include 11 | #include 12 | #endif 13 | #include 14 | #include 15 | 16 | // SKETCH BEGIN 17 | AsyncWebServer server(80); 18 | AsyncWebSocket ws("/ws"); 19 | AsyncEventSource events("/events"); 20 | 21 | void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ 22 | if(type == WS_EVT_CONNECT){ 23 | Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); 24 | client->printf("Hello Client %u :)", client->id()); 25 | client->ping(); 26 | } else if(type == WS_EVT_DISCONNECT){ 27 | Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); 28 | } else if(type == WS_EVT_ERROR){ 29 | Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); 30 | } else if(type == WS_EVT_PONG){ 31 | Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); 32 | } else if(type == WS_EVT_DATA){ 33 | AwsFrameInfo * info = (AwsFrameInfo*)arg; 34 | String msg = ""; 35 | if(info->final && info->index == 0 && info->len == len){ 36 | //the whole message is in a single frame and we got all of it's data 37 | Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); 38 | 39 | if(info->opcode == WS_TEXT){ 40 | for(size_t i=0; i < info->len; i++) { 41 | msg += (char) data[i]; 42 | } 43 | } else { 44 | char buff[3]; 45 | for(size_t i=0; i < info->len; i++) { 46 | sprintf(buff, "%02x ", (uint8_t) data[i]); 47 | msg += buff ; 48 | } 49 | } 50 | Serial.printf("%s\n",msg.c_str()); 51 | 52 | if(info->opcode == WS_TEXT) 53 | client->text("I got your text message"); 54 | else 55 | client->binary("I got your binary message"); 56 | } else { 57 | //message is comprised of multiple frames or the frame is split into multiple packets 58 | if(info->index == 0){ 59 | if(info->num == 0) 60 | Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); 61 | Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); 62 | } 63 | 64 | Serial.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); 65 | 66 | if(info->opcode == WS_TEXT){ 67 | for(size_t i=0; i < len; i++) { 68 | msg += (char) data[i]; 69 | } 70 | } else { 71 | char buff[3]; 72 | for(size_t i=0; i < len; i++) { 73 | sprintf(buff, "%02x ", (uint8_t) data[i]); 74 | msg += buff ; 75 | } 76 | } 77 | Serial.printf("%s\n",msg.c_str()); 78 | 79 | if((info->index + len) == info->len){ 80 | Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); 81 | if(info->final){ 82 | Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); 83 | if(info->message_opcode == WS_TEXT) 84 | client->text("I got your text message"); 85 | else 86 | client->binary("I got your binary message"); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | 94 | const char* ssid = "*******"; 95 | const char* password = "*******"; 96 | const char * hostName = "esp-async"; 97 | const char* http_username = "admin"; 98 | const char* http_password = "admin"; 99 | 100 | void setup(){ 101 | Serial.begin(115200); 102 | Serial.setDebugOutput(true); 103 | WiFi.mode(WIFI_AP_STA); 104 | WiFi.softAP(hostName); 105 | WiFi.begin(ssid, password); 106 | if (WiFi.waitForConnectResult() != WL_CONNECTED) { 107 | Serial.printf("STA: Failed!\n"); 108 | WiFi.disconnect(false); 109 | delay(1000); 110 | WiFi.begin(ssid, password); 111 | } 112 | 113 | //Send OTA events to the browser 114 | ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); }); 115 | ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); }); 116 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 117 | char p[32]; 118 | sprintf(p, "Progress: %u%%\n", (progress/(total/100))); 119 | events.send(p, "ota"); 120 | }); 121 | ArduinoOTA.onError([](ota_error_t error) { 122 | if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota"); 123 | else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota"); 124 | else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota"); 125 | else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota"); 126 | else if(error == OTA_END_ERROR) events.send("End Failed", "ota"); 127 | }); 128 | ArduinoOTA.setHostname(hostName); 129 | ArduinoOTA.begin(); 130 | 131 | MDNS.addService("http","tcp",80); 132 | 133 | SPIFFS.begin(); 134 | 135 | ws.onEvent(onWsEvent); 136 | server.addHandler(&ws); 137 | 138 | events.onConnect([](AsyncEventSourceClient *client){ 139 | client->send("hello!",NULL,millis(),1000); 140 | }); 141 | server.addHandler(&events); 142 | 143 | #ifdef ESP32 144 | server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password)); 145 | #elif defined(ESP8266) 146 | server.addHandler(new SPIFFSEditor(http_username,http_password)); 147 | #endif 148 | 149 | server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ 150 | request->send(200, "text/plain", String(ESP.getFreeHeap())); 151 | }); 152 | 153 | server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); 154 | 155 | server.onNotFound([](AsyncWebServerRequest *request){ 156 | Serial.printf("NOT_FOUND: "); 157 | if(request->method() == HTTP_GET) 158 | Serial.printf("GET"); 159 | else if(request->method() == HTTP_POST) 160 | Serial.printf("POST"); 161 | else if(request->method() == HTTP_DELETE) 162 | Serial.printf("DELETE"); 163 | else if(request->method() == HTTP_PUT) 164 | Serial.printf("PUT"); 165 | else if(request->method() == HTTP_PATCH) 166 | Serial.printf("PATCH"); 167 | else if(request->method() == HTTP_HEAD) 168 | Serial.printf("HEAD"); 169 | else if(request->method() == HTTP_OPTIONS) 170 | Serial.printf("OPTIONS"); 171 | else 172 | Serial.printf("UNKNOWN"); 173 | Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); 174 | 175 | if(request->contentLength()){ 176 | Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); 177 | Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); 178 | } 179 | 180 | int headers = request->headers(); 181 | int i; 182 | for(i=0;igetHeader(i); 184 | Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); 185 | } 186 | 187 | int params = request->params(); 188 | for(i=0;igetParam(i); 190 | if(p->isFile()){ 191 | Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); 192 | } else if(p->isPost()){ 193 | Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); 194 | } else { 195 | Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); 196 | } 197 | } 198 | 199 | request->send(404); 200 | }); 201 | server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ 202 | if(!index) 203 | Serial.printf("UploadStart: %s\n", filename.c_str()); 204 | Serial.printf("%s", (const char*)data); 205 | if(final) 206 | Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len); 207 | }); 208 | server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ 209 | if(!index) 210 | Serial.printf("BodyStart: %u\n", total); 211 | Serial.printf("%s", (const char*)data); 212 | if(index + len == total) 213 | Serial.printf("BodyEnd: %u\n", total); 214 | }); 215 | server.begin(); 216 | } 217 | 218 | void loop(){ 219 | ArduinoOTA.handle(); 220 | ws.cleanupClients(); 221 | } 222 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/.exclude.files: -------------------------------------------------------------------------------- 1 | /*.js.gz 2 | /.exclude.files 3 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/favicon.ico -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | WebSocketTester 23 | 52 | 124 | 125 | 126 |

127 |     
128 | $ 129 |
130 | 131 | 132 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkmakes/SMARS-esp32/e7a23a218aa2840e07955547e62a6f3654568508/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/regex_patterns/.test.build_flags: -------------------------------------------------------------------------------- 1 | -DASYNCWEBSERVER_REGEX=1 2 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino: -------------------------------------------------------------------------------- 1 | // 2 | // A simple server implementation with regex routes: 3 | // * serve static messages 4 | // * read GET and POST parameters 5 | // * handle missing pages / 404s 6 | // 7 | 8 | // Add buildflag ASYNCWEBSERVER_REGEX to enable the regex support 9 | 10 | // For platformio: platformio.ini: 11 | // build_flags = 12 | // -DASYNCWEBSERVER_REGEX 13 | 14 | // For arduino IDE: create/update platform.local.txt 15 | // Windows: C:\Users\(username)\AppData\Local\Arduino15\packages\espxxxx\hardware\espxxxx\{version}\platform.local.txt 16 | // Linux: ~/.arduino15/packages/espxxxx/hardware/espxxxx/{version}/platform.local.txt 17 | // 18 | // compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 19 | 20 | #include 21 | #ifdef ESP32 22 | #include 23 | #include 24 | #elif defined(ESP8266) 25 | #include 26 | #include 27 | #endif 28 | #include 29 | 30 | AsyncWebServer server(80); 31 | 32 | const char* ssid = "YOUR_SSID"; 33 | const char* password = "YOUR_PASSWORD"; 34 | 35 | const char* PARAM_MESSAGE = "message"; 36 | 37 | void notFound(AsyncWebServerRequest *request) { 38 | request->send(404, "text/plain", "Not found"); 39 | } 40 | 41 | void setup() { 42 | 43 | Serial.begin(115200); 44 | WiFi.mode(WIFI_STA); 45 | WiFi.begin(ssid, password); 46 | if (WiFi.waitForConnectResult() != WL_CONNECTED) { 47 | Serial.printf("WiFi Failed!\n"); 48 | return; 49 | } 50 | 51 | Serial.print("IP Address: "); 52 | Serial.println(WiFi.localIP()); 53 | 54 | server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ 55 | request->send(200, "text/plain", "Hello, world"); 56 | }); 57 | 58 | // Send a GET request to /sensor/ 59 | server.on("^\\/sensor\\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { 60 | String sensorNumber = request->pathArg(0); 61 | request->send(200, "text/plain", "Hello, sensor: " + sensorNumber); 62 | }); 63 | 64 | // Send a GET request to /sensor//action/ 65 | server.on("^\\/sensor\\/([0-9]+)\\/action\\/([a-zA-Z0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { 66 | String sensorNumber = request->pathArg(0); 67 | String action = request->pathArg(1); 68 | request->send(200, "text/plain", "Hello, sensor: " + sensorNumber + ", with action: " + action); 69 | }); 70 | 71 | server.onNotFound(notFound); 72 | 73 | server.begin(); 74 | } 75 | 76 | void loop() { 77 | } 78 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/examples/simple_server/simple_server.ino: -------------------------------------------------------------------------------- 1 | // 2 | // A simple server implementation showing how to: 3 | // * serve static messages 4 | // * read GET and POST parameters 5 | // * handle missing pages / 404s 6 | // 7 | 8 | #include 9 | #ifdef ESP32 10 | #include 11 | #include 12 | #elif defined(ESP8266) 13 | #include 14 | #include 15 | #endif 16 | #include 17 | 18 | AsyncWebServer server(80); 19 | 20 | const char* ssid = "YOUR_SSID"; 21 | const char* password = "YOUR_PASSWORD"; 22 | 23 | const char* PARAM_MESSAGE = "message"; 24 | 25 | void notFound(AsyncWebServerRequest *request) { 26 | request->send(404, "text/plain", "Not found"); 27 | } 28 | 29 | void setup() { 30 | 31 | Serial.begin(115200); 32 | WiFi.mode(WIFI_STA); 33 | WiFi.begin(ssid, password); 34 | if (WiFi.waitForConnectResult() != WL_CONNECTED) { 35 | Serial.printf("WiFi Failed!\n"); 36 | return; 37 | } 38 | 39 | Serial.print("IP Address: "); 40 | Serial.println(WiFi.localIP()); 41 | 42 | server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ 43 | request->send(200, "text/plain", "Hello, world"); 44 | }); 45 | 46 | // Send a GET request to /get?message= 47 | server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) { 48 | String message; 49 | if (request->hasParam(PARAM_MESSAGE)) { 50 | message = request->getParam(PARAM_MESSAGE)->value(); 51 | } else { 52 | message = "No message sent"; 53 | } 54 | request->send(200, "text/plain", "Hello, GET: " + message); 55 | }); 56 | 57 | // Send a POST request to /post with a form field message set to 58 | server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){ 59 | String message; 60 | if (request->hasParam(PARAM_MESSAGE, true)) { 61 | message = request->getParam(PARAM_MESSAGE, true)->value(); 62 | } else { 63 | message = "No message sent"; 64 | } 65 | request->send(200, "text/plain", "Hello, POST: " + message); 66 | }); 67 | 68 | server.onNotFound(notFound); 69 | 70 | server.begin(); 71 | } 72 | 73 | void loop() { 74 | } -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/keywords.txt: -------------------------------------------------------------------------------- 1 | JsonArray KEYWORD1 2 | add KEYWORD2 3 | createArray KEYWORD3 4 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"ESP Async WebServer", 3 | "description":"Asynchronous HTTP and WebSocket Server Library for ESP8266 and ESP32", 4 | "keywords":"http,async,websocket,webserver", 5 | "authors": 6 | { 7 | "name": "Hristo Gochkov", 8 | "maintainer": true 9 | }, 10 | "repository": 11 | { 12 | "type": "git", 13 | "url": "https://github.com/me-no-dev/ESPAsyncWebServer.git" 14 | }, 15 | "version": "1.2.3", 16 | "license": "LGPL-3.0", 17 | "frameworks": "arduino", 18 | "platforms": ["espressif8266", "espressif32"], 19 | "dependencies": [ 20 | { 21 | "name": "ESPAsyncTCP", 22 | "platforms": "espressif8266" 23 | }, 24 | { 25 | "name": "AsyncTCP", 26 | "platforms": "espressif32" 27 | }, 28 | { 29 | "name": "Hash", 30 | "platforms": "espressif8266" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/library.properties: -------------------------------------------------------------------------------- 1 | name=ESP Async WebServer 2 | version=1.2.3 3 | author=Me-No-Dev 4 | maintainer=Me-No-Dev 5 | sentence=Async Web Server for ESP8266 and ESP31B 6 | paragraph=Async Web Server for ESP8266 and ESP31B 7 | category=Other 8 | url=https://github.com/me-no-dev/ESPAsyncWebServer 9 | architectures=* 10 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/AsyncEventSource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | #include "Arduino.h" 21 | #include "AsyncEventSource.h" 22 | 23 | static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){ 24 | String ev = ""; 25 | 26 | if(reconnect){ 27 | ev += "retry: "; 28 | ev += String(reconnect); 29 | ev += "\r\n"; 30 | } 31 | 32 | if(id){ 33 | ev += "id: "; 34 | ev += String(id); 35 | ev += "\r\n"; 36 | } 37 | 38 | if(event != NULL){ 39 | ev += "event: "; 40 | ev += String(event); 41 | ev += "\r\n"; 42 | } 43 | 44 | if(message != NULL){ 45 | size_t messageLen = strlen(message); 46 | char * lineStart = (char *)message; 47 | char * lineEnd; 48 | do { 49 | char * nextN = strchr(lineStart, '\n'); 50 | char * nextR = strchr(lineStart, '\r'); 51 | if(nextN == NULL && nextR == NULL){ 52 | size_t llen = ((char *)message + messageLen) - lineStart; 53 | char * ldata = (char *)malloc(llen+1); 54 | if(ldata != NULL){ 55 | memcpy(ldata, lineStart, llen); 56 | ldata[llen] = 0; 57 | ev += "data: "; 58 | ev += ldata; 59 | ev += "\r\n\r\n"; 60 | free(ldata); 61 | } 62 | lineStart = (char *)message + messageLen; 63 | } else { 64 | char * nextLine = NULL; 65 | if(nextN != NULL && nextR != NULL){ 66 | if(nextR < nextN){ 67 | lineEnd = nextR; 68 | if(nextN == (nextR + 1)) 69 | nextLine = nextN + 1; 70 | else 71 | nextLine = nextR + 1; 72 | } else { 73 | lineEnd = nextN; 74 | if(nextR == (nextN + 1)) 75 | nextLine = nextR + 1; 76 | else 77 | nextLine = nextN + 1; 78 | } 79 | } else if(nextN != NULL){ 80 | lineEnd = nextN; 81 | nextLine = nextN + 1; 82 | } else { 83 | lineEnd = nextR; 84 | nextLine = nextR + 1; 85 | } 86 | 87 | size_t llen = lineEnd - lineStart; 88 | char * ldata = (char *)malloc(llen+1); 89 | if(ldata != NULL){ 90 | memcpy(ldata, lineStart, llen); 91 | ldata[llen] = 0; 92 | ev += "data: "; 93 | ev += ldata; 94 | ev += "\r\n"; 95 | free(ldata); 96 | } 97 | lineStart = nextLine; 98 | if(lineStart == ((char *)message + messageLen)) 99 | ev += "\r\n"; 100 | } 101 | } while(lineStart < ((char *)message + messageLen)); 102 | } 103 | 104 | return ev; 105 | } 106 | 107 | // Message 108 | 109 | AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len) 110 | : _data(nullptr), _len(len), _sent(0), _acked(0) 111 | { 112 | _data = (uint8_t*)malloc(_len+1); 113 | if(_data == nullptr){ 114 | _len = 0; 115 | } else { 116 | memcpy(_data, data, len); 117 | _data[_len] = 0; 118 | } 119 | } 120 | 121 | AsyncEventSourceMessage::~AsyncEventSourceMessage() { 122 | if(_data != NULL) 123 | free(_data); 124 | } 125 | 126 | size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) { 127 | (void)time; 128 | // If the whole message is now acked... 129 | if(_acked + len > _len){ 130 | // Return the number of extra bytes acked (they will be carried on to the next message) 131 | const size_t extra = _acked + len - _len; 132 | _acked = _len; 133 | return extra; 134 | } 135 | // Return that no extra bytes left. 136 | _acked += len; 137 | return 0; 138 | } 139 | 140 | size_t AsyncEventSourceMessage::send(AsyncClient *client) { 141 | const size_t len = _len - _sent; 142 | if(client->space() < len){ 143 | return 0; 144 | } 145 | size_t sent = client->add((const char *)_data, len); 146 | if(client->canSend()) 147 | client->send(); 148 | _sent += sent; 149 | return sent; 150 | } 151 | 152 | // Client 153 | 154 | AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server) 155 | : _messageQueue(LinkedList([](AsyncEventSourceMessage *m){ delete m; })) 156 | { 157 | _client = request->client(); 158 | _server = server; 159 | _lastId = 0; 160 | if(request->hasHeader("Last-Event-ID")) 161 | _lastId = atoi(request->getHeader("Last-Event-ID")->value().c_str()); 162 | 163 | _client->setRxTimeout(0); 164 | _client->onError(NULL, NULL); 165 | _client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this); 166 | _client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this); 167 | _client->onData(NULL, NULL); 168 | _client->onTimeout([this](void *r, AsyncClient* c __attribute__((unused)), uint32_t time){ ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this); 169 | _client->onDisconnect([this](void *r, AsyncClient* c){ ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this); 170 | 171 | _server->_addClient(this); 172 | delete request; 173 | } 174 | 175 | AsyncEventSourceClient::~AsyncEventSourceClient(){ 176 | _messageQueue.free(); 177 | close(); 178 | } 179 | 180 | void AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage *dataMessage){ 181 | if(dataMessage == NULL) 182 | return; 183 | if(!connected()){ 184 | delete dataMessage; 185 | return; 186 | } 187 | if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){ 188 | ets_printf("ERROR: Too many messages queued\n"); 189 | delete dataMessage; 190 | } else { 191 | _messageQueue.add(dataMessage); 192 | } 193 | if(_client->canSend()) 194 | _runQueue(); 195 | } 196 | 197 | void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){ 198 | while(len && !_messageQueue.isEmpty()){ 199 | len = _messageQueue.front()->ack(len, time); 200 | if(_messageQueue.front()->finished()) 201 | _messageQueue.remove(_messageQueue.front()); 202 | } 203 | 204 | _runQueue(); 205 | } 206 | 207 | void AsyncEventSourceClient::_onPoll(){ 208 | if(!_messageQueue.isEmpty()){ 209 | _runQueue(); 210 | } 211 | } 212 | 213 | 214 | void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){ 215 | _client->close(true); 216 | } 217 | 218 | void AsyncEventSourceClient::_onDisconnect(){ 219 | _client = NULL; 220 | _server->_handleDisconnect(this); 221 | } 222 | 223 | void AsyncEventSourceClient::close(){ 224 | if(_client != NULL) 225 | _client->close(); 226 | } 227 | 228 | void AsyncEventSourceClient::write(const char * message, size_t len){ 229 | _queueMessage(new AsyncEventSourceMessage(message, len)); 230 | } 231 | 232 | void AsyncEventSourceClient::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){ 233 | String ev = generateEventMessage(message, event, id, reconnect); 234 | _queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length())); 235 | } 236 | 237 | void AsyncEventSourceClient::_runQueue(){ 238 | while(!_messageQueue.isEmpty() && _messageQueue.front()->finished()){ 239 | _messageQueue.remove(_messageQueue.front()); 240 | } 241 | 242 | for(auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) 243 | { 244 | if(!(*i)->sent()) 245 | (*i)->send(_client); 246 | } 247 | } 248 | 249 | 250 | // Handler 251 | 252 | AsyncEventSource::AsyncEventSource(const String& url) 253 | : _url(url) 254 | , _clients(LinkedList([](AsyncEventSourceClient *c){ delete c; })) 255 | , _connectcb(NULL) 256 | {} 257 | 258 | AsyncEventSource::~AsyncEventSource(){ 259 | close(); 260 | } 261 | 262 | void AsyncEventSource::onConnect(ArEventHandlerFunction cb){ 263 | _connectcb = cb; 264 | } 265 | 266 | void AsyncEventSource::_addClient(AsyncEventSourceClient * client){ 267 | /*char * temp = (char *)malloc(2054); 268 | if(temp != NULL){ 269 | memset(temp+1,' ',2048); 270 | temp[0] = ':'; 271 | temp[2049] = '\r'; 272 | temp[2050] = '\n'; 273 | temp[2051] = '\r'; 274 | temp[2052] = '\n'; 275 | temp[2053] = 0; 276 | client->write((const char *)temp, 2053); 277 | free(temp); 278 | }*/ 279 | 280 | _clients.add(client); 281 | if(_connectcb) 282 | _connectcb(client); 283 | } 284 | 285 | void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){ 286 | _clients.remove(client); 287 | } 288 | 289 | void AsyncEventSource::close(){ 290 | for(const auto &c: _clients){ 291 | if(c->connected()) 292 | c->close(); 293 | } 294 | } 295 | 296 | // pmb fix 297 | size_t AsyncEventSource::avgPacketsWaiting() const { 298 | if(_clients.isEmpty()) 299 | return 0; 300 | 301 | size_t aql=0; 302 | uint32_t nConnectedClients=0; 303 | 304 | for(const auto &c: _clients){ 305 | if(c->connected()) { 306 | aql+=c->packetsWaiting(); 307 | ++nConnectedClients; 308 | } 309 | } 310 | // return aql / nConnectedClients; 311 | return ((aql) + (nConnectedClients/2))/(nConnectedClients); // round up 312 | } 313 | 314 | void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){ 315 | 316 | 317 | String ev = generateEventMessage(message, event, id, reconnect); 318 | for(const auto &c: _clients){ 319 | if(c->connected()) { 320 | c->write(ev.c_str(), ev.length()); 321 | } 322 | } 323 | } 324 | 325 | size_t AsyncEventSource::count() const { 326 | return _clients.count_if([](AsyncEventSourceClient *c){ 327 | return c->connected(); 328 | }); 329 | } 330 | 331 | bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){ 332 | if(request->method() != HTTP_GET || !request->url().equals(_url)) { 333 | return false; 334 | } 335 | request->addInterestingHeader("Last-Event-ID"); 336 | return true; 337 | } 338 | 339 | void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){ 340 | if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) 341 | return request->requestAuthentication(); 342 | request->send(new AsyncEventSourceResponse(this)); 343 | } 344 | 345 | // Response 346 | 347 | AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){ 348 | _server = server; 349 | _code = 200; 350 | _contentType = "text/event-stream"; 351 | _sendContentLength = false; 352 | addHeader("Cache-Control", "no-cache"); 353 | addHeader("Connection","keep-alive"); 354 | } 355 | 356 | void AsyncEventSourceResponse::_respond(AsyncWebServerRequest *request){ 357 | String out = _assembleHead(request->version()); 358 | request->client()->write(out.c_str(), _headLength); 359 | _state = RESPONSE_WAIT_ACK; 360 | } 361 | 362 | size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time __attribute__((unused))){ 363 | if(len){ 364 | new AsyncEventSourceClient(request, _server); 365 | } 366 | return 0; 367 | } 368 | 369 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/AsyncEventSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | #ifndef ASYNCEVENTSOURCE_H_ 21 | #define ASYNCEVENTSOURCE_H_ 22 | 23 | #include 24 | #ifdef ESP32 25 | #include 26 | #define SSE_MAX_QUEUED_MESSAGES 32 27 | #else 28 | #include 29 | #define SSE_MAX_QUEUED_MESSAGES 8 30 | #endif 31 | #include 32 | 33 | #include "AsyncWebSynchronization.h" 34 | 35 | #ifdef ESP8266 36 | #include 37 | #ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library 38 | #include <../src/Hash.h> 39 | #endif 40 | #endif 41 | 42 | #ifdef ESP32 43 | #define DEFAULT_MAX_SSE_CLIENTS 8 44 | #else 45 | #define DEFAULT_MAX_SSE_CLIENTS 4 46 | #endif 47 | 48 | class AsyncEventSource; 49 | class AsyncEventSourceResponse; 50 | class AsyncEventSourceClient; 51 | typedef std::function ArEventHandlerFunction; 52 | 53 | class AsyncEventSourceMessage { 54 | private: 55 | uint8_t * _data; 56 | size_t _len; 57 | size_t _sent; 58 | //size_t _ack; 59 | size_t _acked; 60 | public: 61 | AsyncEventSourceMessage(const char * data, size_t len); 62 | ~AsyncEventSourceMessage(); 63 | size_t ack(size_t len, uint32_t time __attribute__((unused))); 64 | size_t send(AsyncClient *client); 65 | bool finished(){ return _acked == _len; } 66 | bool sent() { return _sent == _len; } 67 | }; 68 | 69 | class AsyncEventSourceClient { 70 | private: 71 | AsyncClient *_client; 72 | AsyncEventSource *_server; 73 | uint32_t _lastId; 74 | LinkedList _messageQueue; 75 | void _queueMessage(AsyncEventSourceMessage *dataMessage); 76 | void _runQueue(); 77 | 78 | public: 79 | 80 | AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server); 81 | ~AsyncEventSourceClient(); 82 | 83 | AsyncClient* client(){ return _client; } 84 | void close(); 85 | void write(const char * message, size_t len); 86 | void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); 87 | bool connected() const { return (_client != NULL) && _client->connected(); } 88 | uint32_t lastId() const { return _lastId; } 89 | size_t packetsWaiting() const { return _messageQueue.length(); } 90 | 91 | //system callbacks (do not call) 92 | void _onAck(size_t len, uint32_t time); 93 | void _onPoll(); 94 | void _onTimeout(uint32_t time); 95 | void _onDisconnect(); 96 | }; 97 | 98 | class AsyncEventSource: public AsyncWebHandler { 99 | private: 100 | String _url; 101 | LinkedList _clients; 102 | ArEventHandlerFunction _connectcb; 103 | public: 104 | AsyncEventSource(const String& url); 105 | ~AsyncEventSource(); 106 | 107 | const char * url() const { return _url.c_str(); } 108 | void close(); 109 | void onConnect(ArEventHandlerFunction cb); 110 | void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); 111 | size_t count() const; //number clinets connected 112 | size_t avgPacketsWaiting() const; 113 | 114 | //system callbacks (do not call) 115 | void _addClient(AsyncEventSourceClient * client); 116 | void _handleDisconnect(AsyncEventSourceClient * client); 117 | virtual bool canHandle(AsyncWebServerRequest *request) override final; 118 | virtual void handleRequest(AsyncWebServerRequest *request) override final; 119 | }; 120 | 121 | class AsyncEventSourceResponse: public AsyncWebServerResponse { 122 | private: 123 | String _content; 124 | AsyncEventSource *_server; 125 | public: 126 | AsyncEventSourceResponse(AsyncEventSource *server); 127 | void _respond(AsyncWebServerRequest *request); 128 | size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); 129 | bool _sourceValid() const { return true; } 130 | }; 131 | 132 | 133 | #endif /* ASYNCEVENTSOURCE_H_ */ 134 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/AsyncJson.h: -------------------------------------------------------------------------------- 1 | // AsyncJson.h 2 | /* 3 | Async Response to use with ArduinoJson and AsyncWebServer 4 | Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon. 5 | 6 | Example of callback in use 7 | 8 | server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) { 9 | 10 | AsyncJsonResponse * response = new AsyncJsonResponse(); 11 | JsonObject& root = response->getRoot(); 12 | root["key1"] = "key number one"; 13 | JsonObject& nested = root.createNestedObject("nested"); 14 | nested["key1"] = "key number one"; 15 | 16 | response->setLength(); 17 | request->send(response); 18 | }); 19 | 20 | -------------------- 21 | 22 | Async Request to use with ArduinoJson and AsyncWebServer 23 | Written by Arsène von Wyss (avonwyss) 24 | 25 | Example 26 | 27 | AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint"); 28 | handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) { 29 | JsonObject& jsonObj = json.as(); 30 | // ... 31 | }); 32 | server.addHandler(handler); 33 | 34 | */ 35 | #ifndef ASYNC_JSON_H_ 36 | #define ASYNC_JSON_H_ 37 | #include 38 | #include 39 | #include 40 | 41 | #if ARDUINOJSON_VERSION_MAJOR == 5 42 | #define ARDUINOJSON_5_COMPATIBILITY 43 | #else 44 | #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 45 | #endif 46 | 47 | constexpr const char* JSON_MIMETYPE = "application/json"; 48 | 49 | /* 50 | * Json Response 51 | * */ 52 | 53 | class ChunkPrint : public Print { 54 | private: 55 | uint8_t* _destination; 56 | size_t _to_skip; 57 | size_t _to_write; 58 | size_t _pos; 59 | public: 60 | ChunkPrint(uint8_t* destination, size_t from, size_t len) 61 | : _destination(destination), _to_skip(from), _to_write(len), _pos{0} {} 62 | virtual ~ChunkPrint(){} 63 | size_t write(uint8_t c){ 64 | if (_to_skip > 0) { 65 | _to_skip--; 66 | return 1; 67 | } else if (_to_write > 0) { 68 | _to_write--; 69 | _destination[_pos++] = c; 70 | return 1; 71 | } 72 | return 0; 73 | } 74 | size_t write(const uint8_t *buffer, size_t size) 75 | { 76 | return this->Print::write(buffer, size); 77 | } 78 | }; 79 | 80 | class AsyncJsonResponse: public AsyncAbstractResponse { 81 | protected: 82 | 83 | #ifdef ARDUINOJSON_5_COMPATIBILITY 84 | DynamicJsonBuffer _jsonBuffer; 85 | #else 86 | DynamicJsonDocument _jsonBuffer; 87 | #endif 88 | 89 | JsonVariant _root; 90 | bool _isValid; 91 | 92 | public: 93 | 94 | #ifdef ARDUINOJSON_5_COMPATIBILITY 95 | AsyncJsonResponse(bool isArray=false): _isValid{false} { 96 | _code = 200; 97 | _contentType = JSON_MIMETYPE; 98 | if(isArray) 99 | _root = _jsonBuffer.createArray(); 100 | else 101 | _root = _jsonBuffer.createObject(); 102 | } 103 | #else 104 | AsyncJsonResponse(bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : _jsonBuffer(maxJsonBufferSize), _isValid{false} { 105 | _code = 200; 106 | _contentType = JSON_MIMETYPE; 107 | if(isArray) 108 | _root = _jsonBuffer.createNestedArray(); 109 | else 110 | _root = _jsonBuffer.createNestedObject(); 111 | } 112 | #endif 113 | 114 | ~AsyncJsonResponse() {} 115 | JsonVariant & getRoot() { return _root; } 116 | bool _sourceValid() const { return _isValid; } 117 | size_t setLength() { 118 | 119 | #ifdef ARDUINOJSON_5_COMPATIBILITY 120 | _contentLength = _root.measureLength(); 121 | #else 122 | _contentLength = measureJson(_root); 123 | #endif 124 | 125 | if (_contentLength) { _isValid = true; } 126 | return _contentLength; 127 | } 128 | 129 | size_t getSize() { return _jsonBuffer.size(); } 130 | 131 | size_t _fillBuffer(uint8_t *data, size_t len){ 132 | ChunkPrint dest(data, _sentLength, len); 133 | 134 | #ifdef ARDUINOJSON_5_COMPATIBILITY 135 | _root.printTo( dest ) ; 136 | #else 137 | serializeJson(_root, dest); 138 | #endif 139 | return len; 140 | } 141 | }; 142 | 143 | class PrettyAsyncJsonResponse: public AsyncJsonResponse { 144 | public: 145 | #ifdef ARDUINOJSON_5_COMPATIBILITY 146 | PrettyAsyncJsonResponse (bool isArray=false) : AsyncJsonResponse{isArray} {} 147 | #else 148 | PrettyAsyncJsonResponse (bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : AsyncJsonResponse{isArray, maxJsonBufferSize} {} 149 | #endif 150 | size_t setLength () { 151 | #ifdef ARDUINOJSON_5_COMPATIBILITY 152 | _contentLength = _root.measurePrettyLength (); 153 | #else 154 | _contentLength = measureJsonPretty(_root); 155 | #endif 156 | if (_contentLength) {_isValid = true;} 157 | return _contentLength; 158 | } 159 | size_t _fillBuffer (uint8_t *data, size_t len) { 160 | ChunkPrint dest (data, _sentLength, len); 161 | #ifdef ARDUINOJSON_5_COMPATIBILITY 162 | _root.prettyPrintTo (dest); 163 | #else 164 | serializeJsonPretty(_root, dest); 165 | #endif 166 | return len; 167 | } 168 | }; 169 | 170 | typedef std::function ArJsonRequestHandlerFunction; 171 | 172 | class AsyncCallbackJsonWebHandler: public AsyncWebHandler { 173 | private: 174 | protected: 175 | const String _uri; 176 | WebRequestMethodComposite _method; 177 | ArJsonRequestHandlerFunction _onRequest; 178 | size_t _contentLength; 179 | #ifndef ARDUINOJSON_5_COMPATIBILITY 180 | const size_t maxJsonBufferSize; 181 | #endif 182 | size_t _maxContentLength; 183 | public: 184 | #ifdef ARDUINOJSON_5_COMPATIBILITY 185 | AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) 186 | : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {} 187 | #else 188 | AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMIC_JSON_DOCUMENT_SIZE) 189 | : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {} 190 | #endif 191 | 192 | void setMethod(WebRequestMethodComposite method){ _method = method; } 193 | void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; } 194 | void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; } 195 | 196 | virtual bool canHandle(AsyncWebServerRequest *request) override final{ 197 | if(!_onRequest) 198 | return false; 199 | 200 | if(!(_method & request->method())) 201 | return false; 202 | 203 | if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) 204 | return false; 205 | 206 | if ( !request->contentType().equalsIgnoreCase(JSON_MIMETYPE) ) 207 | return false; 208 | 209 | request->addInterestingHeader("ANY"); 210 | return true; 211 | } 212 | 213 | virtual void handleRequest(AsyncWebServerRequest *request) override final { 214 | if(_onRequest) { 215 | if (request->_tempObject != NULL) { 216 | 217 | #ifdef ARDUINOJSON_5_COMPATIBILITY 218 | DynamicJsonBuffer jsonBuffer; 219 | JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject)); 220 | if (json.success()) { 221 | #else 222 | DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize); 223 | DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject)); 224 | if(!error) { 225 | JsonVariant json = jsonBuffer.as(); 226 | #endif 227 | 228 | _onRequest(request, json); 229 | return; 230 | } 231 | } 232 | request->send(_contentLength > _maxContentLength ? 413 : 400); 233 | } else { 234 | request->send(500); 235 | } 236 | } 237 | virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { 238 | } 239 | virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { 240 | if (_onRequest) { 241 | _contentLength = total; 242 | if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) { 243 | request->_tempObject = malloc(total); 244 | } 245 | if (request->_tempObject != NULL) { 246 | memcpy((uint8_t*)(request->_tempObject) + index, data, len); 247 | } 248 | } 249 | } 250 | virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} 251 | }; 252 | #endif 253 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/AsyncWebSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef ASYNCWEBSOCKET_H_ 22 | #define ASYNCWEBSOCKET_H_ 23 | 24 | #include 25 | #ifdef ESP32 26 | #include 27 | #define WS_MAX_QUEUED_MESSAGES 32 28 | #else 29 | #include 30 | #define WS_MAX_QUEUED_MESSAGES 8 31 | #endif 32 | #include 33 | 34 | #include "AsyncWebSynchronization.h" 35 | 36 | #ifdef ESP8266 37 | #include 38 | #ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library 39 | #include <../src/Hash.h> 40 | #endif 41 | #endif 42 | 43 | #ifdef ESP32 44 | #define DEFAULT_MAX_WS_CLIENTS 8 45 | #else 46 | #define DEFAULT_MAX_WS_CLIENTS 4 47 | #endif 48 | 49 | class AsyncWebSocket; 50 | class AsyncWebSocketResponse; 51 | class AsyncWebSocketClient; 52 | class AsyncWebSocketControl; 53 | 54 | typedef struct { 55 | /** Message type as defined by enum AwsFrameType. 56 | * Note: Applications will only see WS_TEXT and WS_BINARY. 57 | * All other types are handled by the library. */ 58 | uint8_t message_opcode; 59 | /** Frame number of a fragmented message. */ 60 | uint32_t num; 61 | /** Is this the last frame in a fragmented message ?*/ 62 | uint8_t final; 63 | /** Is this frame masked? */ 64 | uint8_t masked; 65 | /** Message type as defined by enum AwsFrameType. 66 | * This value is the same as message_opcode for non-fragmented 67 | * messages, but may also be WS_CONTINUATION in a fragmented message. */ 68 | uint8_t opcode; 69 | /** Length of the current frame. 70 | * This equals the total length of the message if num == 0 && final == true */ 71 | uint64_t len; 72 | /** Mask key */ 73 | uint8_t mask[4]; 74 | /** Offset of the data inside the current frame. */ 75 | uint64_t index; 76 | } AwsFrameInfo; 77 | 78 | typedef enum { WS_DISCONNECTED, WS_CONNECTED, WS_DISCONNECTING } AwsClientStatus; 79 | typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PING, WS_PONG } AwsFrameType; 80 | typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus; 81 | typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType; 82 | 83 | class AsyncWebSocketMessageBuffer { 84 | private: 85 | uint8_t * _data; 86 | size_t _len; 87 | bool _lock; 88 | uint32_t _count; 89 | 90 | public: 91 | AsyncWebSocketMessageBuffer(); 92 | AsyncWebSocketMessageBuffer(size_t size); 93 | AsyncWebSocketMessageBuffer(uint8_t * data, size_t size); 94 | AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer &); 95 | AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer &&); 96 | ~AsyncWebSocketMessageBuffer(); 97 | void operator ++(int i) { (void)i; _count++; } 98 | void operator --(int i) { (void)i; if (_count > 0) { _count--; } ; } 99 | bool reserve(size_t size); 100 | void lock() { _lock = true; } 101 | void unlock() { _lock = false; } 102 | uint8_t * get() { return _data; } 103 | size_t length() { return _len; } 104 | uint32_t count() { return _count; } 105 | bool canDelete() { return (!_count && !_lock); } 106 | 107 | friend AsyncWebSocket; 108 | 109 | }; 110 | 111 | class AsyncWebSocketMessage { 112 | protected: 113 | uint8_t _opcode; 114 | bool _mask; 115 | AwsMessageStatus _status; 116 | public: 117 | AsyncWebSocketMessage():_opcode(WS_TEXT),_mask(false),_status(WS_MSG_ERROR){} 118 | virtual ~AsyncWebSocketMessage(){} 119 | virtual void ack(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))){} 120 | virtual size_t send(AsyncClient *client __attribute__((unused))){ return 0; } 121 | virtual bool finished(){ return _status != WS_MSG_SENDING; } 122 | virtual bool betweenFrames() const { return false; } 123 | }; 124 | 125 | class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage { 126 | private: 127 | size_t _len; 128 | size_t _sent; 129 | size_t _ack; 130 | size_t _acked; 131 | uint8_t * _data; 132 | public: 133 | AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode=WS_TEXT, bool mask=false); 134 | AsyncWebSocketBasicMessage(uint8_t opcode=WS_TEXT, bool mask=false); 135 | virtual ~AsyncWebSocketBasicMessage() override; 136 | virtual bool betweenFrames() const override { return _acked == _ack; } 137 | virtual void ack(size_t len, uint32_t time) override ; 138 | virtual size_t send(AsyncClient *client) override ; 139 | }; 140 | 141 | class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage { 142 | private: 143 | uint8_t * _data; 144 | size_t _len; 145 | size_t _sent; 146 | size_t _ack; 147 | size_t _acked; 148 | AsyncWebSocketMessageBuffer * _WSbuffer; 149 | public: 150 | AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode=WS_TEXT, bool mask=false); 151 | virtual ~AsyncWebSocketMultiMessage() override; 152 | virtual bool betweenFrames() const override { return _acked == _ack; } 153 | virtual void ack(size_t len, uint32_t time) override ; 154 | virtual size_t send(AsyncClient *client) override ; 155 | }; 156 | 157 | class AsyncWebSocketClient { 158 | private: 159 | AsyncClient *_client; 160 | AsyncWebSocket *_server; 161 | uint32_t _clientId; 162 | AwsClientStatus _status; 163 | 164 | LinkedList _controlQueue; 165 | LinkedList _messageQueue; 166 | 167 | uint8_t _pstate; 168 | AwsFrameInfo _pinfo; 169 | 170 | uint32_t _lastMessageTime; 171 | uint32_t _keepAlivePeriod; 172 | 173 | void _queueMessage(AsyncWebSocketMessage *dataMessage); 174 | void _queueControl(AsyncWebSocketControl *controlMessage); 175 | void _runQueue(); 176 | 177 | public: 178 | void *_tempObject; 179 | 180 | AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server); 181 | ~AsyncWebSocketClient(); 182 | 183 | //client id increments for the given server 184 | uint32_t id(){ return _clientId; } 185 | AwsClientStatus status(){ return _status; } 186 | AsyncClient* client(){ return _client; } 187 | AsyncWebSocket *server(){ return _server; } 188 | AwsFrameInfo const &pinfo() const { return _pinfo; } 189 | 190 | IPAddress remoteIP(); 191 | uint16_t remotePort(); 192 | 193 | //control frames 194 | void close(uint16_t code=0, const char * message=NULL); 195 | void ping(uint8_t *data=NULL, size_t len=0); 196 | 197 | //set auto-ping period in seconds. disabled if zero (default) 198 | void keepAlivePeriod(uint16_t seconds){ 199 | _keepAlivePeriod = seconds * 1000; 200 | } 201 | uint16_t keepAlivePeriod(){ 202 | return (uint16_t)(_keepAlivePeriod / 1000); 203 | } 204 | 205 | //data packets 206 | void message(AsyncWebSocketMessage *message){ _queueMessage(message); } 207 | bool queueIsFull(); 208 | 209 | size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3))); 210 | #ifndef ESP32 211 | size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); 212 | #endif 213 | void text(const char * message, size_t len); 214 | void text(const char * message); 215 | void text(uint8_t * message, size_t len); 216 | void text(char * message); 217 | void text(const String &message); 218 | void text(const __FlashStringHelper *data); 219 | void text(AsyncWebSocketMessageBuffer *buffer); 220 | 221 | void binary(const char * message, size_t len); 222 | void binary(const char * message); 223 | void binary(uint8_t * message, size_t len); 224 | void binary(char * message); 225 | void binary(const String &message); 226 | void binary(const __FlashStringHelper *data, size_t len); 227 | void binary(AsyncWebSocketMessageBuffer *buffer); 228 | 229 | bool canSend() { return _messageQueue.length() < WS_MAX_QUEUED_MESSAGES; } 230 | 231 | //system callbacks (do not call) 232 | void _onAck(size_t len, uint32_t time); 233 | void _onError(int8_t); 234 | void _onPoll(); 235 | void _onTimeout(uint32_t time); 236 | void _onDisconnect(); 237 | void _onData(void *pbuf, size_t plen); 238 | }; 239 | 240 | typedef std::function AwsEventHandler; 241 | 242 | //WebServer Handler implementation that plays the role of a socket server 243 | class AsyncWebSocket: public AsyncWebHandler { 244 | public: 245 | typedef LinkedList AsyncWebSocketClientLinkedList; 246 | private: 247 | String _url; 248 | AsyncWebSocketClientLinkedList _clients; 249 | uint32_t _cNextId; 250 | AwsEventHandler _eventHandler; 251 | bool _enabled; 252 | AsyncWebLock _lock; 253 | 254 | public: 255 | AsyncWebSocket(const String& url); 256 | ~AsyncWebSocket(); 257 | const char * url() const { return _url.c_str(); } 258 | void enable(bool e){ _enabled = e; } 259 | bool enabled() const { return _enabled; } 260 | bool availableForWriteAll(); 261 | bool availableForWrite(uint32_t id); 262 | 263 | size_t count() const; 264 | AsyncWebSocketClient * client(uint32_t id); 265 | bool hasClient(uint32_t id){ return client(id) != NULL; } 266 | 267 | void close(uint32_t id, uint16_t code=0, const char * message=NULL); 268 | void closeAll(uint16_t code=0, const char * message=NULL); 269 | void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS); 270 | 271 | void ping(uint32_t id, uint8_t *data=NULL, size_t len=0); 272 | void pingAll(uint8_t *data=NULL, size_t len=0); // done 273 | 274 | void text(uint32_t id, const char * message, size_t len); 275 | void text(uint32_t id, const char * message); 276 | void text(uint32_t id, uint8_t * message, size_t len); 277 | void text(uint32_t id, char * message); 278 | void text(uint32_t id, const String &message); 279 | void text(uint32_t id, const __FlashStringHelper *message); 280 | 281 | void textAll(const char * message, size_t len); 282 | void textAll(const char * message); 283 | void textAll(uint8_t * message, size_t len); 284 | void textAll(char * message); 285 | void textAll(const String &message); 286 | void textAll(const __FlashStringHelper *message); // need to convert 287 | void textAll(AsyncWebSocketMessageBuffer * buffer); 288 | 289 | void binary(uint32_t id, const char * message, size_t len); 290 | void binary(uint32_t id, const char * message); 291 | void binary(uint32_t id, uint8_t * message, size_t len); 292 | void binary(uint32_t id, char * message); 293 | void binary(uint32_t id, const String &message); 294 | void binary(uint32_t id, const __FlashStringHelper *message, size_t len); 295 | 296 | void binaryAll(const char * message, size_t len); 297 | void binaryAll(const char * message); 298 | void binaryAll(uint8_t * message, size_t len); 299 | void binaryAll(char * message); 300 | void binaryAll(const String &message); 301 | void binaryAll(const __FlashStringHelper *message, size_t len); 302 | void binaryAll(AsyncWebSocketMessageBuffer * buffer); 303 | 304 | void message(uint32_t id, AsyncWebSocketMessage *message); 305 | void messageAll(AsyncWebSocketMultiMessage *message); 306 | 307 | size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4))); 308 | size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); 309 | #ifndef ESP32 310 | size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__ ((format (printf, 3, 4))); 311 | #endif 312 | size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); 313 | 314 | //event listener 315 | void onEvent(AwsEventHandler handler){ 316 | _eventHandler = handler; 317 | } 318 | 319 | //system callbacks (do not call) 320 | uint32_t _getNextId(){ return _cNextId++; } 321 | void _addClient(AsyncWebSocketClient * client); 322 | void _handleDisconnect(AsyncWebSocketClient * client); 323 | void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); 324 | virtual bool canHandle(AsyncWebServerRequest *request) override final; 325 | virtual void handleRequest(AsyncWebServerRequest *request) override final; 326 | 327 | 328 | // messagebuffer functions/objects. 329 | AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0); 330 | AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size); 331 | LinkedList _buffers; 332 | void _cleanBuffers(); 333 | 334 | AsyncWebSocketClientLinkedList getClients() const; 335 | }; 336 | 337 | //WebServer response to authenticate the socket and detach the tcp client from the web server request 338 | class AsyncWebSocketResponse: public AsyncWebServerResponse { 339 | private: 340 | String _content; 341 | AsyncWebSocket *_server; 342 | public: 343 | AsyncWebSocketResponse(const String& key, AsyncWebSocket *server); 344 | void _respond(AsyncWebServerRequest *request); 345 | size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); 346 | bool _sourceValid() const { return true; } 347 | }; 348 | 349 | 350 | #endif /* ASYNCWEBSOCKET_H_ */ 351 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h: -------------------------------------------------------------------------------- 1 | #ifndef ASYNCWEBSYNCHRONIZATION_H_ 2 | #define ASYNCWEBSYNCHRONIZATION_H_ 3 | 4 | // Synchronisation is only available on ESP32, as the ESP8266 isn't using FreeRTOS by default 5 | 6 | #include 7 | 8 | #ifdef ESP32 9 | 10 | // This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore 11 | class AsyncWebLock 12 | { 13 | private: 14 | SemaphoreHandle_t _lock; 15 | mutable void *_lockedBy; 16 | 17 | public: 18 | AsyncWebLock() { 19 | _lock = xSemaphoreCreateBinary(); 20 | _lockedBy = NULL; 21 | xSemaphoreGive(_lock); 22 | } 23 | 24 | ~AsyncWebLock() { 25 | vSemaphoreDelete(_lock); 26 | } 27 | 28 | bool lock() const { 29 | extern void *pxCurrentTCB; 30 | if (_lockedBy != pxCurrentTCB) { 31 | xSemaphoreTake(_lock, portMAX_DELAY); 32 | _lockedBy = pxCurrentTCB; 33 | return true; 34 | } 35 | return false; 36 | } 37 | 38 | void unlock() const { 39 | _lockedBy = NULL; 40 | xSemaphoreGive(_lock); 41 | } 42 | }; 43 | 44 | #else 45 | 46 | // This is the 8266 version of the Sync Lock which is currently unimplemented 47 | class AsyncWebLock 48 | { 49 | 50 | public: 51 | AsyncWebLock() { 52 | } 53 | 54 | ~AsyncWebLock() { 55 | } 56 | 57 | bool lock() const { 58 | return false; 59 | } 60 | 61 | void unlock() const { 62 | } 63 | }; 64 | #endif 65 | 66 | class AsyncWebLockGuard 67 | { 68 | private: 69 | const AsyncWebLock *_lock; 70 | 71 | public: 72 | AsyncWebLockGuard(const AsyncWebLock &l) { 73 | if (l.lock()) { 74 | _lock = &l; 75 | } else { 76 | _lock = NULL; 77 | } 78 | } 79 | 80 | ~AsyncWebLockGuard() { 81 | if (_lock) { 82 | _lock->unlock(); 83 | } 84 | } 85 | }; 86 | 87 | #endif // ASYNCWEBSYNCHRONIZATION_H_ -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef _ESPAsyncWebServer_H_ 22 | #define _ESPAsyncWebServer_H_ 23 | 24 | #include "Arduino.h" 25 | 26 | #include 27 | #include "FS.h" 28 | 29 | #include "StringArray.h" 30 | 31 | #ifdef ESP32 32 | #include 33 | #include 34 | #elif defined(ESP8266) 35 | #include 36 | #include 37 | #else 38 | #error Platform not supported 39 | #endif 40 | 41 | #ifdef ASYNCWEBSERVER_REGEX 42 | #define ASYNCWEBSERVER_REGEX_ATTRIBUTE 43 | #else 44 | #define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined"))) 45 | #endif 46 | 47 | #define DEBUGF(...) //Serial.printf(__VA_ARGS__) 48 | 49 | class AsyncWebServer; 50 | class AsyncWebServerRequest; 51 | class AsyncWebServerResponse; 52 | class AsyncWebHeader; 53 | class AsyncWebParameter; 54 | class AsyncWebRewrite; 55 | class AsyncWebHandler; 56 | class AsyncStaticWebHandler; 57 | class AsyncCallbackWebHandler; 58 | class AsyncResponseStream; 59 | 60 | #ifndef WEBSERVER_H 61 | typedef enum { 62 | HTTP_GET = 0b00000001, 63 | HTTP_POST = 0b00000010, 64 | HTTP_DELETE = 0b00000100, 65 | HTTP_PUT = 0b00001000, 66 | HTTP_PATCH = 0b00010000, 67 | HTTP_HEAD = 0b00100000, 68 | HTTP_OPTIONS = 0b01000000, 69 | HTTP_ANY = 0b01111111, 70 | } WebRequestMethod; 71 | #endif 72 | 73 | //if this value is returned when asked for data, packet will not be sent and you will be asked for data again 74 | #define RESPONSE_TRY_AGAIN 0xFFFFFFFF 75 | 76 | typedef uint8_t WebRequestMethodComposite; 77 | typedef std::function ArDisconnectHandler; 78 | 79 | /* 80 | * PARAMETER :: Chainable object to hold GET/POST and FILE parameters 81 | * */ 82 | 83 | class AsyncWebParameter { 84 | private: 85 | String _name; 86 | String _value; 87 | size_t _size; 88 | bool _isForm; 89 | bool _isFile; 90 | 91 | public: 92 | 93 | AsyncWebParameter(const String& name, const String& value, bool form=false, bool file=false, size_t size=0): _name(name), _value(value), _size(size), _isForm(form), _isFile(file){} 94 | const String& name() const { return _name; } 95 | const String& value() const { return _value; } 96 | size_t size() const { return _size; } 97 | bool isPost() const { return _isForm; } 98 | bool isFile() const { return _isFile; } 99 | }; 100 | 101 | /* 102 | * HEADER :: Chainable object to hold the headers 103 | * */ 104 | 105 | class AsyncWebHeader { 106 | private: 107 | String _name; 108 | String _value; 109 | 110 | public: 111 | AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){} 112 | AsyncWebHeader(const String& data): _name(), _value(){ 113 | if(!data) return; 114 | int index = data.indexOf(':'); 115 | if (index < 0) return; 116 | _name = data.substring(0, index); 117 | _value = data.substring(index + 2); 118 | } 119 | ~AsyncWebHeader(){} 120 | const String& name() const { return _name; } 121 | const String& value() const { return _value; } 122 | String toString() const { return String(_name+": "+_value+"\r\n"); } 123 | }; 124 | 125 | /* 126 | * REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect 127 | * */ 128 | 129 | typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType; 130 | 131 | typedef std::function AwsResponseFiller; 132 | typedef std::function AwsTemplateProcessor; 133 | 134 | class AsyncWebServerRequest { 135 | using File = fs::File; 136 | using FS = fs::FS; 137 | friend class AsyncWebServer; 138 | friend class AsyncCallbackWebHandler; 139 | private: 140 | AsyncClient* _client; 141 | AsyncWebServer* _server; 142 | AsyncWebHandler* _handler; 143 | AsyncWebServerResponse* _response; 144 | StringArray _interestingHeaders; 145 | ArDisconnectHandler _onDisconnectfn; 146 | 147 | String _temp; 148 | uint8_t _parseState; 149 | 150 | uint8_t _version; 151 | WebRequestMethodComposite _method; 152 | String _url; 153 | String _host; 154 | String _contentType; 155 | String _boundary; 156 | String _authorization; 157 | RequestedConnectionType _reqconntype; 158 | void _removeNotInterestingHeaders(); 159 | bool _isDigest; 160 | bool _isMultipart; 161 | bool _isPlainPost; 162 | bool _expectingContinue; 163 | size_t _contentLength; 164 | size_t _parsedLength; 165 | 166 | LinkedList _headers; 167 | LinkedList _params; 168 | LinkedList _pathParams; 169 | 170 | uint8_t _multiParseState; 171 | uint8_t _boundaryPosition; 172 | size_t _itemStartIndex; 173 | size_t _itemSize; 174 | String _itemName; 175 | String _itemFilename; 176 | String _itemType; 177 | String _itemValue; 178 | uint8_t *_itemBuffer; 179 | size_t _itemBufferIndex; 180 | bool _itemIsFile; 181 | 182 | void _onPoll(); 183 | void _onAck(size_t len, uint32_t time); 184 | void _onError(int8_t error); 185 | void _onTimeout(uint32_t time); 186 | void _onDisconnect(); 187 | void _onData(void *buf, size_t len); 188 | 189 | void _addParam(AsyncWebParameter*); 190 | void _addPathParam(const char *param); 191 | 192 | bool _parseReqHead(); 193 | bool _parseReqHeader(); 194 | void _parseLine(); 195 | void _parsePlainPostChar(uint8_t data); 196 | void _parseMultipartPostByte(uint8_t data, bool last); 197 | void _addGetParams(const String& params); 198 | 199 | void _handleUploadStart(); 200 | void _handleUploadByte(uint8_t data, bool last); 201 | void _handleUploadEnd(); 202 | 203 | public: 204 | File _tempFile; 205 | void *_tempObject; 206 | 207 | AsyncWebServerRequest(AsyncWebServer*, AsyncClient*); 208 | ~AsyncWebServerRequest(); 209 | 210 | AsyncClient* client(){ return _client; } 211 | uint8_t version() const { return _version; } 212 | WebRequestMethodComposite method() const { return _method; } 213 | const String& url() const { return _url; } 214 | const String& host() const { return _host; } 215 | const String& contentType() const { return _contentType; } 216 | size_t contentLength() const { return _contentLength; } 217 | bool multipart() const { return _isMultipart; } 218 | const char * methodToString() const; 219 | const char * requestedConnTypeToString() const; 220 | RequestedConnectionType requestedConnType() const { return _reqconntype; } 221 | bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED); 222 | void onDisconnect (ArDisconnectHandler fn); 223 | 224 | //hash is the string representation of: 225 | // base64(user:pass) for basic or 226 | // user:realm:md5(user:realm:pass) for digest 227 | bool authenticate(const char * hash); 228 | bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false); 229 | void requestAuthentication(const char * realm = NULL, bool isDigest = true); 230 | 231 | void setHandler(AsyncWebHandler *handler){ _handler = handler; } 232 | void addInterestingHeader(const String& name); 233 | 234 | void redirect(const String& url); 235 | 236 | void send(AsyncWebServerResponse *response); 237 | void send(int code, const String& contentType=String(), const String& content=String()); 238 | void send(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 239 | void send(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 240 | void send(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); 241 | void send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 242 | void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 243 | void send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); 244 | void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr); 245 | 246 | AsyncWebServerResponse *beginResponse(int code, const String& contentType=String(), const String& content=String()); 247 | AsyncWebServerResponse *beginResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 248 | AsyncWebServerResponse *beginResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 249 | AsyncWebServerResponse *beginResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); 250 | AsyncWebServerResponse *beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 251 | AsyncWebServerResponse *beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 252 | AsyncResponseStream *beginResponseStream(const String& contentType, size_t bufferSize=1460); 253 | AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); 254 | AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr); 255 | 256 | size_t headers() const; // get header count 257 | bool hasHeader(const String& name) const; // check if header exists 258 | bool hasHeader(const __FlashStringHelper * data) const; // check if header exists 259 | 260 | AsyncWebHeader* getHeader(const String& name) const; 261 | AsyncWebHeader* getHeader(const __FlashStringHelper * data) const; 262 | AsyncWebHeader* getHeader(size_t num) const; 263 | 264 | size_t params() const; // get arguments count 265 | bool hasParam(const String& name, bool post=false, bool file=false) const; 266 | bool hasParam(const __FlashStringHelper * data, bool post=false, bool file=false) const; 267 | 268 | AsyncWebParameter* getParam(const String& name, bool post=false, bool file=false) const; 269 | AsyncWebParameter* getParam(const __FlashStringHelper * data, bool post, bool file) const; 270 | AsyncWebParameter* getParam(size_t num) const; 271 | 272 | size_t args() const { return params(); } // get arguments count 273 | const String& arg(const String& name) const; // get request argument value by name 274 | const String& arg(const __FlashStringHelper * data) const; // get request argument value by F(name) 275 | const String& arg(size_t i) const; // get request argument value by number 276 | const String& argName(size_t i) const; // get request argument name by number 277 | bool hasArg(const char* name) const; // check if argument exists 278 | bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists 279 | 280 | const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const; 281 | 282 | const String& header(const char* name) const;// get request header value by name 283 | const String& header(const __FlashStringHelper * data) const;// get request header value by F(name) 284 | const String& header(size_t i) const; // get request header value by number 285 | const String& headerName(size_t i) const; // get request header name by number 286 | String urlDecode(const String& text) const; 287 | }; 288 | 289 | /* 290 | * FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server) 291 | * */ 292 | 293 | typedef std::function ArRequestFilterFunction; 294 | 295 | bool ON_STA_FILTER(AsyncWebServerRequest *request); 296 | 297 | bool ON_AP_FILTER(AsyncWebServerRequest *request); 298 | 299 | /* 300 | * REWRITE :: One instance can be handle any Request (done by the Server) 301 | * */ 302 | 303 | class AsyncWebRewrite { 304 | protected: 305 | String _from; 306 | String _toUrl; 307 | String _params; 308 | ArRequestFilterFunction _filter; 309 | public: 310 | AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL){ 311 | int index = _toUrl.indexOf('?'); 312 | if (index > 0) { 313 | _params = _toUrl.substring(index +1); 314 | _toUrl = _toUrl.substring(0, index); 315 | } 316 | } 317 | virtual ~AsyncWebRewrite(){} 318 | AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } 319 | bool filter(AsyncWebServerRequest *request) const { return _filter == NULL || _filter(request); } 320 | const String& from(void) const { return _from; } 321 | const String& toUrl(void) const { return _toUrl; } 322 | const String& params(void) const { return _params; } 323 | virtual bool match(AsyncWebServerRequest *request) { return from() == request->url() && filter(request); } 324 | }; 325 | 326 | /* 327 | * HANDLER :: One instance can be attached to any Request (done by the Server) 328 | * */ 329 | 330 | class AsyncWebHandler { 331 | protected: 332 | ArRequestFilterFunction _filter; 333 | String _username; 334 | String _password; 335 | public: 336 | AsyncWebHandler():_username(""), _password(""){} 337 | AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } 338 | AsyncWebHandler& setAuthentication(const char *username, const char *password){ _username = String(username);_password = String(password); return *this; }; 339 | bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); } 340 | virtual ~AsyncWebHandler(){} 341 | virtual bool canHandle(AsyncWebServerRequest *request __attribute__((unused))){ 342 | return false; 343 | } 344 | virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){} 345 | virtual void handleUpload(AsyncWebServerRequest *request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))){} 346 | virtual void handleBody(AsyncWebServerRequest *request __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))){} 347 | virtual bool isRequestHandlerTrivial(){return true;} 348 | }; 349 | 350 | /* 351 | * RESPONSE :: One instance is created for each Request (attached by the Handler) 352 | * */ 353 | 354 | typedef enum { 355 | RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED 356 | } WebResponseState; 357 | 358 | class AsyncWebServerResponse { 359 | protected: 360 | int _code; 361 | LinkedList _headers; 362 | String _contentType; 363 | size_t _contentLength; 364 | bool _sendContentLength; 365 | bool _chunked; 366 | size_t _headLength; 367 | size_t _sentLength; 368 | size_t _ackedLength; 369 | size_t _writtenLength; 370 | WebResponseState _state; 371 | const char* _responseCodeToString(int code); 372 | 373 | public: 374 | AsyncWebServerResponse(); 375 | virtual ~AsyncWebServerResponse(); 376 | virtual void setCode(int code); 377 | virtual void setContentLength(size_t len); 378 | virtual void setContentType(const String& type); 379 | virtual void addHeader(const String& name, const String& value); 380 | virtual String _assembleHead(uint8_t version); 381 | virtual bool _started() const; 382 | virtual bool _finished() const; 383 | virtual bool _failed() const; 384 | virtual bool _sourceValid() const; 385 | virtual void _respond(AsyncWebServerRequest *request); 386 | virtual size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); 387 | }; 388 | 389 | /* 390 | * SERVER :: One instance 391 | * */ 392 | 393 | typedef std::function ArRequestHandlerFunction; 394 | typedef std::function ArUploadHandlerFunction; 395 | typedef std::function ArBodyHandlerFunction; 396 | 397 | class AsyncWebServer { 398 | protected: 399 | AsyncServer _server; 400 | LinkedList _rewrites; 401 | LinkedList _handlers; 402 | AsyncCallbackWebHandler* _catchAllHandler; 403 | 404 | public: 405 | AsyncWebServer(uint16_t port); 406 | ~AsyncWebServer(); 407 | 408 | void begin(); 409 | void end(); 410 | 411 | #if ASYNC_TCP_SSL_ENABLED 412 | void onSslFileRequest(AcSSlFileHandler cb, void* arg); 413 | void beginSecure(const char *cert, const char *private_key_file, const char *password); 414 | #endif 415 | 416 | AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite); 417 | bool removeRewrite(AsyncWebRewrite* rewrite); 418 | AsyncWebRewrite& rewrite(const char* from, const char* to); 419 | 420 | AsyncWebHandler& addHandler(AsyncWebHandler* handler); 421 | bool removeHandler(AsyncWebHandler* handler); 422 | 423 | AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest); 424 | AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest); 425 | AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload); 426 | AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody); 427 | 428 | AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL); 429 | 430 | void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned 431 | void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads 432 | void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request) 433 | 434 | void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody 435 | 436 | void _handleDisconnect(AsyncWebServerRequest *request); 437 | void _attachHandler(AsyncWebServerRequest *request); 438 | void _rewriteRequest(AsyncWebServerRequest *request); 439 | }; 440 | 441 | class DefaultHeaders { 442 | using headers_t = LinkedList; 443 | headers_t _headers; 444 | 445 | DefaultHeaders() 446 | :_headers(headers_t([](AsyncWebHeader *h){ delete h; })) 447 | {} 448 | public: 449 | using ConstIterator = headers_t::ConstIterator; 450 | 451 | void addHeader(const String& name, const String& value){ 452 | _headers.add(new AsyncWebHeader(name, value)); 453 | } 454 | 455 | ConstIterator begin() const { return _headers.begin(); } 456 | ConstIterator end() const { return _headers.end(); } 457 | 458 | DefaultHeaders(DefaultHeaders const &) = delete; 459 | DefaultHeaders &operator=(DefaultHeaders const &) = delete; 460 | static DefaultHeaders &Instance() { 461 | static DefaultHeaders instance; 462 | return instance; 463 | } 464 | }; 465 | 466 | #include "WebResponseImpl.h" 467 | #include "WebHandlerImpl.h" 468 | #include "AsyncWebSocket.h" 469 | #include "AsyncEventSource.h" 470 | 471 | #endif /* _AsyncWebServer_H_ */ 472 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/SPIFFSEditor.h: -------------------------------------------------------------------------------- 1 | #ifndef SPIFFSEditor_H_ 2 | #define SPIFFSEditor_H_ 3 | #include 4 | 5 | class SPIFFSEditor: public AsyncWebHandler { 6 | private: 7 | fs::FS _fs; 8 | String _username; 9 | String _password; 10 | bool _authenticated; 11 | uint32_t _startTime; 12 | public: 13 | #ifdef ESP32 14 | SPIFFSEditor(const fs::FS& fs, const String& username=String(), const String& password=String()); 15 | #else 16 | SPIFFSEditor(const String& username=String(), const String& password=String(), const fs::FS& fs=SPIFFS); 17 | #endif 18 | virtual bool canHandle(AsyncWebServerRequest *request) override final; 19 | virtual void handleRequest(AsyncWebServerRequest *request) override final; 20 | virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final; 21 | virtual bool isRequestHandlerTrivial() override final {return false;} 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/StringArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef STRINGARRAY_H_ 22 | #define STRINGARRAY_H_ 23 | 24 | #include "stddef.h" 25 | #include "WString.h" 26 | 27 | template 28 | class LinkedListNode { 29 | T _value; 30 | public: 31 | LinkedListNode* next; 32 | LinkedListNode(const T val): _value(val), next(nullptr) {} 33 | ~LinkedListNode(){} 34 | const T& value() const { return _value; }; 35 | T& value(){ return _value; } 36 | }; 37 | 38 | template class Item = LinkedListNode> 39 | class LinkedList { 40 | public: 41 | typedef Item ItemType; 42 | typedef std::function OnRemove; 43 | typedef std::function Predicate; 44 | private: 45 | ItemType* _root; 46 | OnRemove _onRemove; 47 | 48 | class Iterator { 49 | ItemType* _node; 50 | public: 51 | Iterator(ItemType* current = nullptr) : _node(current) {} 52 | Iterator(const Iterator& i) : _node(i._node) {} 53 | Iterator& operator ++() { _node = _node->next; return *this; } 54 | bool operator != (const Iterator& i) const { return _node != i._node; } 55 | const T& operator * () const { return _node->value(); } 56 | const T* operator -> () const { return &_node->value(); } 57 | }; 58 | 59 | public: 60 | typedef const Iterator ConstIterator; 61 | ConstIterator begin() const { return ConstIterator(_root); } 62 | ConstIterator end() const { return ConstIterator(nullptr); } 63 | 64 | LinkedList(OnRemove onRemove) : _root(nullptr), _onRemove(onRemove) {} 65 | ~LinkedList(){} 66 | void add(const T& t){ 67 | auto it = new ItemType(t); 68 | if(!_root){ 69 | _root = it; 70 | } else { 71 | auto i = _root; 72 | while(i->next) i = i->next; 73 | i->next = it; 74 | } 75 | } 76 | T& front() const { 77 | return _root->value(); 78 | } 79 | 80 | bool isEmpty() const { 81 | return _root == nullptr; 82 | } 83 | size_t length() const { 84 | size_t i = 0; 85 | auto it = _root; 86 | while(it){ 87 | i++; 88 | it = it->next; 89 | } 90 | return i; 91 | } 92 | size_t count_if(Predicate predicate) const { 93 | size_t i = 0; 94 | auto it = _root; 95 | while(it){ 96 | if (!predicate){ 97 | i++; 98 | } 99 | else if (predicate(it->value())) { 100 | i++; 101 | } 102 | it = it->next; 103 | } 104 | return i; 105 | } 106 | const T* nth(size_t N) const { 107 | size_t i = 0; 108 | auto it = _root; 109 | while(it){ 110 | if(i++ == N) 111 | return &(it->value()); 112 | it = it->next; 113 | } 114 | return nullptr; 115 | } 116 | bool remove(const T& t){ 117 | auto it = _root; 118 | auto pit = _root; 119 | while(it){ 120 | if(it->value() == t){ 121 | if(it == _root){ 122 | _root = _root->next; 123 | } else { 124 | pit->next = it->next; 125 | } 126 | 127 | if (_onRemove) { 128 | _onRemove(it->value()); 129 | } 130 | 131 | delete it; 132 | return true; 133 | } 134 | pit = it; 135 | it = it->next; 136 | } 137 | return false; 138 | } 139 | bool remove_first(Predicate predicate){ 140 | auto it = _root; 141 | auto pit = _root; 142 | while(it){ 143 | if(predicate(it->value())){ 144 | if(it == _root){ 145 | _root = _root->next; 146 | } else { 147 | pit->next = it->next; 148 | } 149 | if (_onRemove) { 150 | _onRemove(it->value()); 151 | } 152 | delete it; 153 | return true; 154 | } 155 | pit = it; 156 | it = it->next; 157 | } 158 | return false; 159 | } 160 | 161 | void free(){ 162 | while(_root != nullptr){ 163 | auto it = _root; 164 | _root = _root->next; 165 | if (_onRemove) { 166 | _onRemove(it->value()); 167 | } 168 | delete it; 169 | } 170 | _root = nullptr; 171 | } 172 | }; 173 | 174 | 175 | class StringArray : public LinkedList { 176 | public: 177 | 178 | StringArray() : LinkedList(nullptr) {} 179 | 180 | bool containsIgnoreCase(const String& str){ 181 | for (const auto& s : *this) { 182 | if (str.equalsIgnoreCase(s)) { 183 | return true; 184 | } 185 | } 186 | return false; 187 | } 188 | }; 189 | 190 | 191 | 192 | 193 | #endif /* STRINGARRAY_H_ */ 194 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebAuthentication.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include "WebAuthentication.h" 22 | #include 23 | #ifdef ESP32 24 | #include "mbedtls/md5.h" 25 | #else 26 | #include "md5.h" 27 | #endif 28 | 29 | 30 | // Basic Auth hash = base64("username:password") 31 | 32 | bool checkBasicAuthentication(const char * hash, const char * username, const char * password){ 33 | if(username == NULL || password == NULL || hash == NULL) 34 | return false; 35 | 36 | size_t toencodeLen = strlen(username)+strlen(password)+1; 37 | size_t encodedLen = base64_encode_expected_len(toencodeLen); 38 | if(strlen(hash) != encodedLen) 39 | return false; 40 | 41 | char *toencode = new char[toencodeLen+1]; 42 | if(toencode == NULL){ 43 | return false; 44 | } 45 | char *encoded = new char[base64_encode_expected_len(toencodeLen)+1]; 46 | if(encoded == NULL){ 47 | delete[] toencode; 48 | return false; 49 | } 50 | sprintf(toencode, "%s:%s", username, password); 51 | if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0){ 52 | delete[] toencode; 53 | delete[] encoded; 54 | return true; 55 | } 56 | delete[] toencode; 57 | delete[] encoded; 58 | return false; 59 | } 60 | 61 | static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or more 62 | #ifdef ESP32 63 | mbedtls_md5_context _ctx; 64 | #else 65 | md5_context_t _ctx; 66 | #endif 67 | uint8_t i; 68 | uint8_t * _buf = (uint8_t*)malloc(16); 69 | if(_buf == NULL) 70 | return false; 71 | memset(_buf, 0x00, 16); 72 | #ifdef ESP32 73 | mbedtls_md5_init(&_ctx); 74 | mbedtls_md5_starts(&_ctx); 75 | mbedtls_md5_update(&_ctx, data, len); 76 | mbedtls_md5_finish(&_ctx, _buf); 77 | #else 78 | MD5Init(&_ctx); 79 | MD5Update(&_ctx, data, len); 80 | MD5Final(_buf, &_ctx); 81 | #endif 82 | for(i = 0; i < 16; i++) { 83 | sprintf(output + (i * 2), "%02x", _buf[i]); 84 | } 85 | free(_buf); 86 | return true; 87 | } 88 | 89 | static String genRandomMD5(){ 90 | #ifdef ESP8266 91 | uint32_t r = RANDOM_REG32; 92 | #else 93 | uint32_t r = rand(); 94 | #endif 95 | char * out = (char*)malloc(33); 96 | if(out == NULL || !getMD5((uint8_t*)(&r), 4, out)) 97 | return ""; 98 | String res = String(out); 99 | free(out); 100 | return res; 101 | } 102 | 103 | static String stringMD5(const String& in){ 104 | char * out = (char*)malloc(33); 105 | if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) 106 | return ""; 107 | String res = String(out); 108 | free(out); 109 | return res; 110 | } 111 | 112 | String generateDigestHash(const char * username, const char * password, const char * realm){ 113 | if(username == NULL || password == NULL || realm == NULL){ 114 | return ""; 115 | } 116 | char * out = (char*)malloc(33); 117 | String res = String(username); 118 | res.concat(":"); 119 | res.concat(realm); 120 | res.concat(":"); 121 | String in = res; 122 | in.concat(password); 123 | if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) 124 | return ""; 125 | res.concat(out); 126 | free(out); 127 | return res; 128 | } 129 | 130 | String requestDigestAuthentication(const char * realm){ 131 | String header = "realm=\""; 132 | if(realm == NULL) 133 | header.concat("asyncesp"); 134 | else 135 | header.concat(realm); 136 | header.concat( "\", qop=\"auth\", nonce=\""); 137 | header.concat(genRandomMD5()); 138 | header.concat("\", opaque=\""); 139 | header.concat(genRandomMD5()); 140 | header.concat("\""); 141 | return header; 142 | } 143 | 144 | bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri){ 145 | if(username == NULL || password == NULL || header == NULL || method == NULL){ 146 | //os_printf("AUTH FAIL: missing requred fields\n"); 147 | return false; 148 | } 149 | 150 | String myHeader = String(header); 151 | int nextBreak = myHeader.indexOf(","); 152 | if(nextBreak < 0){ 153 | //os_printf("AUTH FAIL: no variables\n"); 154 | return false; 155 | } 156 | 157 | String myUsername = String(); 158 | String myRealm = String(); 159 | String myNonce = String(); 160 | String myUri = String(); 161 | String myResponse = String(); 162 | String myQop = String(); 163 | String myNc = String(); 164 | String myCnonce = String(); 165 | 166 | myHeader += ", "; 167 | do { 168 | String avLine = myHeader.substring(0, nextBreak); 169 | avLine.trim(); 170 | myHeader = myHeader.substring(nextBreak+1); 171 | nextBreak = myHeader.indexOf(","); 172 | 173 | int eqSign = avLine.indexOf("="); 174 | if(eqSign < 0){ 175 | //os_printf("AUTH FAIL: no = sign\n"); 176 | return false; 177 | } 178 | String varName = avLine.substring(0, eqSign); 179 | avLine = avLine.substring(eqSign + 1); 180 | if(avLine.startsWith("\"")){ 181 | avLine = avLine.substring(1, avLine.length() - 1); 182 | } 183 | 184 | if(varName.equals("username")){ 185 | if(!avLine.equals(username)){ 186 | //os_printf("AUTH FAIL: username\n"); 187 | return false; 188 | } 189 | myUsername = avLine; 190 | } else if(varName.equals("realm")){ 191 | if(realm != NULL && !avLine.equals(realm)){ 192 | //os_printf("AUTH FAIL: realm\n"); 193 | return false; 194 | } 195 | myRealm = avLine; 196 | } else if(varName.equals("nonce")){ 197 | if(nonce != NULL && !avLine.equals(nonce)){ 198 | //os_printf("AUTH FAIL: nonce\n"); 199 | return false; 200 | } 201 | myNonce = avLine; 202 | } else if(varName.equals("opaque")){ 203 | if(opaque != NULL && !avLine.equals(opaque)){ 204 | //os_printf("AUTH FAIL: opaque\n"); 205 | return false; 206 | } 207 | } else if(varName.equals("uri")){ 208 | if(uri != NULL && !avLine.equals(uri)){ 209 | //os_printf("AUTH FAIL: uri\n"); 210 | return false; 211 | } 212 | myUri = avLine; 213 | } else if(varName.equals("response")){ 214 | myResponse = avLine; 215 | } else if(varName.equals("qop")){ 216 | myQop = avLine; 217 | } else if(varName.equals("nc")){ 218 | myNc = avLine; 219 | } else if(varName.equals("cnonce")){ 220 | myCnonce = avLine; 221 | } 222 | } while(nextBreak > 0); 223 | 224 | String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ":" + myRealm + ":" + String(password)); 225 | String ha2 = String(method) + ":" + myUri; 226 | String response = ha1 + ":" + myNonce + ":" + myNc + ":" + myCnonce + ":" + myQop + ":" + stringMD5(ha2); 227 | 228 | if(myResponse.equals(stringMD5(response))){ 229 | //os_printf("AUTH SUCCESS\n"); 230 | return true; 231 | } 232 | 233 | //os_printf("AUTH FAIL: password\n"); 234 | return false; 235 | } 236 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebAuthentication.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef WEB_AUTHENTICATION_H_ 23 | #define WEB_AUTHENTICATION_H_ 24 | 25 | #include "Arduino.h" 26 | 27 | bool checkBasicAuthentication(const char * header, const char * username, const char * password); 28 | String requestDigestAuthentication(const char * realm); 29 | bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri); 30 | 31 | //for storing hashed versions on the device that can be authenticated against 32 | String generateDigestHash(const char * username, const char * password, const char * realm); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebHandlerImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef ASYNCWEBSERVERHANDLERIMPL_H_ 22 | #define ASYNCWEBSERVERHANDLERIMPL_H_ 23 | 24 | #include 25 | #ifdef ASYNCWEBSERVER_REGEX 26 | #include 27 | #endif 28 | 29 | #include "stddef.h" 30 | #include 31 | 32 | class AsyncStaticWebHandler: public AsyncWebHandler { 33 | using File = fs::File; 34 | using FS = fs::FS; 35 | private: 36 | bool _getFile(AsyncWebServerRequest *request); 37 | bool _fileExists(AsyncWebServerRequest *request, const String& path); 38 | uint8_t _countBits(const uint8_t value) const; 39 | protected: 40 | FS _fs; 41 | String _uri; 42 | String _path; 43 | String _default_file; 44 | String _cache_control; 45 | String _last_modified; 46 | AwsTemplateProcessor _callback; 47 | bool _isDir; 48 | bool _gzipFirst; 49 | uint8_t _gzipStats; 50 | public: 51 | AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control); 52 | virtual bool canHandle(AsyncWebServerRequest *request) override final; 53 | virtual void handleRequest(AsyncWebServerRequest *request) override final; 54 | AsyncStaticWebHandler& setIsDir(bool isDir); 55 | AsyncStaticWebHandler& setDefaultFile(const char* filename); 56 | AsyncStaticWebHandler& setCacheControl(const char* cache_control); 57 | AsyncStaticWebHandler& setLastModified(const char* last_modified); 58 | AsyncStaticWebHandler& setLastModified(struct tm* last_modified); 59 | #ifdef ESP8266 60 | AsyncStaticWebHandler& setLastModified(time_t last_modified); 61 | AsyncStaticWebHandler& setLastModified(); //sets to current time. Make sure sntp is runing and time is updated 62 | #endif 63 | AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;} 64 | }; 65 | 66 | class AsyncCallbackWebHandler: public AsyncWebHandler { 67 | private: 68 | protected: 69 | String _uri; 70 | WebRequestMethodComposite _method; 71 | ArRequestHandlerFunction _onRequest; 72 | ArUploadHandlerFunction _onUpload; 73 | ArBodyHandlerFunction _onBody; 74 | bool _isRegex; 75 | public: 76 | AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {} 77 | void setUri(const String& uri){ 78 | _uri = uri; 79 | _isRegex = uri.startsWith("^") && uri.endsWith("$"); 80 | } 81 | void setMethod(WebRequestMethodComposite method){ _method = method; } 82 | void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; } 83 | void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; } 84 | void onBody(ArBodyHandlerFunction fn){ _onBody = fn; } 85 | 86 | virtual bool canHandle(AsyncWebServerRequest *request) override final{ 87 | 88 | if(!_onRequest) 89 | return false; 90 | 91 | if(!(_method & request->method())) 92 | return false; 93 | 94 | #ifdef ASYNCWEBSERVER_REGEX 95 | if (_isRegex) { 96 | std::regex pattern(_uri.c_str()); 97 | std::smatch matches; 98 | std::string s(request->url().c_str()); 99 | if(std::regex_search(s, matches, pattern)) { 100 | for (size_t i = 1; i < matches.size(); ++i) { // start from 1 101 | request->_addPathParam(matches[i].str().c_str()); 102 | } 103 | } else { 104 | return false; 105 | } 106 | } else 107 | #endif 108 | if (_uri.length() && _uri.endsWith("*")) { 109 | String uriTemplate = String(_uri); 110 | uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1); 111 | if (!request->url().startsWith(uriTemplate)) 112 | return false; 113 | } 114 | else if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) 115 | return false; 116 | 117 | request->addInterestingHeader("ANY"); 118 | return true; 119 | } 120 | 121 | virtual void handleRequest(AsyncWebServerRequest *request) override final { 122 | if(_onRequest) 123 | _onRequest(request); 124 | else 125 | request->send(500); 126 | } 127 | virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { 128 | if(_onUpload) 129 | _onUpload(request, filename, index, data, len, final); 130 | } 131 | virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { 132 | if(_onBody) 133 | _onBody(request, data, len, index, total); 134 | } 135 | virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} 136 | }; 137 | 138 | #endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */ 139 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebHandlers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include "ESPAsyncWebServer.h" 22 | #include "WebHandlerImpl.h" 23 | 24 | AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control) 25 | : _fs(fs), _uri(uri), _path(path), _default_file("index.htm"), _cache_control(cache_control), _last_modified(""), _callback(nullptr) 26 | { 27 | // Ensure leading '/' 28 | if (_uri.length() == 0 || _uri[0] != '/') _uri = "/" + _uri; 29 | if (_path.length() == 0 || _path[0] != '/') _path = "/" + _path; 30 | 31 | // If path ends with '/' we assume a hint that this is a directory to improve performance. 32 | // However - if it does not end with '/' we, can't assume a file, path can still be a directory. 33 | _isDir = _path[_path.length()-1] == '/'; 34 | 35 | // Remove the trailing '/' so we can handle default file 36 | // Notice that root will be "" not "/" 37 | if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1); 38 | if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1); 39 | 40 | // Reset stats 41 | _gzipFirst = false; 42 | _gzipStats = 0xF8; 43 | } 44 | 45 | AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir){ 46 | _isDir = isDir; 47 | return *this; 48 | } 49 | 50 | AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename){ 51 | _default_file = String(filename); 52 | return *this; 53 | } 54 | 55 | AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control){ 56 | _cache_control = String(cache_control); 57 | return *this; 58 | } 59 | 60 | AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified){ 61 | _last_modified = String(last_modified); 62 | return *this; 63 | } 64 | 65 | AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified){ 66 | char result[30]; 67 | strftime (result,30,"%a, %d %b %Y %H:%M:%S %Z", last_modified); 68 | return setLastModified((const char *)result); 69 | } 70 | 71 | #ifdef ESP8266 72 | AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified){ 73 | return setLastModified((struct tm *)gmtime(&last_modified)); 74 | } 75 | 76 | AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){ 77 | time_t last_modified; 78 | if(time(&last_modified) == 0) //time is not yet set 79 | return *this; 80 | return setLastModified(last_modified); 81 | } 82 | #endif 83 | bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){ 84 | if(request->method() != HTTP_GET 85 | || !request->url().startsWith(_uri) 86 | || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP) 87 | ){ 88 | return false; 89 | } 90 | if (_getFile(request)) { 91 | // We interested in "If-Modified-Since" header to check if file was modified 92 | if (_last_modified.length()) 93 | request->addInterestingHeader("If-Modified-Since"); 94 | 95 | if(_cache_control.length()) 96 | request->addInterestingHeader("If-None-Match"); 97 | 98 | DEBUGF("[AsyncStaticWebHandler::canHandle] TRUE\n"); 99 | return true; 100 | } 101 | 102 | return false; 103 | } 104 | 105 | bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) 106 | { 107 | // Remove the found uri 108 | String path = request->url().substring(_uri.length()); 109 | 110 | // We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/' 111 | bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/'); 112 | 113 | path = _path + path; 114 | 115 | // Do we have a file or .gz file 116 | if (!canSkipFileCheck && _fileExists(request, path)) 117 | return true; 118 | 119 | // Can't handle if not default file 120 | if (_default_file.length() == 0) 121 | return false; 122 | 123 | // Try to add default file, ensure there is a trailing '/' ot the path. 124 | if (path.length() == 0 || path[path.length()-1] != '/') 125 | path += "/"; 126 | path += _default_file; 127 | 128 | return _fileExists(request, path); 129 | } 130 | 131 | #ifdef ESP32 132 | #define FILE_IS_REAL(f) (f == true && !f.isDirectory()) 133 | #else 134 | #define FILE_IS_REAL(f) (f == true) 135 | #endif 136 | 137 | bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const String& path) 138 | { 139 | bool fileFound = false; 140 | bool gzipFound = false; 141 | 142 | String gzip = path + ".gz"; 143 | 144 | if (_gzipFirst) { 145 | request->_tempFile = _fs.open(gzip, "r"); 146 | gzipFound = FILE_IS_REAL(request->_tempFile); 147 | if (!gzipFound){ 148 | request->_tempFile = _fs.open(path, "r"); 149 | fileFound = FILE_IS_REAL(request->_tempFile); 150 | } 151 | } else { 152 | request->_tempFile = _fs.open(path, "r"); 153 | fileFound = FILE_IS_REAL(request->_tempFile); 154 | if (!fileFound){ 155 | request->_tempFile = _fs.open(gzip, "r"); 156 | gzipFound = FILE_IS_REAL(request->_tempFile); 157 | } 158 | } 159 | 160 | bool found = fileFound || gzipFound; 161 | 162 | if (found) { 163 | // Extract the file name from the path and keep it in _tempObject 164 | size_t pathLen = path.length(); 165 | char * _tempPath = (char*)malloc(pathLen+1); 166 | snprintf(_tempPath, pathLen+1, "%s", path.c_str()); 167 | request->_tempObject = (void*)_tempPath; 168 | 169 | // Calculate gzip statistic 170 | _gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0); 171 | if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip 172 | else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip 173 | else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first 174 | } 175 | 176 | return found; 177 | } 178 | 179 | uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const 180 | { 181 | uint8_t w = value; 182 | uint8_t n; 183 | for (n=0; w!=0; n++) w&=w-1; 184 | return n; 185 | } 186 | 187 | void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) 188 | { 189 | // Get the filename from request->_tempObject and free it 190 | String filename = String((char*)request->_tempObject); 191 | free(request->_tempObject); 192 | request->_tempObject = NULL; 193 | if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) 194 | return request->requestAuthentication(); 195 | 196 | if (request->_tempFile == true) { 197 | String etag = String(request->_tempFile.size()); 198 | if (_last_modified.length() && _last_modified == request->header("If-Modified-Since")) { 199 | request->_tempFile.close(); 200 | request->send(304); // Not modified 201 | } else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag)) { 202 | request->_tempFile.close(); 203 | AsyncWebServerResponse * response = new AsyncBasicResponse(304); // Not modified 204 | response->addHeader("Cache-Control", _cache_control); 205 | response->addHeader("ETag", etag); 206 | request->send(response); 207 | } else { 208 | AsyncWebServerResponse * response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback); 209 | if (_last_modified.length()) 210 | response->addHeader("Last-Modified", _last_modified); 211 | if (_cache_control.length()){ 212 | response->addHeader("Cache-Control", _cache_control); 213 | response->addHeader("ETag", etag); 214 | } 215 | request->send(response); 216 | } 217 | } else { 218 | request->send(404); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebResponseImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef ASYNCWEBSERVERRESPONSEIMPL_H_ 22 | #define ASYNCWEBSERVERRESPONSEIMPL_H_ 23 | 24 | #ifdef Arduino_h 25 | // arduino is not compatible with std::vector 26 | #undef min 27 | #undef max 28 | #endif 29 | #include 30 | // It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max. 31 | 32 | class AsyncBasicResponse: public AsyncWebServerResponse { 33 | private: 34 | String _content; 35 | public: 36 | AsyncBasicResponse(int code, const String& contentType=String(), const String& content=String()); 37 | void _respond(AsyncWebServerRequest *request); 38 | size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); 39 | bool _sourceValid() const { return true; } 40 | }; 41 | 42 | class AsyncAbstractResponse: public AsyncWebServerResponse { 43 | private: 44 | String _head; 45 | // Data is inserted into cache at begin(). 46 | // This is inefficient with vector, but if we use some other container, 47 | // we won't be able to access it as contiguous array of bytes when reading from it, 48 | // so by gaining performance in one place, we'll lose it in another. 49 | std::vector _cache; 50 | size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len); 51 | size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen); 52 | protected: 53 | AwsTemplateProcessor _callback; 54 | public: 55 | AsyncAbstractResponse(AwsTemplateProcessor callback=nullptr); 56 | void _respond(AsyncWebServerRequest *request); 57 | size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); 58 | bool _sourceValid() const { return false; } 59 | virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } 60 | }; 61 | 62 | #ifndef TEMPLATE_PLACEHOLDER 63 | #define TEMPLATE_PLACEHOLDER '%' 64 | #endif 65 | 66 | #define TEMPLATE_PARAM_NAME_LENGTH 32 67 | class AsyncFileResponse: public AsyncAbstractResponse { 68 | using File = fs::File; 69 | using FS = fs::FS; 70 | private: 71 | File _content; 72 | String _path; 73 | void _setContentType(const String& path); 74 | public: 75 | AsyncFileResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 76 | AsyncFileResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 77 | ~AsyncFileResponse(); 78 | bool _sourceValid() const { return !!(_content); } 79 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 80 | }; 81 | 82 | class AsyncStreamResponse: public AsyncAbstractResponse { 83 | private: 84 | Stream *_content; 85 | public: 86 | AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); 87 | bool _sourceValid() const { return !!(_content); } 88 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 89 | }; 90 | 91 | class AsyncCallbackResponse: public AsyncAbstractResponse { 92 | private: 93 | AwsResponseFiller _content; 94 | size_t _filledLength; 95 | public: 96 | AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 97 | bool _sourceValid() const { return !!(_content); } 98 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 99 | }; 100 | 101 | class AsyncChunkedResponse: public AsyncAbstractResponse { 102 | private: 103 | AwsResponseFiller _content; 104 | size_t _filledLength; 105 | public: 106 | AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); 107 | bool _sourceValid() const { return !!(_content); } 108 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 109 | }; 110 | 111 | class AsyncProgmemResponse: public AsyncAbstractResponse { 112 | private: 113 | const uint8_t * _content; 114 | size_t _readLength; 115 | public: 116 | AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); 117 | bool _sourceValid() const { return true; } 118 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 119 | }; 120 | 121 | class cbuf; 122 | 123 | class AsyncResponseStream: public AsyncAbstractResponse, public Print { 124 | private: 125 | cbuf *_content; 126 | public: 127 | AsyncResponseStream(const String& contentType, size_t bufferSize); 128 | ~AsyncResponseStream(); 129 | bool _sourceValid() const { return (_state < RESPONSE_END); } 130 | virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; 131 | size_t write(const uint8_t *data, size_t len); 132 | size_t write(uint8_t data); 133 | using Print::write; 134 | }; 135 | 136 | #endif /* ASYNCWEBSERVERRESPONSEIMPL_H_ */ 137 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/WebServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Asynchronous WebServer library for Espressif MCUs 3 | 4 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include "ESPAsyncWebServer.h" 22 | #include "WebHandlerImpl.h" 23 | 24 | bool ON_STA_FILTER(AsyncWebServerRequest *request) { 25 | return WiFi.localIP() == request->client()->localIP(); 26 | } 27 | 28 | bool ON_AP_FILTER(AsyncWebServerRequest *request) { 29 | return WiFi.localIP() != request->client()->localIP(); 30 | } 31 | 32 | 33 | AsyncWebServer::AsyncWebServer(uint16_t port) 34 | : _server(port) 35 | , _rewrites(LinkedList([](AsyncWebRewrite* r){ delete r; })) 36 | , _handlers(LinkedList([](AsyncWebHandler* h){ delete h; })) 37 | { 38 | _catchAllHandler = new AsyncCallbackWebHandler(); 39 | if(_catchAllHandler == NULL) 40 | return; 41 | _server.onClient([](void *s, AsyncClient* c){ 42 | if(c == NULL) 43 | return; 44 | c->setRxTimeout(3); 45 | AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c); 46 | if(r == NULL){ 47 | c->close(true); 48 | c->free(); 49 | delete c; 50 | } 51 | }, this); 52 | } 53 | 54 | AsyncWebServer::~AsyncWebServer(){ 55 | reset(); 56 | end(); 57 | if(_catchAllHandler) delete _catchAllHandler; 58 | } 59 | 60 | AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite){ 61 | _rewrites.add(rewrite); 62 | return *rewrite; 63 | } 64 | 65 | bool AsyncWebServer::removeRewrite(AsyncWebRewrite *rewrite){ 66 | return _rewrites.remove(rewrite); 67 | } 68 | 69 | AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to){ 70 | return addRewrite(new AsyncWebRewrite(from, to)); 71 | } 72 | 73 | AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler){ 74 | _handlers.add(handler); 75 | return *handler; 76 | } 77 | 78 | bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){ 79 | return _handlers.remove(handler); 80 | } 81 | 82 | void AsyncWebServer::begin(){ 83 | _server.setNoDelay(true); 84 | _server.begin(); 85 | } 86 | 87 | void AsyncWebServer::end(){ 88 | _server.end(); 89 | } 90 | 91 | #if ASYNC_TCP_SSL_ENABLED 92 | void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg){ 93 | _server.onSslFileRequest(cb, arg); 94 | } 95 | 96 | void AsyncWebServer::beginSecure(const char *cert, const char *key, const char *password){ 97 | _server.beginSecure(cert, key, password); 98 | } 99 | #endif 100 | 101 | void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){ 102 | delete request; 103 | } 104 | 105 | void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){ 106 | for(const auto& r: _rewrites){ 107 | if (r->match(request)){ 108 | request->_url = r->toUrl(); 109 | request->_addGetParams(r->params()); 110 | } 111 | } 112 | } 113 | 114 | void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ 115 | for(const auto& h: _handlers){ 116 | if (h->filter(request) && h->canHandle(request)){ 117 | request->setHandler(h); 118 | return; 119 | } 120 | } 121 | 122 | request->addInterestingHeader("ANY"); 123 | request->setHandler(_catchAllHandler); 124 | } 125 | 126 | 127 | AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ 128 | AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); 129 | handler->setUri(uri); 130 | handler->setMethod(method); 131 | handler->onRequest(onRequest); 132 | handler->onUpload(onUpload); 133 | handler->onBody(onBody); 134 | addHandler(handler); 135 | return *handler; 136 | } 137 | 138 | AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){ 139 | AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); 140 | handler->setUri(uri); 141 | handler->setMethod(method); 142 | handler->onRequest(onRequest); 143 | handler->onUpload(onUpload); 144 | addHandler(handler); 145 | return *handler; 146 | } 147 | 148 | AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){ 149 | AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); 150 | handler->setUri(uri); 151 | handler->setMethod(method); 152 | handler->onRequest(onRequest); 153 | addHandler(handler); 154 | return *handler; 155 | } 156 | 157 | AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){ 158 | AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); 159 | handler->setUri(uri); 160 | handler->onRequest(onRequest); 161 | addHandler(handler); 162 | return *handler; 163 | } 164 | 165 | AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control){ 166 | AsyncStaticWebHandler* handler = new AsyncStaticWebHandler(uri, fs, path, cache_control); 167 | addHandler(handler); 168 | return *handler; 169 | } 170 | 171 | void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){ 172 | _catchAllHandler->onRequest(fn); 173 | } 174 | 175 | void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn){ 176 | _catchAllHandler->onUpload(fn); 177 | } 178 | 179 | void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn){ 180 | _catchAllHandler->onBody(fn); 181 | } 182 | 183 | void AsyncWebServer::reset(){ 184 | _rewrites.free(); 185 | _handlers.free(); 186 | 187 | if (_catchAllHandler != NULL){ 188 | _catchAllHandler->onRequest(NULL); 189 | _catchAllHandler->onUpload(NULL); 190 | _catchAllHandler->onBody(NULL); 191 | } 192 | } 193 | 194 | -------------------------------------------------------------------------------- /lib/ESPAsyncWebServer/src/edit.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ESP Editor 6 | 135 | 609 | 610 | 618 | 619 | 620 |
621 |
622 |
623 |
624 | 625 | 626 | 627 | 628 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .piolibdeps 3 | .clang_complete 4 | .gcc-flags.json 5 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < http://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < http://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choice one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to by used as a library with examples 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/README.md: -------------------------------------------------------------------------------- 1 | # TB6612FNG_ESP32 2 | Sparkfun library adapted for working on esp32 3 | 4 | Source: 5 | https://github.com/sparkfun/SparkFun_TB6612FNG_Arduino_Library 6 | https://github.com/vincasmiliunas/ESP32-Arduino-TB6612FNG 7 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/examples/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // Pins for all inputs, keep in mind the PWM defines must be on PWM pins 4 | // the default pins listed are the ones used on the Redbot (ROB-12097) with 5 | // the exception of STBY which the Redbot controls with a physical switch/* 6 | #define AIN1 2 7 | #define BIN1 7 8 | #define AIN2 4 9 | #define BIN2 8 10 | #define PWMA T0 11 | #define PWMB T2 12 | #define STBY 9 13 | 14 | 15 | // these constants are used to allow you to make your motor configuration 16 | // line up with function names like forward. Value can be 1 or -1 17 | const int offsetA = 1; 18 | const int offsetB = 1; 19 | 20 | Motor motor1 = Motor(AIN1, AIN2, PWMA, offsetA, STBY,5000 ,8,1 ); 21 | Motor motor2 = Motor(BIN1, BIN2, PWMB, offsetB, STBY,5000 ,8,2 ); 22 | 23 | // Initializing motors. The library will allow you to initialize as many 24 | // motors as you have memory for. If you are using functions like forward 25 | // that take 2 motors as arguements you can either write new functions or 26 | // call the function more than once. 27 | 28 | 29 | void setup() 30 | { 31 | 32 | } 33 | 34 | void loop() 35 | { 36 | 37 | 38 | //Use of the drive function which takes as arguements the speed 39 | //and optional duration. A negative speed will cause it to go 40 | //backwards. Speed can be from -255 to 255. Also use of the 41 | //brake function which takes no arguements. 42 | motor1.drive(255,1000); 43 | motor1.drive(-255,1000); 44 | motor1.brake(); 45 | delay(1000); 46 | 47 | //Use of the drive function which takes as arguements the speed 48 | //and optional duration. A negative speed will cause it to go 49 | //backwards. Speed can be from -255 to 255. Also use of the 50 | //brake function which takes no arguements. 51 | motor2.drive(255,1000); 52 | motor2.drive(-255,1000); 53 | motor2.brake(); 54 | delay(1000); 55 | 56 | //Use of the forward function, which takes as arguements two motors 57 | //and optionally a speed. If a negative number is used for speed 58 | //it will go backwards 59 | forward(motor1, motor2, 150); 60 | delay(1000); 61 | 62 | //Use of the back function, which takes as arguments two motors 63 | //and optionally a speed. Either a positive number or a negative 64 | //number for speed will cause it to go backwards 65 | back(motor1, motor2, -150); 66 | delay(1000); 67 | 68 | //Use of the brake function which takes as arguments two motors. 69 | //Note that functions do not stop motors on their own. 70 | brake(motor1, motor2); 71 | delay(1000); 72 | 73 | //Use of the left and right functions which take as arguements two 74 | //motors and a speed. This function turns both motors to move in 75 | //the appropriate direction. For turning a single motor use drive. 76 | left(motor1, motor2, 100); 77 | delay(1000); 78 | right(motor1, motor2, 100); 79 | delay(1000); 80 | 81 | //Use of brake again. 82 | brake(motor1, motor2); 83 | delay(1000); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/examples/motors/motors.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // Pins for all inputs, keep in mind the PWM defines must be on PWM pins 4 | // the default pins listed are the ones used on the Redbot (ROB-12097) with 5 | // the exception of STBY which the Redbot controls with a physical switch/* 6 | #define AIN1 2 7 | #define BIN1 7 8 | #define AIN2 4 9 | #define BIN2 8 10 | #define PWMA T0 11 | #define PWMB T2 12 | #define STBY 9 13 | 14 | 15 | // these constants are used to allow you to make your motor configuration 16 | // line up with function names like forward. Value can be 1 or -1 17 | const int offsetA = 1; 18 | const int offsetB = 1; 19 | 20 | Motor motor1 = Motor(AIN1, AIN2, PWMA, offsetA, STBY,5000 ,8,1 ); 21 | Motor motor2 = Motor(BIN1, BIN2, PWMB, offsetB, STBY,5000 ,8,2 ); 22 | 23 | // Initializing motors. The library will allow you to initialize as many 24 | // motors as you have memory for. If you are using functions like forward 25 | // that take 2 motors as arguements you can either write new functions or 26 | // call the function more than once. 27 | 28 | 29 | void setup() 30 | { 31 | 32 | } 33 | 34 | void loop() 35 | { 36 | 37 | 38 | //Use of the drive function which takes as arguements the speed 39 | //and optional duration. A negative speed will cause it to go 40 | //backwards. Speed can be from -255 to 255. Also use of the 41 | //brake function which takes no arguements. 42 | motor1.drive(255,1000); 43 | motor1.drive(-255,1000); 44 | motor1.brake(); 45 | delay(1000); 46 | 47 | //Use of the drive function which takes as arguements the speed 48 | //and optional duration. A negative speed will cause it to go 49 | //backwards. Speed can be from -255 to 255. Also use of the 50 | //brake function which takes no arguements. 51 | motor2.drive(255,1000); 52 | motor2.drive(-255,1000); 53 | motor2.brake(); 54 | delay(1000); 55 | 56 | //Use of the forward function, which takes as arguements two motors 57 | //and optionally a speed. If a negative number is used for speed 58 | //it will go backwards 59 | forward(motor1, motor2, 150); 60 | delay(1000); 61 | 62 | //Use of the back function, which takes as arguments two motors 63 | //and optionally a speed. Either a positive number or a negative 64 | //number for speed will cause it to go backwards 65 | back(motor1, motor2, -150); 66 | delay(1000); 67 | 68 | //Use of the brake function which takes as arguments two motors. 69 | //Note that functions do not stop motors on their own. 70 | brake(motor1, motor2); 71 | delay(1000); 72 | 73 | //Use of the left and right functions which take as arguements two 74 | //motors and a speed. This function turns both motors to move in 75 | //the appropriate direction. For turning a single motor use drive. 76 | left(motor1, motor2, 100); 77 | delay(1000); 78 | right(motor1, motor2, 100); 79 | delay(1000); 80 | 81 | //Use of brake again. 82 | brake(motor1, motor2); 83 | delay(1000); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) http://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- readme.txt --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | Then in `src/main.c` you should use: 31 | 32 | #include 33 | #include 34 | 35 | // rest H/C/CPP code 36 | 37 | PlatformIO will find your libraries automatically, configure preprocessor's 38 | include paths and build them. 39 | 40 | More information about PlatformIO Library Dependency Finder 41 | - http://docs.platformio.org/page/librarymanager/ldf.html 42 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/library.properties: -------------------------------------------------------------------------------- 1 | name=TB6612FNG_ESP32 2 | version=0.0.1 3 | author=Pablopeza 4 | maintainer=Pablopeza 5 | sentence=Allows control of 2 DC motors, using two input signals. 6 | paragraph=Individually control motor outputs of 2 DC motors at 1.2A constant current. There are four function modes, including: CW, CCW, short-brake, and stop. 7 | category=Device Control 8 | url=https://github.com/pablopeza/TB6612FNG_ESP32 9 | architectures=esp32 10 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32doit-devkit-v1] 12 | platform = espressif32 13 | board = esp32doit-devkit-v1 14 | framework = arduino 15 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/src/TB6612_ESP32.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | ******************************************************************************/ 4 | 5 | #include "TB6612_ESP32.h" 6 | #include 7 | #include 8 | Motor::Motor(int In1pin, int In2pin, int PWMpin, int offset, int STBYpin, int freq, int resolution, int channel_pin) 9 | { 10 | In1 = In1pin; 11 | In2 = In2pin; 12 | PWM = PWMpin; 13 | Standby = STBYpin; 14 | Offset = offset; 15 | Channel=channel_pin; 16 | 17 | pinMode(In1, OUTPUT); 18 | pinMode(In2, OUTPUT); 19 | pinMode(PWMpin, OUTPUT); 20 | pinMode(Standby, OUTPUT); 21 | 22 | ledcSetup(Channel, freq, resolution); 23 | ledcAttachPin(PWM, Channel); 24 | 25 | } 26 | 27 | void Motor::drive(int speed) 28 | { 29 | digitalWrite(Standby, HIGH); 30 | speed = speed * Offset; 31 | if (speed>=0) fwd(speed); 32 | else rev(-speed); 33 | } 34 | void Motor::drive(int speed, int duration) 35 | { 36 | drive(speed); 37 | delay(duration); 38 | } 39 | 40 | void Motor::fwd(int speed) 41 | { 42 | digitalWrite(In1, HIGH); 43 | digitalWrite(In2, LOW); 44 | ledcWrite(Channel, speed); 45 | 46 | } 47 | 48 | void Motor::rev(int speed) 49 | { 50 | digitalWrite(In1, LOW); 51 | digitalWrite(In2, HIGH); 52 | ledcWrite(Channel, speed); 53 | } 54 | 55 | void Motor::brake() 56 | { 57 | digitalWrite(In1, HIGH); 58 | digitalWrite(In2, HIGH); 59 | ledcWrite(Channel, 0); 60 | } 61 | 62 | void Motor::standby() 63 | { 64 | digitalWrite(Standby, LOW); 65 | } 66 | 67 | void forward(Motor motor1, Motor motor2, int speed) 68 | { 69 | motor1.drive(speed); 70 | motor2.drive(speed); 71 | } 72 | void forward(Motor motor1, Motor motor2) 73 | { 74 | motor1.drive(DEFAULTSPEED); 75 | motor2.drive(DEFAULTSPEED); 76 | } 77 | 78 | 79 | void back(Motor motor1, Motor motor2, int speed) 80 | { 81 | int temp = abs(speed); 82 | motor1.drive(-temp); 83 | motor2.drive(-temp); 84 | } 85 | void back(Motor motor1, Motor motor2) 86 | { 87 | motor1.drive(-DEFAULTSPEED); 88 | motor2.drive(-DEFAULTSPEED); 89 | } 90 | void left(Motor left, Motor right, int speed) 91 | { 92 | int temp = abs(speed)/2; 93 | left.drive(-temp); 94 | right.drive(temp); 95 | 96 | } 97 | 98 | 99 | void right(Motor left, Motor right, int speed) 100 | { 101 | int temp = abs(speed)/2; 102 | left.drive(temp); 103 | right.drive(-temp); 104 | 105 | } 106 | void brake(Motor motor1, Motor motor2) 107 | { 108 | motor1.brake(); 109 | motor2.brake(); 110 | } 111 | -------------------------------------------------------------------------------- /lib/TB6612FNG_ESP32/src/TB6612_ESP32.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | ******************************************************************************/ 4 | 5 | #include 6 | #include 7 | //used in some functions so you don't have to send a speed 8 | #define DEFAULTSPEED 255 9 | 10 | 11 | 12 | class Motor 13 | { 14 | public: 15 | // Constructor. Mainly sets up pins. 16 | Motor(int In1pin, int In2pin, int PWMpin, int offset, int STBYpin,int freq, int resolution, int channel_pin); 17 | 18 | // Drive in direction given by sign, at speed given by magnitude of the 19 | //parameter. 20 | void drive(int speed); 21 | 22 | // drive(), but with a delay(duration) 23 | void drive(int speed, int duration); 24 | 25 | //currently not implemented 26 | //void stop(); // Stop motors, but allow them to coast to a halt. 27 | //void coast(); // Stop motors, but allow them to coast to a halt. 28 | 29 | //Stops motor by setting both input pins high 30 | void brake(); 31 | 32 | //set the chip to standby mode. The drive function takes it out of standby 33 | //(forward, back, left, and right all call drive) 34 | void standby(); 35 | 36 | private: 37 | //variables for the 2 inputs, PWM input, Offset value, and the Standby pin 38 | int In1, In2, PWM, Offset,Standby,Channel; 39 | 40 | //private functions that spin the motor CC and CCW 41 | void fwd(int speed); 42 | void rev(int speed); 43 | 44 | 45 | }; 46 | 47 | //Takes 2 motors and goes forward, if it does not go forward adjust offset 48 | //values until it does. These will also take a negative number and go backwards 49 | //There is also an optional speed input, if speed is not used, the function will 50 | //use the DEFAULTSPEED constant. 51 | void forward(Motor motor1, Motor motor2, int speed); 52 | void forward(Motor motor1, Motor motor2); 53 | 54 | //Similar to forward, will take 2 motors and go backwards. This will take either 55 | //a positive or negative number and will go backwards either way. Once again the 56 | //speed input is optional and will use DEFAULTSPEED if it is not defined. 57 | void back(Motor motor1, Motor motor2, int speed); 58 | void back(Motor motor1, Motor motor2); 59 | 60 | //Left and right take 2 motors, and it is important the order they are sent. 61 | //The left motor should be on the left side of the bot. These functions 62 | //also take a speed value 63 | void left(Motor left, Motor right, int speed); 64 | void right(Motor left, Motor right, int speed); 65 | 66 | //This function takes 2 motors and and brakes them 67 | void brake(Motor motor1, Motor motor2); 68 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | /* 3 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp 4 | Ported to Arduino ESP32 by Evandro Copercini 5 | Adapted by Manos Zeakis for ESP32 and TB6612FNG 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define AIN1 13 15 | #define BIN1 12 16 | #define AIN2 14 17 | #define BIN2 27 18 | #define PWMA 26 19 | #define PWMB 25 20 | #define STBY 17 21 | 22 | const int offsetA = 1; 23 | const int offsetB = -1; 24 | 25 | Motor motor1 = Motor(AIN1, AIN2, PWMA, offsetA, STBY,5000 ,8,1 ); 26 | Motor motor2 = Motor(BIN1, BIN2, PWMB, offsetB, STBY,5000 ,8,2 ); 27 | 28 | BLECharacteristic *pCharacteristic; 29 | bool deviceConnected = false; 30 | 31 | #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID 32 | #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 33 | #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" 34 | 35 | class MyServerCallbacks: public BLEServerCallbacks { 36 | void onConnect(BLEServer* pServer) { 37 | deviceConnected = true; 38 | }; 39 | 40 | void onDisconnect(BLEServer* pServer) { 41 | deviceConnected = false; 42 | } 43 | }; 44 | 45 | class MyCallbacks: public BLECharacteristicCallbacks { 46 | void onWrite(BLECharacteristic *pCharacteristic) { 47 | std::string rxValue = pCharacteristic->getValue(); 48 | 49 | if (rxValue.length() > 0) { 50 | Serial.println("*********"); 51 | Serial.print("Received Value: "); 52 | 53 | for (int i = 0; i < rxValue.length(); i++) { 54 | Serial.print(rxValue[i]); 55 | } 56 | 57 | Serial.println(); 58 | 59 | if (rxValue.find("A") != -1) { 60 | Serial.println("front"); 61 | forward(motor1, motor2, 50); 62 | delay(1000); 63 | brake(motor1, motor2); 64 | } 65 | else if (rxValue.find("B") != -1) { 66 | Serial.println("back"); 67 | back(motor1, motor2, -50); 68 | delay(1000); 69 | brake(motor1, motor2); 70 | } 71 | else if (rxValue.find("C") != -1) { 72 | Serial.println("right"); 73 | right(motor1, motor2, 150); 74 | delay(600); 75 | brake(motor1, motor2); 76 | } 77 | else if (rxValue.find("D") != -1) { 78 | Serial.println("left"); 79 | left(motor1, motor2, 150); 80 | delay(600); 81 | brake(motor1, motor2); 82 | } 83 | else if (rxValue.find("E") != -1) { 84 | Serial.println("left"); 85 | right(motor1, motor2, 150); 86 | delay(2400); 87 | brake(motor1, motor2); 88 | } Serial.println(); 89 | Serial.println("*********"); 90 | } 91 | } 92 | }; 93 | 94 | void setup() { 95 | Serial.begin(115200); 96 | 97 | BLEDevice::init("Raidho"); // Give it a name 98 | 99 | BLEServer *pServer = BLEDevice::createServer(); 100 | pServer->setCallbacks(new MyServerCallbacks()); 101 | 102 | BLEService *pService = pServer->createService(SERVICE_UUID); 103 | 104 | pCharacteristic = pService->createCharacteristic( 105 | CHARACTERISTIC_UUID_TX, 106 | BLECharacteristic::PROPERTY_NOTIFY 107 | ); 108 | 109 | pCharacteristic->addDescriptor(new BLE2902()); 110 | 111 | BLECharacteristic *pCharacteristic = pService->createCharacteristic( 112 | CHARACTERISTIC_UUID_RX, 113 | BLECharacteristic::PROPERTY_WRITE 114 | ); 115 | 116 | pCharacteristic->setCallbacks(new MyCallbacks()); 117 | 118 | pService->start(); 119 | 120 | pServer->getAdvertising()->start(); 121 | Serial.println("Waiting a client connection to notify..."); 122 | } 123 | 124 | void loop() { 125 | } -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32dev] 12 | platform = espressif32 13 | board = esp32dev 14 | framework = arduino 15 | lib_deps = ArduinoWebsockets 16 | AsyncTCP 17 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | const char* ssid = "ESP32_ROBv1"; //Enter SSID 2 | const char* password = "yourpasswd"; //Enter Password 3 | 4 | #define AIN1 13 5 | #define BIN1 12 6 | #define AIN2 14 7 | #define BIN2 25 8 | #define PWMA 26 9 | #define PWMB 27 10 | #define STBY 17 11 | 12 | // these constants are used to allow you to make your motor configuration 13 | // line up with function names like forward. Value can be 1 or -1 14 | const int offsetA = 1; 15 | const int offsetB = 1; 16 | 17 | Motor motor2 = Motor(AIN1, AIN2, PWMA, offsetA, STBY,5000 ,8,1 ); 18 | Motor motor1 = Motor(BIN1, BIN2, PWMB, offsetB, STBY,5000 ,8,2 ); 19 | 20 | using namespace websockets; 21 | WebsocketsServer server; 22 | AsyncWebServer webserver(80); 23 | 24 | int LValue, RValue, commaIndex; -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Arduino.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "config.h" 9 | #include "web.h" 10 | 11 | /** ESP32 robot tank with wifi and one joystick web control sketch. 12 | Based on SMARS modular robot project using esp32 and tb6612. 13 | https://www.thingiverse.com/thing:2662828 14 | 15 | for complete complete program: https://github.com/nkmakes/SMARS-esp32 16 | 17 | Made by nkmakes.github.io, August 2020. 18 | 19 | ----------------------------------------- 20 | Camera stream based upon: 21 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp 22 | Ported to Arduino ESP32 by Evandro Copercini 23 | Adapted by Manos Zeakis for ESP32 and TB6612FNG 24 | */ 25 | 26 | void setup() 27 | { 28 | Serial.begin(9600); 29 | 30 | // Create AP 31 | WiFi.softAP(ssid, password); 32 | IPAddress IP = WiFi.softAPIP(); 33 | Serial.print("AP IP address: "); 34 | Serial.println(IP); 35 | 36 | // HTTP handler assignment 37 | webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { 38 | AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz)); 39 | response->addHeader("Content-Encoding", "gzip"); 40 | request->send(response); 41 | }); 42 | 43 | // start server 44 | webserver.begin(); 45 | server.listen(82); 46 | Serial.print("Is server live? "); 47 | Serial.println(server.available()); 48 | 49 | } 50 | 51 | // handle http messages 52 | void handle_message(WebsocketsMessage msg) { 53 | commaIndex = msg.data().indexOf(','); 54 | LValue = msg.data().substring(0, commaIndex).toInt(); 55 | RValue = msg.data().substring(commaIndex + 1).toInt(); 56 | motor1.drive(LValue); 57 | motor2.drive(RValue); 58 | } 59 | 60 | void loop() 61 | { 62 | auto client = server.accept(); 63 | client.onMessage(handle_message); 64 | while (client.available()) { 65 | client.poll(); 66 | } 67 | } -------------------------------------------------------------------------------- /src/web.h: -------------------------------------------------------------------------------- 1 | const uint8_t index_html_gz[] = { 0x1f, 0x8b, 0x08, 0x08, 0x62, 0x90, 0x32, 0x5f, 0x00, 0xff, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x2e, 0x67, 0x7a, 0x00, 0xbd, 0x59, 0x7d, 0x53, 0xdb, 0x38, 0xb7, 0xff, 0x7f, 0x3f, 0x85, 0x9a, 0xce, 0x53, 0x6c, 0x70, 0x1c, 0x27, 0x2c, 0xbb, 0xdd, 0x14, 0xc3, 0xb4, 0x40, 0xb9, 0xbd, 0x43, 0x77, 0x19, 0xc2, 0x5d, 0x60, 0x9e, 0xb9, 0xc3, 0x08, 0x5b, 0x49, 0xdc, 0x3a, 0x96, 0xc7, 0x96, 0x13, 0xd8, 0x96, 0xef, 0xbe, 0x3f, 0x49, 0x7e, 0x8b, 0x23, 0xa0, 0x7b, 0xe7, 0x99, 0x9b, 0x99, 0x24, 0x96, 0xce, 0x8b, 0xce, 0x9b, 0xce, 0x39, 0x92, 0xf7, 0x5f, 0x1d, 0xff, 0x71, 0x74, 0x79, 0x73, 0x7e, 0x42, 0xe6, 0x62, 0x11, 0x1f, 0xfc, 0xf4, 0xd3, 0xbe, 0xfe, 0x27, 0xf8, 0xec, 0xcf, 0x19, 0x0d, 0xf5, 0xa3, 0x1a, 0x2e, 0x98, 0xa0, 0x24, 0xa1, 0x0b, 0xe6, 0x6f, 0x2d, 0x23, 0xb6, 0x4a, 0x79, 0x26, 0xb6, 0x2a, 0x20, 0x09, 0x78, 0x22, 0x58, 0x22, 0xfc, 0xad, 0x55, 0x14, 0x8a, 0xb9, 0x1f, 0xb2, 0x65, 0x14, 0xb0, 0xbe, 0x1a, 0x38, 0x35, 0x52, 0x94, 0x44, 0x22, 0xa2, 0x71, 0x3f, 0x0f, 0x68, 0xcc, 0xfc, 0xa1, 0xeb, 0x35, 0xa0, 0x22, 0x67, 0x99, 0x9a, 0xa7, 0x77, 0x00, 0x25, 0x7c, 0x8b, 0x0c, 0xba, 0x4b, 0x07, 0x73, 0x9a, 0xe5, 0x4c, 0xf8, 0xbd, 0x42, 0x4c, 0xfb, 0x6f, 0x7b, 0x80, 0x2b, 0x84, 0x06, 0x4b, 0x44, 0x22, 0x66, 0x07, 0xff, 0xcd, 0x1f, 0x72, 0x11, 0x05, 0x5f, 0x89, 0x60, 0xb9, 0xd8, 0x1f, 0xe8, 0xc9, 0x1a, 0x69, 0xf3, 0x61, 0x3f, 0x17, 0x0f, 0x6d, 0x8c, 0xd7, 0x52, 0x15, 0x1a, 0x25, 0x2c, 0x23, 0xdf, 0xea, 0x49, 0xf5, 0x51, 0xda, 0x8c, 0xc9, 0xd0, 0xf3, 0xfe, 0xf5, 0x6e, 0x1d, 0x32, 0x67, 0xd1, 0x6c, 0x2e, 0xc6, 0xe4, 0xe7, 0xdf, 0x96, 0xf3, 0x0e, 0xe8, 0x8e, 0x06, 0x5f, 0x67, 0x19, 0x2f, 0x92, 0xb0, 0x1f, 0xf0, 0x98, 0x67, 0x63, 0xf2, 0x7a, 0x77, 0x77, 0xb7, 0x83, 0x14, 0x46, 0x79, 0x1a, 0xd3, 0x87, 0x31, 0x99, 0xc6, 0xec, 0xbe, 0x03, 0xa3, 0x71, 0x34, 0x4b, 0xfa, 0x91, 0x60, 0x8b, 0x7c, 0x4c, 0x02, 0xd8, 0x98, 0x65, 0x1d, 0x8c, 0x2f, 0x05, 0x14, 0x9e, 0x3e, 0x80, 0xbf, 0xf2, 0xc1, 0x13, 0x58, 0x7c, 0xc9, 0xb2, 0x69, 0xcc, 0x57, 0x63, 0x32, 0x8f, 0xc2, 0x90, 0x25, 0x5d, 0x39, 0x79, 0x16, 0xc2, 0x05, 0x19, 0x0d, 0xa3, 0x02, 0x0b, 0xfd, 0x9a, 0x76, 0xe5, 0x10, 0xbc, 0x08, 0xe6, 0x7d, 0x1a, 0x88, 0x88, 0x27, 0x63, 0x92, 0xf0, 0x84, 0x35, 0x08, 0x8f, 0x0d, 0xea, 0x6b, 0x29, 0xe9, 0xd3, 0x96, 0xdb, 0x60, 0x5b, 0x99, 0xce, 0x04, 0xdb, 0xb4, 0x5d, 0x36, 0xbb, 0xb3, 0x46, 0x3f, 0xef, 0x39, 0x64, 0xb4, 0x8b, 0xe0, 0xf9, 0xed, 0x37, 0xdb, 0xa8, 0x85, 0xe4, 0x96, 0xde, 0x93, 0x9c, 0xc7, 0x51, 0x28, 0x49, 0xa8, 0x35, 0xdc, 0xfd, 0xc5, 0x21, 0xcd, 0x8f, 0xbb, 0x67, 0x26, 0xac, 0xd5, 0xdf, 0xdb, 0x70, 0xf1, 0x73, 0xea, 0xb7, 0x22, 0x98, 0xc5, 0x2c, 0x80, 0x36, 0xcf, 0x9b, 0x67, 0x2c, 0xd9, 0x2c, 0x59, 0xd7, 0x4a, 0x46, 0x75, 0x21, 0xfb, 0x2f, 0x6f, 0xa1, 0xef, 0x50, 0xfe, 0x8c, 0xa0, 0x34, 0xb6, 0x8d, 0xd7, 0x92, 0x7e, 0x83, 0xf7, 0x5c, 0x3a, 0xba, 0xcb, 0x3a, 0x28, 0xb2, 0x5c, 0x32, 0x4c, 0x79, 0x64, 0x08, 0x8d, 0x52, 0xf9, 0xd2, 0x4b, 0xa3, 0x35, 0x47, 0xb4, 0xf9, 0xd3, 0x8c, 0xd1, 0x2e, 0xe7, 0x94, 0xe7, 0xd8, 0xd4, 0xd2, 0x26, 0xd3, 0xe8, 0x9e, 0x85, 0x1d, 0xce, 0x99, 0x76, 0xae, 0xb7, 0x61, 0xcc, 0x74, 0x6d, 0xf2, 0x51, 0x6f, 0x65, 0xb5, 0x1d, 0x07, 0x9d, 0xfd, 0x68, 0xda, 0xb1, 0x41, 0x16, 0xa5, 0x82, 0x88, 0x87, 0x94, 0xf9, 0x3d, 0xc1, 0xee, 0xc5, 0xe0, 0x0b, 0x5d, 0x52, 0x3d, 0xdb, 0x6b, 0x28, 0x97, 0x34, 0x23, 0xc8, 0x06, 0x13, 0x99, 0x0d, 0xfc, 0x69, 0x91, 0x28, 0xdf, 0x59, 0xc2, 0x61, 0xf6, 0x37, 0x09, 0x8a, 0xfc, 0x25, 0x47, 0x7c, 0x78, 0xbe, 0xef, 0x5b, 0xcc, 0x67, 0xdf, 0xbf, 0x7f, 0x7b, 0xb4, 0x5d, 0x95, 0x2e, 0x0e, 0x7b, 0x5f, 0xca, 0x24, 0xd2, 0x1b, 0x33, 0x3d, 0xe5, 0x24, 0x0d, 0x36, 0x73, 0x95, 0xa5, 0x0e, 0x3d, 0x00, 0x75, 0x86, 0xe3, 0x6d, 0xa0, 0x8e, 0x68, 0x05, 0xd5, 0x8f, 0xce, 0xbc, 0x0d, 0x56, 0x0e, 0x48, 0x68, 0xfc, 0x31, 0x8a, 0xe3, 0x23, 0xe9, 0xe6, 0xc3, 0xde, 0x6b, 0xcf, 0x7b, 0xff, 0xde, 0xf3, 0xe4, 0x62, 0x1b, 0x50, 0x27, 0x33, 0x11, 0x9f, 0x21, 0x3f, 0x5d, 0x29, 0x21, 0x46, 0x2d, 0xa2, 0x7a, 0xd6, 0x09, 0x4d, 0x44, 0x13, 0x91, 0xf1, 0xaf, 0xac, 0x59, 0x73, 0x77, 0x77, 0x7d, 0xcd, 0x16, 0xdc, 0xa1, 0x6d, 0x06, 0xb0, 0xb0, 0x61, 0xd5, 0x8d, 0x59, 0x27, 0x36, 0x11, 0x75, 0x57, 0x7d, 0xeb, 0xe9, 0x55, 0x0d, 0x70, 0x27, 0xf0, 0x43, 0x1e, 0x14, 0x0b, 0xa4, 0x2f, 0x77, 0xc6, 0xc4, 0x49, 0xcc, 0xe4, 0xe3, 0x87, 0x87, 0x4f, 0xa1, 0x25, 0x6c, 0xa7, 0x68, 0x80, 0x01, 0x02, 0x51, 0xb0, 0x12, 0x6e, 0xf5, 0x02, 0x9a, 0xc0, 0xfd, 0x3d, 0xfb, 0x5d, 0xe1, 0x46, 0xa1, 0x1f, 0x39, 0x10, 0x20, 0x79, 0xf3, 0xc6, 0x4a, 0xfc, 0xc0, 0x0d, 0xe2, 0x08, 0x28, 0x4a, 0x3c, 0x5b, 0xce, 0x73, 0xcc, 0xf3, 0x7a, 0xfe, 0xbf, 0x94, 0x7f, 0xc0, 0x5a, 0xfb, 0xd1, 0x4f, 0xf0, 0xa4, 0x7d, 0xe6, 0x73, 0x27, 0x70, 0x69, 0x9a, 0xb2, 0x24, 0x3c, 0x9a, 0x47, 0x71, 0x68, 0x15, 0xf6, 0x3b, 0x19, 0x34, 0xb9, 0x5f, 0x48, 0xd1, 0x8e, 0x64, 0xaa, 0xbd, 0xc7, 0xd2, 0xa3, 0xb0, 0x67, 0x3b, 0x53, 0xdf, 0x73, 0x96, 0xfe, 0x68, 0xfb, 0x33, 0x15, 0x73, 0xf7, 0xfc, 0x93, 0x33, 0xf3, 0xad, 0x92, 0x63, 0x7f, 0x38, 0xf4, 0xec, 0xc1, 0xc8, 0x59, 0xf9, 0xb3, 0x9d, 0x3d, 0xe7, 0x08, 0xbf, 0xc8, 0x5b, 0x0b, 0xf0, 0x50, 0x50, 0x00, 0x52, 0x3c, 0xeb, 0x15, 0x31, 0x38, 0xab, 0x01, 0x43, 0xcf, 0x39, 0xf1, 0xfb, 0xc3, 0xed, 0x33, 0x67, 0xd2, 0x20, 0x60, 0xf2, 0xab, 0x9c, 0x9c, 0x38, 0x57, 0xfe, 0xc2, 0x39, 0xf5, 0xd3, 0x77, 0x55, 0x50, 0x93, 0x7b, 0xcb, 0xfe, 0x96, 0xbb, 0x77, 0x6c, 0x16, 0x25, 0xe7, 0x10, 0xc2, 0xb2, 0x9d, 0xdc, 0xa5, 0x59, 0x60, 0x2d, 0x9c, 0xd4, 0x39, 0x72, 0x20, 0x9d, 0xf3, 0x6a, 0x28, 0xe7, 0xe2, 0xca, 0x57, 0x3e, 0xc5, 0x28, 0x57, 0xa6, 0x9f, 0xc8, 0xfd, 0xe6, 0xc7, 0xf5, 0xd8, 0xb2, 0x1f, 0x6b, 0xbe, 0x0f, 0x1b, 0x7c, 0xaf, 0xf6, 0x67, 0x30, 0xe1, 0x95, 0xbf, 0xc2, 0xe3, 0xce, 0xec, 0xa0, 0x14, 0x58, 0x4d, 0x55, 0x3a, 0x03, 0x74, 0xaa, 0xb0, 0x4e, 0x25, 0xd6, 0xa9, 0xc2, 0xd2, 0x2a, 0xa8, 0xb9, 0x6a, 0x20, 0xf1, 0xb4, 0x94, 0x57, 0xce, 0xa9, 0x33, 0xab, 0xa4, 0x54, 0x66, 0x16, 0x7e, 0x5e, 0x3a, 0xf9, 0x02, 0x19, 0x99, 0xc6, 0xa7, 0x32, 0x31, 0x4b, 0x5f, 0x4b, 0x85, 0xf6, 0x1c, 0xf9, 0x3b, 0x92, 0x69, 0x50, 0xb8, 0x34, 0x0c, 0x55, 0xec, 0x4c, 0x90, 0x53, 0x2c, 0xcf, 0x81, 0x97, 0x3b, 0x73, 0x43, 0x27, 0x94, 0xeb, 0x4c, 0xb1, 0xa1, 0xb4, 0xa6, 0xa2, 0x1c, 0x29, 0x23, 0x35, 0x06, 0xc9, 0x3a, 0x06, 0x09, 0xdb, 0x06, 0xe9, 0xc1, 0xdf, 0xb2, 0x00, 0xe4, 0x82, 0x66, 0xa2, 0x17, 0x25, 0xa4, 0x0e, 0xc5, 0xea, 0xa1, 0x0c, 0xc6, 0x43, 0x78, 0x1e, 0xcb, 0x9f, 0x2c, 0xf1, 0x7c, 0x16, 0xe5, 0xa8, 0xc7, 0x2c, 0xb3, 0x7a, 0x2d, 0x5a, 0xa7, 0x49, 0x44, 0xf6, 0xb7, 0xa9, 0x3f, 0x7c, 0x54, 0x9e, 0x79, 0x92, 0x68, 0x81, 0x6c, 0xbe, 0x4e, 0x23, 0xdc, 0x34, 0x63, 0x12, 0xf3, 0x98, 0x4d, 0x69, 0x11, 0x0b, 0xa8, 0x31, 0xf4, 0xfd, 0xa9, 0xf2, 0x80, 0x70, 0x15, 0x11, 0xcb, 0xff, 0xed, 0xfd, 0xaf, 0x9b, 0xd2, 0x19, 0xbb, 0x46, 0x98, 0x6c, 0x4c, 0xde, 0x38, 0x57, 0x7d, 0x78, 0x81, 0x4f, 0xa7, 0x68, 0xa7, 0xce, 0xd8, 0x54, 0x38, 0xa7, 0xcd, 0xf8, 0x92, 0xa7, 0x50, 0x3c, 0x88, 0x19, 0xcd, 0x2e, 0x50, 0xca, 0x60, 0x52, 0xaf, 0xda, 0x1e, 0xf5, 0xe6, 0xb0, 0x1d, 0xc4, 0x9b, 0x83, 0xd8, 0xb0, 0x5f, 0x90, 0x1e, 0xbb, 0xa7, 0xab, 0xb0, 0x57, 0x05, 0xef, 0x8f, 0xaf, 0xa2, 0x16, 0xb1, 0xc7, 0x46, 0xcb, 0x2e, 0x38, 0xea, 0x6e, 0xc8, 0x57, 0xc9, 0x3f, 0x30, 0xac, 0xa2, 0xd9, 0x34, 0x6c, 0xcb, 0x8a, 0x8d, 0xe9, 0xfe, 0xdf, 0xec, 0xa5, 0x84, 0x2a, 0xd2, 0xff, 0x98, 0xb9, 0xaa, 0x91, 0x23, 0xe6, 0x51, 0xee, 0x9e, 0x32, 0x9d, 0x03, 0x9b, 0x32, 0x68, 0x7f, 0xcb, 0x98, 0x28, 0xb2, 0x84, 0x94, 0x7c, 0x1e, 0x6b, 0x44, 0x9d, 0x14, 0x8d, 0x98, 0x7a, 0xa5, 0x06, 0xf5, 0x9c, 0xe7, 0xd7, 0x06, 0xc4, 0xab, 0x35, 0x8c, 0x1b, 0x03, 0xc6, 0x69, 0x83, 0x61, 0x60, 0x60, 0x59, 0x57, 0xfd, 0x85, 0x3d, 0x58, 0x6d, 0xa3, 0x29, 0x44, 0x49, 0xe6, 0x1f, 0x65, 0x67, 0x21, 0x15, 0xab, 0x68, 0x0c, 0x2c, 0x2d, 0xeb, 0xb4, 0x9f, 0x96, 0x34, 0xdb, 0xfd, 0xa1, 0x91, 0xec, 0x38, 0xca, 0xda, 0x84, 0x3a, 0xd1, 0xf4, 0x7a, 0x0e, 0xf3, 0xb1, 0x9e, 0x13, 0xf9, 0xe0, 0xf0, 0xae, 0x14, 0x30, 0x3a, 0xf0, 0xbf, 0xbe, 0x79, 0x13, 0xed, 0xfb, 0x13, 0x84, 0x04, 0x90, 0x8e, 0x90, 0xe6, 0xa3, 0x7d, 0x4c, 0xc9, 0xc1, 0xef, 0x72, 0x70, 0x50, 0x42, 0x26, 0x18, 0xb0, 0xfd, 0x13, 0x0c, 0x80, 0xe4, 0xfb, 0xe2, 0x10, 0x73, 0x57, 0xbd, 0xb1, 0xd8, 0x91, 0x7f, 0x00, 0x1d, 0x9c, 0xad, 0x81, 0x4e, 0x34, 0xe8, 0x04, 0x20, 0xf1, 0xf8, 0xb8, 0xde, 0x17, 0xfd, 0xb4, 0xd6, 0x06, 0xa9, 0x76, 0xa6, 0x3c, 0xe4, 0xac, 0x63, 0xd5, 0xdd, 0xd0, 0xfe, 0x40, 0x9f, 0xd1, 0xf4, 0xd4, 0xfe, 0x1d, 0x0f, 0x1f, 0x74, 0xfb, 0xd3, 0xf0, 0x09, 0xa3, 0x25, 0x41, 0x51, 0xdc, 0xe2, 0x05, 0xca, 0xad, 0x2c, 0x5b, 0xea, 0x68, 0xb3, 0xd5, 0x74, 0x49, 0x35, 0x96, 0xea, 0xbb, 0xfc, 0x5e, 0x7d, 0x96, 0xf1, 0x70, 0x96, 0xe9, 0x1d, 0xec, 0x0f, 0x00, 0x33, 0x60, 0x83, 0xa7, 0xec, 0x92, 0x8e, 0xa3, 0x65, 0xaf, 0xa2, 0xd4, 0xfd, 0x23, 0xf2, 0x32, 0xfa, 0xc7, 0x92, 0x8b, 0x1e, 0x2c, 0x68, 0x86, 0x02, 0x32, 0xa6, 0x85, 0xe0, 0x26, 0x8e, 0x2d, 0xa5, 0x15, 0xa4, 0xdb, 0xe8, 0x55, 0xfa, 0x95, 0xe7, 0xcc, 0x5c, 0x10, 0x79, 0xfe, 0x24, 0x7e, 0x93, 0x84, 0x3b, 0xcd, 0xc2, 0x16, 0xf2, 0x36, 0xa3, 0x8b, 0xad, 0x4e, 0x93, 0xaf, 0x69, 0xaf, 0x26, 0xb7, 0xff, 0x73, 0x71, 0x06, 0xea, 0xde, 0x2a, 0x1f, 0x0f, 0x06, 0x3d, 0xb2, 0x83, 0xe3, 0x49, 0x82, 0x14, 0xe2, 0xc6, 0x3c, 0xa0, 0x32, 0x34, 0xdc, 0x39, 0x07, 0xde, 0x0e, 0xe9, 0x8d, 0xdf, 0x8e, 0x7a, 0x26, 0x16, 0xab, 0x1c, 0xe4, 0x09, 0x44, 0xb8, 0x62, 0x77, 0x13, 0x1e, 0x7c, 0x65, 0xc2, 0xd2, 0x5c, 0xb1, 0xe0, 0x1a, 0xfa, 0x2a, 0x77, 0x79, 0xb2, 0x60, 0x79, 0x8e, 0x2c, 0x02, 0x92, 0xfa, 0xe9, 0xa0, 0xdb, 0x45, 0xcb, 0xc3, 0xf1, 0x94, 0x58, 0x25, 0x82, 0x1b, 0x52, 0x9c, 0x77, 0x23, 0x2c, 0x45, 0x93, 0x80, 0xf1, 0x29, 0xf9, 0x10, 0xf3, 0x3b, 0xdb, 0x40, 0xa3, 0x7b, 0xdc, 0x22, 0x8b, 0xff, 0xb8, 0xfb, 0x82, 0xbc, 0x80, 0x25, 0x20, 0x44, 0x59, 0x38, 0xf5, 0x14, 0xc6, 0x6b, 0x5c, 0xbb, 0xe7, 0x1e, 0xcd, 0x04, 0xe6, 0x74, 0xf3, 0x2c, 0x00, 0x7d, 0xcd, 0x6b, 0x13, 0xaf, 0x75, 0x12, 0x90, 0xa3, 0x6e, 0xe8, 0xb6, 0x25, 0x8a, 0x69, 0x2e, 0x2e, 0xd1, 0x1f, 0x39, 0xea, 0x69, 0x82, 0x32, 0xe0, 0x90, 0x1c, 0xbf, 0x97, 0xd1, 0x82, 0x21, 0x10, 0x1b, 0xd2, 0xc1, 0x80, 0xc4, 0xd1, 0x22, 0x12, 0x0a, 0x1a, 0x25, 0x33, 0x9c, 0x0c, 0x08, 0x8e, 0x4e, 0xb5, 0xa5, 0x50, 0xe8, 0xb2, 0x07, 0xb2, 0xeb, 0x91, 0x45, 0xde, 0xa6, 0x99, 0x0b, 0x91, 0x4a, 0xe7, 0xcd, 0x22, 0x31, 0x2f, 0xee, 0xdc, 0x80, 0x2f, 0x06, 0x09, 0xe3, 0x49, 0x84, 0x1c, 0x3a, 0xc0, 0x11, 0xf7, 0x4b, 0x7e, 0xcb, 0xf2, 0x74, 0x77, 0x74, 0xcb, 0xee, 0xe9, 0x22, 0x8d, 0x59, 0x3e, 0xb8, 0x83, 0x01, 0x07, 0x0b, 0xc8, 0xc2, 0xb2, 0x1a, 0xf3, 0x16, 0x0b, 0x0d, 0x02, 0x16, 0xc7, 0xe9, 0x1c, 0x4f, 0xb7, 0xf2, 0xf4, 0x9c, 0xf1, 0x38, 0x66, 0xe1, 0x6d, 0x16, 0xdc, 0x06, 0x34, 0x1b, 0xac, 0x56, 0xab, 0x01, 0x22, 0x83, 0xdd, 0xbb, 0xf2, 0x52, 0xa4, 0x5e, 0xbf, 0x6e, 0x8e, 0xa4, 0xcc, 0x96, 0xb8, 0x17, 0x5d, 0xcf, 0x48, 0x0b, 0x24, 0x5c, 0x06, 0xa8, 0x8c, 0x91, 0x63, 0xf8, 0xc2, 0xb2, 0x65, 0x88, 0x4a, 0xed, 0xad, 0x8e, 0x03, 0xa2, 0xa9, 0x55, 0x99, 0x88, 0xa0, 0x6d, 0x26, 0x38, 0xfc, 0xb1, 0x29, 0x76, 0x68, 0x48, 0xbe, 0x7f, 0x57, 0x4c, 0xfa, 0xb5, 0x09, 0xc9, 0x81, 0x0f, 0x4b, 0x98, 0xc2, 0x40, 0xc0, 0x46, 0xa6, 0xe0, 0x50, 0x01, 0x58, 0x4b, 0x69, 0xf2, 0x3c, 0x69, 0xb8, 0xff, 0x88, 0xb4, 0xf5, 0xb1, 0x4e, 0x25, 0x49, 0x43, 0x88, 0x10, 0xec, 0xa0, 0x60, 0x6e, 0x31, 0x73, 0xb0, 0xea, 0xfd, 0xc3, 0x63, 0x86, 0xad, 0x36, 0x03, 0xd2, 0x8b, 0x31, 0xb6, 0x36, 0xaa, 0x82, 0x0a, 0x92, 0x42, 0x9d, 0x0d, 0x33, 0xbe, 0x6a, 0x05, 0x98, 0x69, 0x79, 0xe9, 0x95, 0x85, 0xdc, 0xb8, 0xb5, 0xc6, 0xaf, 0xd6, 0xec, 0x7d, 0x28, 0xc3, 0xac, 0x4f, 0xac, 0x75, 0xa3, 0xdb, 0x64, 0x8c, 0xf9, 0x4d, 0x41, 0xb1, 0x20, 0x98, 0xed, 0x13, 0xcf, 0x36, 0xea, 0xa9, 0x16, 0x32, 0x90, 0xb5, 0x64, 0x04, 0x82, 0x6c, 0x1f, 0xf4, 0xc0, 0xb2, 0x6c, 0x73, 0x56, 0xd8, 0x24, 0x4a, 0x8a, 0x38, 0x36, 0x7b, 0x45, 0x79, 0xba, 0xb2, 0x92, 0xc9, 0xb8, 0x0e, 0xe4, 0xea, 0xcc, 0x37, 0x26, 0x6e, 0x9e, 0x0c, 0x45, 0x48, 0x8f, 0x74, 0x7d, 0xd1, 0x83, 0x17, 0xce, 0xe0, 0xd8, 0xa4, 0x47, 0x2a, 0x0d, 0xd5, 0x27, 0x70, 0xc2, 0x75, 0x8e, 0xc2, 0x69, 0x93, 0x13, 0x31, 0x67, 0xe4, 0xf8, 0xd3, 0x9f, 0x64, 0x4b, 0x97, 0x90, 0xad, 0xb5, 0xec, 0x81, 0xb9, 0x32, 0x1a, 0x2b, 0x5a, 0xab, 0xc2, 0x6b, 0x49, 0xaf, 0x8e, 0xf0, 0x49, 0x5a, 0xa8, 0x26, 0xe4, 0x99, 0x62, 0xd0, 0x93, 0x37, 0x14, 0x7f, 0x61, 0xbf, 0xb2, 0x6b, 0x9c, 0x10, 0x8d, 0xe4, 0x37, 0x3f, 0x44, 0x7e, 0xd3, 0x25, 0x0f, 0xa3, 0x8c, 0x29, 0xc8, 0x73, 0xe4, 0x35, 0x52, 0x97, 0x7a, 0x5a, 0xb0, 0xec, 0x2f, 0xfa, 0xe9, 0x39, 0xda, 0x12, 0xc5, 0x4c, 0x79, 0xfc, 0x32, 0xe5, 0x71, 0x97, 0xf2, 0xfe, 0x39, 0x9a, 0x0d, 0xf3, 0x48, 0x2f, 0x3c, 0x89, 0xad, 0xac, 0xf1, 0xcc, 0x25, 0xcd, 0x66, 0xba, 0x04, 0x07, 0x2d, 0x96, 0x95, 0xc0, 0xaf, 0xd7, 0x0e, 0x91, 0x7f, 0x37, 0xc6, 0xe4, 0xf9, 0x99, 0x8b, 0xcf, 0xd1, 0xfd, 0xd9, 0x7a, 0xa8, 0xb6, 0x20, 0x17, 0x9b, 0x90, 0xe9, 0x79, 0xb4, 0xbc, 0x39, 0x53, 0xb5, 0x04, 0x69, 0x72, 0xe4, 0x7a, 0xef, 0x50, 0x28, 0x2e, 0x11, 0x66, 0x62, 0x9e, 0xb1, 0x7c, 0xce, 0xe3, 0x90, 0x50, 0x54, 0xee, 0x79, 0x14, 0xcc, 0x55, 0xf4, 0xa5, 0xd1, 0x92, 0x0b, 0xa2, 0xef, 0xf3, 0xd0, 0xc0, 0xe0, 0x68, 0x96, 0xcb, 0xa0, 0xed, 0x7c, 0x2e, 0xd1, 0x39, 0xb6, 0x38, 0x60, 0xb0, 0x60, 0x34, 0x2f, 0x32, 0xe4, 0x0b, 0x1c, 0x02, 0x0b, 0xdc, 0x67, 0xe7, 0xa8, 0x57, 0x8a, 0xe1, 0x4d, 0x9f, 0xde, 0x47, 0x26, 0x1e, 0x74, 0x45, 0x1f, 0xc8, 0x34, 0xe3, 0x0b, 0x85, 0x76, 0xad, 0xd0, 0x88, 0x75, 0xe3, 0xa3, 0xb5, 0x25, 0xef, 0xc9, 0x4c, 0xed, 0x92, 0x0c, 0x3a, 0xc4, 0x05, 0x43, 0x27, 0x12, 0xc7, 0x84, 0xe6, 0x39, 0xae, 0x7c, 0x0d, 0x9c, 0x16, 0x3c, 0x63, 0x04, 0xed, 0x80, 0xe4, 0x53, 0xdd, 0x50, 0x6d, 0xe5, 0x24, 0xa3, 0x09, 0x4a, 0x25, 0x76, 0x55, 0x5b, 0xa7, 0xdc, 0x35, 0x30, 0x78, 0x1f, 0xa3, 0x3a, 0xca, 0x1b, 0x76, 0x4d, 0x33, 0x26, 0x96, 0xe7, 0xba, 0x3b, 0xc3, 0xd1, 0xaf, 0xeb, 0x59, 0x6c, 0x6d, 0x00, 0x2e, 0x97, 0x27, 0x9f, 0xcf, 0xc9, 0x9f, 0xef, 0x2f, 0x3e, 0xbd, 0xff, 0x70, 0x76, 0x32, 0xd9, 0x30, 0x3d, 0x51, 0x6e, 0x39, 0xcf, 0xd8, 0x42, 0xfa, 0xac, 0xa4, 0xc1, 0x0c, 0xcf, 0x88, 0x15, 0xe3, 0xb8, 0x64, 0xe3, 0x96, 0x50, 0x01, 0x61, 0x35, 0xe4, 0x30, 0xec, 0xb9, 0x8a, 0xda, 0xea, 0x0f, 0x47, 0x6f, 0x4d, 0x12, 0x74, 0xd9, 0x5e, 0x74, 0xd8, 0xaa, 0x7b, 0x45, 0xfb, 0xff, 0xc8, 0x16, 0x8c, 0x11, 0x2c, 0x93, 0x94, 0xe1, 0xba, 0xb2, 0xd6, 0x11, 0x33, 0xb0, 0x9d, 0x9a, 0x34, 0xe5, 0xd6, 0x1f, 0x62, 0x2c, 0x63, 0x70, 0x22, 0xdf, 0x6d, 0x94, 0x6c, 0x25, 0xdf, 0x0f, 0x78, 0xa5, 0x81, 0x26, 0x8e, 0xa8, 0x77, 0x1e, 0xe4, 0x6e, 0xb0, 0x22, 0x61, 0x26, 0xef, 0x7e, 0x29, 0x0a, 0x90, 0xf6, 0x97, 0xe4, 0x8b, 0x2f, 0x3c, 0x31, 0xc4, 0xdf, 0xf3, 0x9e, 0x38, 0xa2, 0x71, 0x50, 0xc4, 0x32, 0xad, 0x1e, 0x2b, 0x2e, 0x97, 0xf2, 0xac, 0x52, 0x2a, 0x1f, 0x22, 0x7e, 0x10, 0x04, 0xf5, 0xfb, 0x8f, 0x6b, 0x9d, 0xdf, 0x8c, 0x8d, 0xa6, 0xda, 0x7a, 0xb2, 0xa1, 0x30, 0xf6, 0x13, 0x6a, 0xa9, 0x8f, 0x3c, 0x5b, 0xd1, 0x2c, 0x34, 0x00, 0x5b, 0xde, 0xc6, 0x5e, 0xd3, 0xbb, 0xf9, 0xc0, 0xf7, 0x0e, 0xe5, 0x1d, 0xbe, 0xeb, 0xa1, 0x60, 0xea, 0xff, 0x1d, 0x92, 0xca, 0x17, 0x36, 0x1f, 0x63, 0x4e, 0x85, 0x46, 0xb2, 0x8d, 0xed, 0x44, 0xcb, 0xcb, 0x26, 0x76, 0x7d, 0x95, 0x27, 0xae, 0x2b, 0xb6, 0xa6, 0xba, 0x46, 0x58, 0x9c, 0x6f, 0xdc, 0xa6, 0x57, 0x7a, 0x5c, 0xc8, 0x1e, 0x32, 0x67, 0xff, 0x5c, 0x8f, 0x97, 0x17, 0x7e, 0x51, 0xf6, 0x7f, 0x66, 0x8a, 0xd6, 0x2d, 0x78, 0x4b, 0x7e, 0x15, 0x50, 0xa5, 0xbb, 0x9f, 0xf0, 0xf4, 0x8d, 0xf6, 0x34, 0xb1, 0x90, 0xa9, 0xb8, 0xc0, 0x6d, 0xf5, 0x66, 0x53, 0xb2, 0xae, 0x6b, 0x7b, 0xb4, 0xad, 0xf3, 0x30, 0x6e, 0x17, 0x21, 0xe9, 0xa6, 0x50, 0xeb, 0x1a, 0xb6, 0x47, 0x1d, 0x42, 0x93, 0xec, 0xbf, 0xa3, 0x97, 0x82, 0xf8, 0x65, 0xc8, 0x96, 0xe9, 0x09, 0x37, 0x1d, 0xc9, 0x66, 0x54, 0x02, 0xbb, 0x4f, 0x70, 0x17, 0xcc, 0x92, 0x99, 0x98, 0xcb, 0x24, 0xa7, 0xb1, 0xad, 0x7a, 0xab, 0xda, 0x78, 0x3f, 0x82, 0xab, 0x1e, 0x99, 0x6e, 0x5f, 0x0c, 0x71, 0xc5, 0xec, 0x43, 0x5c, 0x9e, 0x29, 0x6a, 0x66, 0xcb, 0xbc, 0xdc, 0x7c, 0x56, 0xbd, 0x53, 0x4d, 0x5c, 0x4b, 0x73, 0x6e, 0x9a, 0xa2, 0x12, 0x45, 0x1a, 0x42, 0x3a, 0x71, 0xd3, 0x5a, 0x35, 0x5f, 0x19, 0x0d, 0xea, 0x3a, 0x98, 0xde, 0xe5, 0x7a, 0xb7, 0xd9, 0x07, 0x4d, 0x89, 0xb2, 0x0f, 0xb1, 0xdd, 0x65, 0x78, 0x58, 0x78, 0x9b, 0x03, 0x51, 0x3b, 0x98, 0x83, 0x16, 0xa6, 0xd9, 0xb0, 0x4d, 0x1e, 0x40, 0xf3, 0x4a, 0x63, 0x02, 0x87, 0x48, 0x35, 0x75, 0x94, 0xc8, 0xd4, 0xa2, 0xd2, 0x99, 0xd1, 0x99, 0xb2, 0xb0, 0x4a, 0xe9, 0xb0, 0x72, 0xbf, 0x31, 0xc3, 0x76, 0x3b, 0x24, 0x76, 0x1a, 0x3d, 0xb6, 0xad, 0x46, 0x6d, 0x43, 0xc8, 0x56, 0xf5, 0xf8, 0x59, 0x86, 0x17, 0xeb, 0x0c, 0xfb, 0x6d, 0x86, 0x4f, 0x67, 0xbb, 0xa7, 0x07, 0xe5, 0x15, 0x8d, 0x32, 0x9a, 0x7a, 0x5d, 0x66, 0x55, 0x7a, 0x6d, 0x8f, 0xdc, 0xbd, 0x3d, 0x5b, 0x1e, 0xdd, 0x1d, 0x79, 0xae, 0xdf, 0xc4, 0xb8, 0xd0, 0x18, 0x32, 0x3f, 0xcb, 0xba, 0x86, 0x3a, 0x5a, 0xb7, 0x27, 0x9a, 0xab, 0xac, 0xf6, 0x88, 0xd4, 0x8c, 0x87, 0x05, 0x7a, 0x55, 0x19, 0x39, 0x43, 0x9d, 0xaa, 0x47, 0xa6, 0x97, 0x55, 0x68, 0xe0, 0x3f, 0xc9, 0x97, 0x27, 0x28, 0xde, 0x56, 0xeb, 0x62, 0x49, 0x77, 0xe2, 0x4d, 0xbf, 0x83, 0x5a, 0xad, 0x6e, 0xba, 0x70, 0x1b, 0x27, 0xeb, 0xb6, 0xba, 0xc1, 0xc2, 0x65, 0x20, 0xc4, 0x40, 0x4b, 0x8e, 0x97, 0x30, 0xd2, 0x0e, 0xeb, 0xbd, 0x36, 0x86, 0xea, 0x45, 0xfc, 0xdf, 0xb0, 0xec, 0x21, 0x20, 0xa0, 0x1f, 0x00, 0x00}; -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /web_smars.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Joystick test 11 | 12 | 13 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | 60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 | 109 | 110 | 111 | 179 | 180 | --------------------------------------------------------------------------------