├── .github └── workflows │ ├── arduino.yml │ ├── esp-idf.yml │ ├── platformio.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── RELEASE.md ├── assets ├── handler-callbacks.svg └── request-flow.svg ├── benchmark ├── arduinomongoose │ ├── .gitignore │ ├── data │ │ └── www │ │ │ └── alien.png │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ └── main.cpp │ └── test │ │ └── README ├── comparison.ods ├── espasyncwebserver │ ├── .gitignore │ ├── data │ │ └── www │ │ │ └── alien.png │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ └── main.cpp │ └── test │ │ └── README ├── eventsource-client-test.js ├── http-client-test.js ├── latency.png ├── loadtest-http.sh ├── loadtest-websocket.sh ├── package.json ├── performance.png ├── psychichttp │ ├── .gitignore │ ├── data │ │ └── www │ │ │ └── alien.png │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── main.cpp │ │ └── secret.h │ └── test │ │ └── README ├── psychichttps │ ├── .gitignore │ ├── data │ │ ├── server.crt │ │ ├── server.key │ │ └── www │ │ │ └── alien.png │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── main.cpp │ │ └── secret.h │ └── test │ │ └── README ├── results │ ├── arduinomongoose-http-loadtest.log │ ├── arduinomongoose-websocket-loadtest.log │ ├── espasync-http-loadtest.log │ ├── espasync-websocket-loadtest.log │ ├── psychic-http-loadtest.log │ ├── psychic-ssl-http-loadtest.log │ ├── psychic-ssl-websocket-loadtest.log │ ├── psychic-v1.1-http-loadtest.log │ ├── psychic-v1.1-websocket-loadtest.log │ └── psychic-websocket-loadtest.log └── websocket-client-test.js ├── component.mk ├── examples ├── arduino │ ├── .gitignore │ ├── arduino.ino │ ├── arduino_captive_portal │ │ ├── README.md │ │ ├── arduino_captive_portal.ino │ │ └── images │ │ │ ├── accesspoint.png │ │ │ └── station.png │ ├── arduino_ota │ │ ├── README.md │ │ ├── arduino_ota.ino │ │ ├── code.bin │ │ ├── data │ │ │ └── update.html │ │ ├── images │ │ │ ├── otaupdate1.png │ │ │ ├── otaupdate2.png │ │ │ ├── otaupdate3.png │ │ │ ├── otaupdate4.png │ │ │ └── otaupdate5.png │ │ └── littlefs.bin │ ├── data │ │ ├── custom.txt │ │ ├── img │ │ │ └── request_flow.png │ │ ├── server.crt │ │ ├── server.key │ │ ├── www-ap │ │ │ └── index.html │ │ └── www │ │ │ ├── alien.png │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ └── text.txt │ └── secret.h ├── esp-idf │ ├── .gitignore │ ├── CMakeLists.txt │ ├── README.md │ ├── data │ │ ├── custom.txt │ │ ├── img │ │ │ └── request_flow.png │ │ ├── server.crt │ │ ├── server.key │ │ ├── www-ap │ │ │ └── index.html │ │ └── www │ │ │ ├── alien.png │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ └── text.txt │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── main │ │ ├── CMakeLists.txt │ │ ├── idf_component.yml │ │ ├── main.cpp │ │ └── secret.h │ ├── partitions_custom.csv │ └── sdkconfig.defaults ├── old │ ├── esp_ota_http_server │ │ ├── .gitignore │ │ ├── .vscode │ │ │ └── extensions.json │ │ ├── include │ │ │ └── README │ │ ├── lib │ │ │ └── README │ │ ├── platformio.ini │ │ ├── src │ │ │ └── esp_ota_http_server.cpp │ │ └── test │ │ │ └── README │ ├── simple_http_server │ │ ├── .gitignore │ │ ├── .vscode │ │ │ └── extensions.json │ │ ├── include │ │ │ └── README │ │ ├── lib │ │ │ └── README │ │ ├── platformio.ini │ │ ├── src │ │ │ └── simple_http_server.cpp │ │ └── test │ │ │ ├── README │ │ │ └── tests.rest │ ├── simplest_web_server_esp │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── .vscode │ │ │ └── extensions.json │ │ ├── include │ │ │ └── README │ │ ├── lib │ │ │ └── README │ │ ├── platformio.ini │ │ ├── src │ │ │ └── simplest_web_server.cpp │ │ └── test │ │ │ └── README │ └── websocket_chat │ │ ├── .gitignore │ │ ├── .vscode │ │ └── extensions.json │ │ ├── include │ │ └── README │ │ ├── lib │ │ └── README │ │ ├── platformio.ini │ │ ├── src │ │ └── websocket_chat.cpp │ │ └── test │ │ ├── README │ │ └── tests.rest ├── platformio │ ├── .gitignore │ ├── data │ │ ├── custom.txt │ │ ├── img │ │ │ └── request_flow.png │ │ ├── server.crt │ │ ├── server.key │ │ ├── www-ap │ │ │ └── index.html │ │ └── www │ │ │ ├── alien.png │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ └── text.txt │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── main.cpp │ │ └── secret.h │ └── test │ │ └── README └── websockets │ ├── .gitignore │ ├── data │ └── www │ │ ├── favicon.ico │ │ └── index.html │ ├── include │ └── README │ ├── lib │ └── README │ ├── platformio.ini │ ├── src │ ├── main.cpp │ └── secret.h │ └── test │ └── README ├── idf_component.yml ├── library.json ├── library.properties ├── request flow.drawio └── src ├── ChunkPrinter.cpp ├── ChunkPrinter.h ├── PsychicClient.cpp ├── PsychicClient.h ├── PsychicCore.h ├── PsychicEndpoint.cpp ├── PsychicEndpoint.h ├── PsychicEventSource.cpp ├── PsychicEventSource.h ├── PsychicFileResponse.cpp ├── PsychicFileResponse.h ├── PsychicHandler.cpp ├── PsychicHandler.h ├── PsychicHttp.h ├── PsychicHttpServer.cpp ├── PsychicHttpServer.h ├── PsychicHttpsServer.cpp ├── PsychicHttpsServer.h ├── PsychicJson.cpp ├── PsychicJson.h ├── PsychicRequest.cpp ├── PsychicRequest.h ├── PsychicResponse.cpp ├── PsychicResponse.h ├── PsychicStaticFileHander.cpp ├── PsychicStaticFileHandler.h ├── PsychicStreamResponse.cpp ├── PsychicStreamResponse.h ├── PsychicUploadHandler.cpp ├── PsychicUploadHandler.h ├── PsychicWebHandler.cpp ├── PsychicWebHandler.h ├── PsychicWebParameter.h ├── PsychicWebSocket.cpp ├── PsychicWebSocket.h ├── TemplatePrinter.cpp ├── TemplatePrinter.h ├── async_worker.cpp ├── async_worker.h ├── http_status.cpp └── http_status.h /.github/workflows/arduino.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Lint 2 | 3 | on: 4 | push: 5 | branches: [] 6 | pull_request: 7 | branches: [] 8 | schedule: 9 | - cron: "0 1 * * 6" # Every Saturday at 1AM 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: arduino/arduino-lint-action@v1 17 | with: 18 | library-manager: update 19 | project-type: library 20 | compliance: strict -------------------------------------------------------------------------------- /.github/workflows/esp-idf.yml: -------------------------------------------------------------------------------- 1 | name: ESP-IDF 2 | 3 | on: 4 | push: 5 | branches: [] 6 | pull_request: 7 | branches: [] 8 | schedule: 9 | - cron: "0 1 * * 6" # Every Saturday at 1AM 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | 17 | build: 18 | name: "ESP-IDF ${{ matrix.idf_ver }}" 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 10 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | idf_ver: ["v4.4.7", "v5.1.4", "v5.3.2"] 26 | idf_target: ["esp32"] 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | with: 31 | path: ${{ github.workspace }}/app 32 | 33 | - name: Compile 34 | uses: espressif/esp-idf-ci-action@v1 35 | with: 36 | esp_idf_version: ${{ matrix.idf_ver }} 37 | target: ${{ matrix.idf_target }} 38 | path: app/examples/esp-idf 39 | command: apt-get update && apt-get install -y python3-venv && idf.py build -------------------------------------------------------------------------------- /.github/workflows/platformio.yml: -------------------------------------------------------------------------------- 1 | name: Platform IO 2 | 3 | on: 4 | push: 5 | branches: [] 6 | pull_request: 7 | branches: [] 8 | schedule: 9 | - cron: "0 1 * * 6" # Every Saturday at 1AM 10 | 11 | jobs: 12 | 13 | build: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | include: 18 | - example: platformio 19 | board: default 20 | 21 | runs-on: ubuntu-latest 22 | name: Build ${{ matrix.example }}-${{ matrix.board }} 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | - name: Set up Python 28 | uses: actions/setup-python@v4 29 | 30 | - name: Install Platform IO 31 | run: 32 | | 33 | pip install -U platformio 34 | platformio update 35 | 36 | - name: Install Checked out PsychicHttp 37 | run: 38 | pio lib -g install $GITHUB_WORKSPACE 39 | 40 | - name: Build example 41 | run: 42 | | 43 | cd examples/${{ matrix.example }} 44 | cp src/secret.h src/_secret.h 45 | pio run -e ${{ matrix.board }} 46 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Release to Platform IO and Arduino 4 | 5 | on: 6 | release: 7 | types: 8 | - released 9 | 10 | jobs: 11 | release_number: 12 | name: Release Number Validation 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | ### Check the version number in the code matches the tag number 17 | - uses: actions/checkout@v4 18 | 19 | - name: Retrieve the version number(s) 20 | run: | 21 | TAG_VERSION=$(sed "s/^v//" <<< $GITHUB_REF_NAME) 22 | PLATFORMIO_VERSION=$(jq ".version" library.json -r) 23 | ARDUINO_VERSION=$(awk -F= '/version/{gsub(/"/, "", $2); print $2}' library.properties) 24 | echo TAG_VERSION=$TAG_VERSION >> $GITHUB_ENV 25 | echo PLATFORMIO_VERSION=$PLATFORMIO_VERSION >> $GITHUB_ENV 26 | echo ARDUINO_VERSION=$ARDUINO_VERSION >> $GITHUB_ENV 27 | - name: Check the version number is semver compliant 28 | run: | 29 | if ! [[ $TAG_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-z]*[0-9]+)?$ ]]; then 30 | echo "ERROR: The version number is not semver compliant" 31 | exit 1 32 | fi 33 | - name: Check the Platformio version matches the tag number 34 | run: | 35 | if [ "$TAG_VERSION" != "$PLATFORMIO_VERSION" ]; then 36 | echo "ERROR: The version number in library.json ($PLATFORMIO_VERSION) does not match the tag number ($TAG_VERSION)" 37 | exit 1 38 | fi 39 | - name: Check the Arduino version matches the tag number 40 | run: | 41 | if [ "$TAG_VERSION" != "$ARDUINO_VERSION" ]; then 42 | echo "ERROR: The version number in library.properties ($ARDUINO_VERSION) does not match the tag number ($TAG_VERSION)" 43 | exit 1 44 | fi 45 | 46 | release_to_platformio: 47 | name: Release to PlatformIO Registry 48 | runs-on: ubuntu-latest 49 | needs: release_number 50 | 51 | steps: 52 | - uses: actions/checkout@v4 53 | 54 | - name: Set up Python 55 | uses: actions/setup-python@v4 56 | 57 | - name: Install Platform IO 58 | run: | 59 | pip install -U platformio 60 | platformio update 61 | 62 | - name: Register new library version 63 | run: | 64 | PLATFORMIO_AUTH_TOKEN=${{ secrets.PLATFORMIO_AUTH_TOKEN }} pio pkg publish --type library --no-interactive --notify 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **.vscode 2 | **.pio 3 | **.DS_Store 4 | .pioenvs 5 | .clang_complete 6 | .gcc-flags.json 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | # Fortran module files 20 | *.mod 21 | # Compiled Static libraries 22 | *.lai 23 | *.la 24 | *.a 25 | *.lib 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | # Visual Studio/VisualMicro stuff 31 | Visual\ Micro 32 | *.sdf 33 | *.opensdf 34 | *.suo 35 | .pioenvs 36 | .piolibdeps 37 | .pio 38 | .vscode/c_cpp_properties.json 39 | .vscode/launch.json 40 | .vscode/settings.json 41 | .vscode/.browse.c_cpp.db* 42 | .vscode/ipch 43 | /psychic-http-loadtest.log 44 | /psychic-websocket-loadtest.log 45 | examples/platformio/lib/PsychicHttp 46 | benchmark/.~lock.comparison.ods# 47 | benchmark/psychic-http-loadtest.log 48 | .$request flow.drawio.bkp 49 | .$request flow.drawio.dtmp 50 | benchmark/package-lock.json 51 | benchmark/node_modules 52 | src/secret.h 53 | benchmark/psychichttp/src/_secret.h 54 | benchmark/psychichttps/src/_secret.h 55 | examples/platformio/src/_secret.h 56 | examples/arduino/src/_secret.h 57 | src/cookie.txt 58 | examples/websockets/lib/PsychicHttp 59 | examples/websockets/src/_secret.h 60 | /build 61 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples/esp-idf/components/UrlEncode"] 2 | path = examples/esp-idf/components/UrlEncode 3 | url = https://github.com/dzungpv/UrlEncode 4 | [submodule "examples/esp-idf/components/ArduinoJson"] 5 | path = examples/esp-idf/components/ArduinoJson 6 | url = https://github.com/bblanchon/ArduinoJson 7 | branch = 7.x 8 | [submodule "examples/esp-idf/components/arduino-esp32"] 9 | path = examples/esp-idf/components/arduino-esp32 10 | url = https://github.com/espressif/arduino-esp32 11 | branch = idf-release/v4.4 12 | [submodule "examples/esp-idf/components/esp_littlefs"] 13 | path = examples/esp-idf/components/esp_littlefs 14 | url = https://github.com/joltwallet/esp_littlefs.git 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v1.2.1 2 | 3 | * Fix bug with missing include preventing the HTTPS server from compiling. 4 | 5 | # v1.2 6 | 7 | * Added TemplatePrinter from https://github.com/Chris--A/PsychicHttp/tree/templatePrint 8 | * Support using as ESP IDF component 9 | * Optional using https server in ESP IDF 10 | * Fixed bug with headers 11 | * Add ESP IDF example + CI script 12 | * Added Arduino Captive Portal example and OTAUpdate from @06GitHub 13 | * HTTPS fix for ESP-IDF v5.0.2+ from @06GitHub 14 | * lots of bugfixes from @mathieucarbou 15 | 16 | Thanks to @Chris--A, @06GitHub, and @dzungpv for your contributions. 17 | 18 | # v1.1 19 | 20 | * Changed the internal structure to support request handlers on endpoints and generic requests that do not match an endpoint 21 | * websockets, uploads, etc should now create an appropriate handler and attach to an endpoint with the server.on() syntax 22 | * Added PsychicClient to abstract away some of the internals of ESP-IDF sockets + add convenience 23 | * onOpen and onClose callbacks have changed as a result 24 | * Added support for EventSource / SSE 25 | * Added support for multipart file uploads 26 | * changed getParam() to return a PsychicWebParameter in line with ESPAsyncWebserver 27 | * Renamed various classes / files: 28 | * PsychicHttpFileResponse -> PsychicFileResponse 29 | * PsychicHttpServerEndpoint -> PsychicEndpoint 30 | * PsychicHttpServerRequest -> PsychicRequest 31 | * PsychicHttpServerResponse -> PsychicResponse 32 | * PsychicHttpWebsocket.h -> PsychicWebSocket.h 33 | * Websocket => WebSocket 34 | * Quite a few bugfixes from the community. Thank you @glennsky, @gb88, @KastanEr, @kstam, and @zekageri -------------------------------------------------------------------------------- /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 | "esp_https_server" 12 | "arduinojson" 13 | "urlencode" 14 | ) 15 | 16 | register_component() 17 | 18 | target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DESP32) 19 | target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti) 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Jeremy Poulter, Zachary Smith, and Mathieu Carbou 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | * Update CHANGELOG 2 | * Bump version in library.json 3 | * Bump version in library.properties 4 | * Make new release + tag 5 | * this will get pulled in automatically by Arduino Library Indexer 6 | * run ```pio pkg publish``` to publish to Platform.io -------------------------------------------------------------------------------- /benchmark/arduinomongoose/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /benchmark/arduinomongoose/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/arduinomongoose/data/www/alien.png -------------------------------------------------------------------------------- /benchmark/arduinomongoose/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 | -------------------------------------------------------------------------------- /benchmark/arduinomongoose/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 | -------------------------------------------------------------------------------- /benchmark/arduinomongoose/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32dev 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | jeremypoulter/ArduinoMongoose 19 | bblanchon/ArduinoJson 20 | board_build.filesystem = littlefs 21 | 22 | [env:default] -------------------------------------------------------------------------------- /benchmark/arduinomongoose/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /benchmark/comparison.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/comparison.ods -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/espasyncwebserver/data/www/alien.png -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/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 | -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/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 | -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32dev 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | https://github.com/me-no-dev/ESPAsyncWebServer 19 | bblanchon/ArduinoJson 20 | board_build.filesystem = littlefs 21 | 22 | [env:default] -------------------------------------------------------------------------------- /benchmark/espasyncwebserver/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /benchmark/eventsource-client-test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const EventSource = require('eventsource'); 4 | const url = 'http://192.168.2.131/events'; 5 | 6 | async function eventSourceClient() { 7 | console.log(`Starting test`); 8 | for (let i = 0; i < 1000000; i++) 9 | { 10 | if (i % 100 == 0) 11 | console.log(`Count: ${i}`); 12 | 13 | let eventSource = new EventSource(url); 14 | 15 | eventSource.onopen = () => { 16 | //console.log('EventSource connection opened.'); 17 | }; 18 | 19 | eventSource.onerror = (error) => { 20 | console.error('EventSource error:', error); 21 | 22 | // Close the connection on error 23 | eventSource.close(); 24 | }; 25 | 26 | await new Promise((resolve) => { 27 | eventSource.onmessage = (event) => { 28 | //console.log('Received message:', event.data); 29 | 30 | // Close the connection after receiving the first message 31 | eventSource.close(); 32 | 33 | resolve(); 34 | } 35 | }); 36 | } 37 | } 38 | 39 | eventSourceClient(); -------------------------------------------------------------------------------- /benchmark/http-client-test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const axios = require('axios'); 4 | 5 | const url = 'http://192.168.2.131/api'; 6 | const queryParams = { 7 | foo: 'bar', 8 | foo1: 'bar', 9 | foo2: 'bar', 10 | foo3: 'bar', 11 | foo4: 'bar', 12 | foo5: 'bar', 13 | foo6: 'bar', 14 | }; 15 | 16 | const totalRequests = 1000000; 17 | const requestsPerCount = 100; 18 | 19 | let requestCount = 0; 20 | 21 | function fetchData() { 22 | axios.get(url, { params: queryParams }) 23 | .then(response => { 24 | requestCount++; 25 | 26 | if (requestCount % requestsPerCount === 0) { 27 | console.log(`Requests completed: ${requestCount}`); 28 | } 29 | 30 | if (requestCount < totalRequests) { 31 | fetchData(); 32 | } else { 33 | console.log('All requests completed.'); 34 | } 35 | }) 36 | .catch(error => { 37 | console.error('Error making request:', error.message); 38 | }); 39 | } 40 | 41 | // Start making requests 42 | console.log(`Starting test`); 43 | fetchData(); -------------------------------------------------------------------------------- /benchmark/latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/latency.png -------------------------------------------------------------------------------- /benchmark/loadtest-http.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #Command to install the testers: 3 | # npm install -g autocannon 4 | 5 | TEST_IP="192.168.2.131" 6 | TEST_TIME=60 7 | LOG_FILE=psychic-http-loadtest.log 8 | TIMEOUT=10000 9 | PROTOCOL=http 10 | #PROTOCOL=https 11 | 12 | if test -f "$LOG_FILE"; then 13 | rm $LOG_FILE 14 | fi 15 | 16 | for CONCURRENCY in 1 2 3 4 5 6 7 8 9 10 15 20 17 | #for CONCURRENCY in 20 18 | do 19 | printf "\n\nCLIENTS: *** $CONCURRENCY ***\n\n" >> $LOG_FILE 20 | echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/" 21 | #loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/" --quiet >> $LOG_FILE 22 | autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/" >> $LOG_FILE 2>&1 23 | printf "\n\n----------------\n\n" >> $LOG_FILE 24 | sleep 1 25 | 26 | echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/api" 27 | #loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/api?foo=bar" --quiet >> $LOG_FILE 28 | autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/api?foo=bar" >> $LOG_FILE 2>&1 29 | printf "\n\n----------------\n\n" >> $LOG_FILE 30 | sleep 1 31 | 32 | echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/alien.png" 33 | #loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --timeout $TIMEOUT "$PROTOCOL://$TEST_IP/alien.png" --quiet >> $LOG_FILE 34 | autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/alien.png" >> $LOG_FILE 2>&1 35 | printf "\n\n----------------\n\n" >> $LOG_FILE 36 | sleep 1 37 | done -------------------------------------------------------------------------------- /benchmark/loadtest-websocket.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #Command to install the testers: 3 | # npm install -g loadtest 4 | 5 | TEST_IP="192.168.2.131" 6 | TEST_TIME=60 7 | LOG_FILE=psychic-websocket-loadtest.log 8 | PROTOCOL=ws 9 | #PROTOCOL=wss 10 | 11 | if test -f "$LOG_FILE"; then 12 | rm $LOG_FILE 13 | fi 14 | 15 | for CONCURRENCY in 1 2 3 4 5 6 7 16 | do 17 | printf "\n\nCLIENTS: *** $CONCURRENCY ***\n\n" >> $LOG_FILE 18 | echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/ws" 19 | loadtest -c $CONCURRENCY --cores 1 -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE 20 | sleep 1 21 | done 22 | 23 | for CONNECTIONS in 8 10 16 20 24 | #for CONNECTIONS in 20 25 | do 26 | CONCURRENCY=$((CONNECTIONS / 2)) 27 | printf "\n\nCLIENTS: *** $CONNECTIONS ***\n\n" >> $LOG_FILE 28 | echo "Testing $CONNECTIONS clients on $PROTOCOL://$TEST_IP/ws" 29 | loadtest -c $CONCURRENCY --cores 2 -t $TEST_TIME --insecure $PROTOCOL://$TEST_IP/ws --quiet 2> /dev/null >> $LOG_FILE 30 | sleep 1 31 | done -------------------------------------------------------------------------------- /benchmark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "axios": "^1.6.2", 4 | "eventsource": "^2.0.2", 5 | "ws": "^8.14.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /benchmark/performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/performance.png -------------------------------------------------------------------------------- /benchmark/psychichttp/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /benchmark/psychichttp/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/psychichttp/data/www/alien.png -------------------------------------------------------------------------------- /benchmark/psychichttp/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 | -------------------------------------------------------------------------------- /benchmark/psychichttp/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 | -------------------------------------------------------------------------------- /benchmark/psychichttp/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32dev 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | https://github.com/hoeken/PsychicHttp 19 | bblanchon/ArduinoJson 20 | board_build.filesystem = littlefs 21 | 22 | [env:default] 23 | -------------------------------------------------------------------------------- /benchmark/psychichttp/src/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "Your_SSID" 2 | #define WIFI_PASS "Your_PASS" -------------------------------------------------------------------------------- /benchmark/psychichttp/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /benchmark/psychichttps/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /benchmark/psychichttps/data/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx 4 | MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ 5 | UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 6 | ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T 7 | sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k 8 | qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd 9 | GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4 10 | sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb 11 | jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/ 12 | ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud 13 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3 14 | emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY 15 | W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx 16 | bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN 17 | ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl 18 | hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo= 19 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /benchmark/psychichttps/data/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH 3 | JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw 4 | h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT 5 | aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al 6 | 3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg 7 | 0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB 8 | vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui 9 | f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9 10 | Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y 11 | JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX 12 | 49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc 13 | +3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6 14 | pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D 15 | 0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG 16 | YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV 17 | MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL 18 | CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin 19 | 7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1 20 | noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8 21 | 4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g 22 | Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/ 23 | nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3 24 | q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2 25 | lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB 26 | jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr 27 | v/t+MeGJP/0Zw8v/X2CFll96 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /benchmark/psychichttps/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/benchmark/psychichttps/data/www/alien.png -------------------------------------------------------------------------------- /benchmark/psychichttps/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 | -------------------------------------------------------------------------------- /benchmark/psychichttps/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 | -------------------------------------------------------------------------------- /benchmark/psychichttps/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32dev 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | https://github.com/hoeken/PsychicHttp 19 | bblanchon/ArduinoJson 20 | board_build.filesystem = littlefs 21 | 22 | [env:default] 23 | -------------------------------------------------------------------------------- /benchmark/psychichttps/src/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "Your_SSID" 2 | #define WIFI_PASS "Your_PASS" -------------------------------------------------------------------------------- /benchmark/psychichttps/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /benchmark/results/psychic-websocket-loadtest.log: -------------------------------------------------------------------------------- 1 | 2 | 3 | CLIENTS: *** 1 *** 4 | 5 | 6 | Target URL: ws://192.168.2.131/ws 7 | Max time (s): 60 8 | Concurrent clients: 1 9 | Agent: none 10 | 11 | Completed requests: 2304 12 | Total errors: 0 13 | Total time: 60.002 s 14 | Mean latency: 25.5 ms 15 | Effective rps: 38 16 | 17 | Percentage of requests served within a certain time 18 | 50% 22 ms 19 | 90% 32 ms 20 | 95% 58 ms 21 | 99% 92 ms 22 | 100% 105 ms (longest request) 23 | 24 | 25 | CLIENTS: *** 2 *** 26 | 27 | 28 | Target URL: ws://192.168.2.131/ws 29 | Max time (s): 60 30 | Concurrent clients: 2 31 | Agent: none 32 | 33 | Completed requests: 3647 34 | Total errors: 0 35 | Total time: 60.002 s 36 | Mean latency: 32.3 ms 37 | Effective rps: 61 38 | 39 | Percentage of requests served within a certain time 40 | 50% 28 ms 41 | 90% 43 ms 42 | 95% 67 ms 43 | 99% 93 ms 44 | 100% 135 ms (longest request) 45 | 46 | 47 | CLIENTS: *** 3 *** 48 | 49 | 50 | Target URL: ws://192.168.2.131/ws 51 | Max time (s): 60 52 | Concurrent clients: 3 53 | Agent: none 54 | 55 | Completed requests: 4629 56 | Total errors: 0 57 | Total time: 60.004 s 58 | Mean latency: 38.3 ms 59 | Effective rps: 77 60 | 61 | Percentage of requests served within a certain time 62 | 50% 34 ms 63 | 90% 51 ms 64 | 95% 79 ms 65 | 99% 110 ms 66 | 100% 152 ms (longest request) 67 | 68 | 69 | CLIENTS: *** 4 *** 70 | 71 | 72 | Target URL: ws://192.168.2.131/ws 73 | Max time (s): 60 74 | Concurrent clients: 4 75 | Agent: none 76 | 77 | Completed requests: 5290 78 | Total errors: 0 79 | Total time: 60.003 s 80 | Mean latency: 44.7 ms 81 | Effective rps: 88 82 | 83 | Percentage of requests served within a certain time 84 | 50% 40 ms 85 | 90% 67 ms 86 | 95% 92 ms 87 | 99% 115 ms 88 | 100% 159 ms (longest request) 89 | 90 | 91 | CLIENTS: *** 5 *** 92 | 93 | 94 | Target URL: ws://192.168.2.131/ws 95 | Max time (s): 60 96 | Concurrent clients: 5 97 | Agent: none 98 | 99 | Completed requests: 5935 100 | Total errors: 0 101 | Total time: 60.002 s 102 | Mean latency: 50 ms 103 | Effective rps: 99 104 | 105 | Percentage of requests served within a certain time 106 | 50% 45 ms 107 | 90% 74 ms 108 | 95% 97 ms 109 | 99% 123 ms 110 | 100% 172 ms (longest request) 111 | 112 | 113 | CLIENTS: *** 6 *** 114 | 115 | 116 | Target URL: ws://192.168.2.131/ws 117 | Max time (s): 60 118 | Concurrent clients: 6 119 | Agent: none 120 | 121 | Completed requests: 6533 122 | Total errors: 0 123 | Total time: 60.003 s 124 | Mean latency: 54.5 ms 125 | Effective rps: 109 126 | 127 | Percentage of requests served within a certain time 128 | 50% 49 ms 129 | 90% 78 ms 130 | 95% 101 ms 131 | 99% 129 ms 132 | 100% 170 ms (longest request) 133 | 134 | 135 | CLIENTS: *** 7 *** 136 | 137 | 138 | Target URL: ws://192.168.2.131/ws 139 | Max time (s): 60 140 | Concurrent clients: 7 141 | Agent: none 142 | 143 | Completed requests: 7086 144 | Total errors: 0 145 | Total time: 60.004 s 146 | Mean latency: 58.6 ms 147 | Effective rps: 118 148 | 149 | Percentage of requests served within a certain time 150 | 50% 54 ms 151 | 90% 85 ms 152 | 95% 107 ms 153 | 99% 130 ms 154 | 100% 184 ms (longest request) 155 | 156 | 157 | CLIENTS: *** 8 *** 158 | 159 | 160 | Target URL: ws://192.168.2.131/ws 161 | Max time (s): 60 162 | Concurrent clients: 8 163 | Running on cores: 2 164 | Agent: none 165 | 166 | Completed requests: 6994 167 | Total errors: 0 168 | Total time: 60.004 s 169 | Mean latency: 59.3 ms 170 | Effective rps: 117 171 | 172 | Percentage of requests served within a certain time 173 | 50% 54 ms 174 | 90% 88 ms 175 | 95% 109 ms 176 | 99% 134 ms 177 | 100% 176 ms (longest request) 178 | 179 | 180 | CLIENTS: *** 10 *** 181 | 182 | 183 | Target URL: ws://192.168.2.131/ws 184 | Max time (s): 60 185 | Concurrent clients: 10 186 | Running on cores: 2 187 | Agent: none 188 | 189 | Completed requests: 7197 190 | Total errors: 0 191 | Total time: 60.004 s 192 | Mean latency: 57.7 ms 193 | Effective rps: 120 194 | 195 | Percentage of requests served within a certain time 196 | 50% 53 ms 197 | 90% 83 ms 198 | 95% 98 ms 199 | 99% 123 ms 200 | 100% 176 ms (longest request) 201 | 202 | 203 | CLIENTS: *** 16 *** 204 | 205 | 206 | Target URL: ws://192.168.2.131/ws 207 | Max time (s): 60 208 | Concurrent clients: 16 209 | Running on cores: 2 210 | Agent: none 211 | 212 | Completed requests: 7173 213 | Total errors: 0 214 | Total time: 60.002 s 215 | Mean latency: 57.9 ms 216 | Effective rps: 120 217 | 218 | Percentage of requests served within a certain time 219 | 50% 53 ms 220 | 90% 83 ms 221 | 95% 100 ms 222 | 99% 123 ms 223 | 100% 156 ms (longest request) 224 | 225 | 226 | CLIENTS: *** 20 *** 227 | 228 | 229 | Target URL: ws://192.168.2.131/ws 230 | Max time (s): 60 231 | Concurrent clients: 20 232 | Running on cores: 2 233 | Agent: none 234 | 235 | Completed requests: 6883 236 | Total errors: 0 237 | Total time: 60.002 s 238 | Mean latency: 60.4 ms 239 | Effective rps: 115 240 | 241 | Percentage of requests served within a certain time 242 | 50% 55 ms 243 | 90% 92 ms 244 | 95% 111 ms 245 | 99% 138 ms 246 | 100% 175 ms (longest request) 247 | -------------------------------------------------------------------------------- /benchmark/websocket-client-test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const WebSocket = require('ws'); 4 | 5 | const uri = 'ws://192.168.2.131/ws'; 6 | 7 | async function websocketClient() { 8 | console.log(`Starting test`); 9 | for (let i = 0; i < 1000000; i++) { 10 | const ws = new WebSocket(uri); 11 | 12 | if (i % 100 == 0) 13 | console.log(`Count: ${i}`); 14 | 15 | ws.on('open', () => { 16 | //console.log(`Connected`); 17 | }); 18 | 19 | ws.on('message', (message) => { 20 | //console.log(`Message: ${message}`); 21 | ws.close(); 22 | }); 23 | 24 | ws.on('error', (error) => { 25 | console.error(`Error: ${error.message}`); 26 | }); 27 | 28 | await new Promise((resolve) => { 29 | ws.on('close', () => { 30 | resolve(); 31 | }); 32 | }); 33 | } 34 | } 35 | 36 | websocketClient(); -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS := src 2 | COMPONENT_SRCDIRS := src 3 | CXXFLAGS += -fno-rtti 4 | -------------------------------------------------------------------------------- /examples/arduino/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /examples/arduino/arduino_captive_portal/README.md: -------------------------------------------------------------------------------- 1 | **1) SUMMARY** 2 | 3 | This example implements a **captive portal** with library DNSServer, ie web page which opens automatically when user connects Wifi network (eg "PsychitHttp"). 4 | 5 | Captiveportal is implemented in **ESPAsyncWebServer** [https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/examples/CaptivePortal/CaptivePortal.ino](url) and in **arduino-esp32 examples** [https://github.com/espressif/arduino-esp32/blob/master/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino](url) 6 | 7 | This feature can be implemented with Psychichttp with a **dedicated handler**, as shown in code below. 8 | 9 | Code highlights are added below for reference. 10 | 11 | **2) CODE** 12 | 13 | **Definitions** 14 | ``` 15 | // captiveportal 16 | // credits https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/examples/CaptivePortal/CaptivePortal.ino 17 | //https://github.com/espressif/arduino-esp32/blob/master/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino 18 | #include 19 | DNSServer dnsServer; 20 | class CaptiveRequestHandler : public PsychicWebHandler { // handler 21 | public: 22 | CaptiveRequestHandler() {}; 23 | virtual ~CaptiveRequestHandler() {}; 24 | bool canHandle(PsychicRequest*request){ 25 | // ... if needed some tests ... return(false); 26 | return true; // activate captive portal 27 | } 28 | esp_err_t handleRequest(PsychicRequest *request) { 29 | //PsychicFileResponse response(request, LittleFS, "/captiveportal.html"); // uncomment : for captive portal page, if any, eg "captiveportal.html" 30 | //return response.send(); // uncomment : return captive portal page 31 | return request->reply(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page 32 | } 33 | }; 34 | CaptiveRequestHandler *captivehandler=NULL; // handler for captive portal 35 | ``` 36 | 37 | **setup()** 38 | ``` 39 | // captive portal 40 | dnsServer.start(53, "*", WiFi.softAPIP()); // DNS requests are executed over port 53 (standard) 41 | captivehandler= new CaptiveRequestHandler(); // create captive portal handler, important : after server.on since handlers are triggered on a first created/first trigerred basis 42 | server.addHandler(captivehandler); // captive portal handler (last handler) 43 | ``` 44 | 45 | **loop()** 46 | ``` 47 | dnsServer.processNextRequest(); // captive portal 48 | ``` 49 | 50 | **3) RESULT** 51 | 52 | **Access Point (web page is opened automatically when connecting to PsychicHttp AP)** 53 | ![captive portal access point](images/accesspoint.png) 54 | 55 | **Station (web page is shown whatever url for Station IP, eg 192.168.1.50/abcdefg** 56 | ![captive portal station point](images/station.png) 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/arduino/arduino_captive_portal/arduino_captive_portal.ino: -------------------------------------------------------------------------------- 1 | /* 2 | PsychicHTTP Server Captive Portal Example 3 | 4 | This example code is in the Public Domain (or CC0 licensed, at your option.) 5 | 6 | Unless required by applicable law or agreed to in writing, this 7 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | char* TAG = "CAPTPORT"; 18 | 19 | // captiveportal 20 | // credits https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/examples/CaptivePortal/CaptivePortal.ino 21 | //https://github.com/espressif/arduino-esp32/blob/master/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino 22 | #include 23 | DNSServer dnsServer; 24 | class CaptiveRequestHandler : public PsychicWebHandler { // handler 25 | public: 26 | CaptiveRequestHandler() {}; 27 | virtual ~CaptiveRequestHandler() {}; 28 | bool canHandle(PsychicRequest*request){ 29 | // ... if needed some tests ... return(false); 30 | return true; // activate captive portal 31 | } 32 | esp_err_t handleRequest(PsychicRequest *request) { 33 | //PsychicFileResponse response(request, LittleFS, "/captiveportal.html"); // uncomment : for captive portal page, if any, eg "captiveportal.html" 34 | //return response.send(); // uncomment : return captive portal page 35 | return request->reply(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page 36 | } 37 | }; 38 | CaptiveRequestHandler *captivehandler=NULL; // handler for captive portal 39 | 40 | const char* ssid = "mySSID"; // replace with your SSID (mode STATION) 41 | const char* password = "myPassword"; // replace with you password (mode STATION) 42 | 43 | // Set your SoftAP credentials 44 | const char *softap_ssid = "PsychicHttp"; 45 | const char *softap_password = ""; 46 | IPAddress softap_ip(10, 0, 0, 1); 47 | 48 | //hostname for mdns (psychic.local) 49 | const char *local_hostname = "psychic"; 50 | 51 | //our main server object 52 | PsychicHttpServer server; 53 | 54 | bool connectToWifi() { 55 | //dual client and AP mode 56 | WiFi.mode(WIFI_AP_STA); 57 | 58 | // Configure SoftAP 59 | WiFi.softAPConfig(softap_ip, softap_ip, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00 60 | WiFi.softAP(softap_ssid, softap_password); 61 | IPAddress myIP = WiFi.softAPIP(); 62 | ESP_LOGI(TAG,"SoftAP IP Address: %s", myIP.toString().c_str()); 63 | ESP_LOGI(TAG,"[WiFi] Connecting to %s", ssid); 64 | 65 | WiFi.begin(ssid, password); 66 | 67 | // Will try for about 10 seconds (20x 500ms) 68 | int tryDelay = 500; 69 | int numberOfTries = 20; 70 | 71 | // Wait for the WiFi event 72 | while (true) { 73 | switch (WiFi.status()) { 74 | case WL_NO_SSID_AVAIL: 75 | ESP_LOGE(TAG,"[WiFi] SSID not found"); 76 | break; 77 | case WL_CONNECT_FAILED: 78 | ESP_LOGI(TAG,"[WiFi] Failed - WiFi not connected! Reason: "); 79 | return false; 80 | break; 81 | case WL_CONNECTION_LOST: 82 | ESP_LOGI(TAG,"[WiFi] Connection was lost"); 83 | break; 84 | case WL_SCAN_COMPLETED: 85 | ESP_LOGI(TAG,"[WiFi] Scan is completed"); 86 | break; 87 | case WL_DISCONNECTED: 88 | ESP_LOGI(TAG,"[WiFi] WiFi is disconnected"); 89 | break; 90 | case WL_CONNECTED: 91 | ESP_LOGI(TAG,"[WiFi] WiFi is connected, IP address %s",WiFi.localIP().toString().c_str()); 92 | return true; 93 | break; 94 | default: 95 | ESP_LOGI(TAG,"[WiFi] WiFi Status: %d",WiFi.status()); 96 | break; 97 | } 98 | delay(tryDelay); 99 | 100 | if (numberOfTries <= 0) { 101 | ESP_LOGI(TAG,"[WiFi] Failed to connect to WiFi!"); 102 | // Use disconnect function to force stop trying to connect 103 | WiFi.disconnect(); 104 | return false; 105 | } 106 | else numberOfTries--; 107 | } 108 | 109 | return false; 110 | } // end connectToWifi 111 | 112 | void setup() { 113 | Serial.begin(115200); 114 | delay(10); 115 | 116 | // Wifi 117 | if (connectToWifi()) { // set up our esp32 to listen on the local_hostname.local domain 118 | if (!MDNS.begin(local_hostname)) { 119 | ESP_LOGE(TAG,"Error starting mDNS"); 120 | return; 121 | } 122 | MDNS.addService("http", "tcp", 80); 123 | 124 | if(!LittleFS.begin()) { 125 | ESP_LOGI(TAG,"ERROR : LittleFS Mount Failed."); 126 | return; 127 | } 128 | 129 | //setup server config stuff here 130 | server.config.max_uri_handlers = 20; //maximum number of uri handlers (.on() calls) 131 | server.listen(80); 132 | 133 | DefaultHeaders::Instance().addHeader("Server", "PsychicHttp"); 134 | 135 | // captive portal 136 | dnsServer.start(53, "*", WiFi.softAPIP()); // DNS requests are executed over port 53 (standard) 137 | captivehandler= new CaptiveRequestHandler(); // create captive portal handler, important : after server.on since handlers are triggered on a first created/first trigerred basis 138 | server.addHandler(captivehandler); // captive portal handler (last handler) 139 | } // end set up our esp32 to listen on the local_hostname.local domain 140 | } // end setup 141 | 142 | void loop() { 143 | dnsServer.processNextRequest(); // captive portal 144 | } 145 | -------------------------------------------------------------------------------- /examples/arduino/arduino_captive_portal/images/accesspoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_captive_portal/images/accesspoint.png -------------------------------------------------------------------------------- /examples/arduino/arduino_captive_portal/images/station.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_captive_portal/images/station.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/code.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/code.bin -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/data/update.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | PSYCHICHTTP 4 | 5 | 6 | 7 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

PsychicHttp OTA Update

88 |
89 | 90 |

This page allows to test OTA update with PsychicHttp, and file naming convention below : 91 |

    92 |
  • "*code.bin" for code (firmware) update, eg "v1_code.bin"
  • 93 |
  • "*littlefs.bin" for data (littlefs) update, eg "v1_littlefs.bin"
  • 94 |
95 |
96 | 97 |
98 |
99 | 106 |
107 |
108 | 109 |
110 |

Update must be done for each of the files provided (code, littlefs). Once updates are made, the ESP32 can be restarted. 111 | 112 |

113 |
114 | 115 | 116 | 166 | -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/images/otaupdate1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/images/otaupdate1.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/images/otaupdate2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/images/otaupdate2.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/images/otaupdate3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/images/otaupdate3.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/images/otaupdate4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/images/otaupdate4.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/images/otaupdate5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/images/otaupdate5.png -------------------------------------------------------------------------------- /examples/arduino/arduino_ota/littlefs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/arduino_ota/littlefs.bin -------------------------------------------------------------------------------- /examples/arduino/data/custom.txt: -------------------------------------------------------------------------------- 1 | Custom text file. -------------------------------------------------------------------------------- /examples/arduino/data/img/request_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/data/img/request_flow.png -------------------------------------------------------------------------------- /examples/arduino/data/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx 4 | MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ 5 | UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 6 | ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T 7 | sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k 8 | qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd 9 | GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4 10 | sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb 11 | jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/ 12 | ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud 13 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3 14 | emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY 15 | W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx 16 | bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN 17 | ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl 18 | hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo= 19 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/arduino/data/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH 3 | JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw 4 | h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT 5 | aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al 6 | 3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg 7 | 0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB 8 | vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui 9 | f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9 10 | Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y 11 | JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX 12 | 49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc 13 | +3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6 14 | pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D 15 | 0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG 16 | YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV 17 | MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL 18 | CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin 19 | 7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1 20 | noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8 21 | 4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g 22 | Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/ 23 | nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3 24 | q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2 25 | lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB 26 | jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr 27 | v/t+MeGJP/0Zw8v/X2CFll96 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /examples/arduino/data/www-ap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PsychicHTTP SoftAP Demo 7 | 8 | 9 | 10 |
11 |

SoftAP Demo

12 |

You are connected to the ESP in SoftAP mode.

13 |
14 | 15 | -------------------------------------------------------------------------------- /examples/arduino/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/data/www/alien.png -------------------------------------------------------------------------------- /examples/arduino/data/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/arduino/data/www/favicon.ico -------------------------------------------------------------------------------- /examples/arduino/data/www/text.txt: -------------------------------------------------------------------------------- 1 | Test File. 2 | -------------------------------------------------------------------------------- /examples/arduino/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "Your_SSID" 2 | #define WIFI_PASS "Your_PASS" -------------------------------------------------------------------------------- /examples/esp-idf/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig 3 | sdkconfig.old 4 | components/ 5 | managed_components/ 6 | dependencies.lock 7 | -------------------------------------------------------------------------------- /examples/esp-idf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 5 | 6 | if(DEFINED ENV{HTTP_PATH}) 7 | set(HTTP_PATH $ENV{HTTP_PATH}) 8 | else() 9 | #these both work 10 | set(HTTP_PATH "../../") 11 | #set(HTTP_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../) 12 | 13 | #this does not work for me... 14 | #set(HTTP_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../PsychicHttp) 15 | endif(DEFINED ENV{HTTP_PATH}) 16 | 17 | set(EXTRA_COMPONENT_DIRS ${HTTP_PATH}) 18 | if(${IDF_VERSION_MAJOR} LESS "5") 19 | include_directories("managed_components/joltwallet__littlefs/include") 20 | endif() 21 | 22 | project(PsychicHttp_IDF) 23 | -------------------------------------------------------------------------------- /examples/esp-idf/README.md: -------------------------------------------------------------------------------- 1 | # PsychicHttp - ESP IDF Example 2 | * Download and install [ESP IDF 4.4.7](https://github.com/espressif/esp-idf/releases/tag/v4.4.7) (or later version) 3 | * Clone the project: ```git clone --recursive git@github.com:hoeken/PsychicHttp.git``` 4 | * Run build command: ```cd PsychicHttp/examples/esp-idf``` and then ```idf.py build``` 5 | * Flash the LittleFS filesystem: ```esptool.py write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x317000 build/littlefs.bin``` 6 | * Flash the app firmware: ```idf.py flash monitor``` and visit the IP address shown in the console with a web browser. 7 | * Learn more about [Arduino as ESP-IDF Component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) 8 | -------------------------------------------------------------------------------- /examples/esp-idf/data/custom.txt: -------------------------------------------------------------------------------- 1 | Custom text file. -------------------------------------------------------------------------------- /examples/esp-idf/data/img/request_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/esp-idf/data/img/request_flow.png -------------------------------------------------------------------------------- /examples/esp-idf/data/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx 4 | MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ 5 | UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 6 | ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T 7 | sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k 8 | qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd 9 | GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4 10 | sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb 11 | jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/ 12 | ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud 13 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3 14 | emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY 15 | W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx 16 | bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN 17 | ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl 18 | hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo= 19 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/esp-idf/data/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH 3 | JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw 4 | h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT 5 | aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al 6 | 3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg 7 | 0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB 8 | vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui 9 | f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9 10 | Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y 11 | JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX 12 | 49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc 13 | +3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6 14 | pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D 15 | 0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG 16 | YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV 17 | MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL 18 | CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin 19 | 7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1 20 | noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8 21 | 4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g 22 | Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/ 23 | nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3 24 | q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2 25 | lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB 26 | jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr 27 | v/t+MeGJP/0Zw8v/X2CFll96 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /examples/esp-idf/data/www-ap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PsychicHTTP SoftAP Demo 7 | 8 | 9 | 10 |
11 |

SoftAP Demo

12 |

You are connected to the ESP in SoftAP mode.

13 |
14 | 15 | -------------------------------------------------------------------------------- /examples/esp-idf/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/esp-idf/data/www/alien.png -------------------------------------------------------------------------------- /examples/esp-idf/data/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/esp-idf/data/www/favicon.ico -------------------------------------------------------------------------------- /examples/esp-idf/data/www/text.txt: -------------------------------------------------------------------------------- 1 | Test File. 2 | -------------------------------------------------------------------------------- /examples/esp-idf/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 | -------------------------------------------------------------------------------- /examples/esp-idf/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 | -------------------------------------------------------------------------------- /examples/esp-idf/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file was automatically generated for projects 2 | # without default 'CMakeLists.txt' file. 3 | 4 | idf_component_register( 5 | SRCS "main.cpp" 6 | INCLUDE_DIRS ".") 7 | 8 | littlefs_create_partition_image(littlefs ${project_dir}/data) 9 | -------------------------------------------------------------------------------- /examples/esp-idf/main/idf_component.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | joltwallet/littlefs: ^1.16.4 3 | -------------------------------------------------------------------------------- /examples/esp-idf/main/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "WIFI_SSID" 2 | #define WIFI_PASS "WIFI_PASS" -------------------------------------------------------------------------------- /examples/esp-idf/partitions_custom.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x11000, 0xC000 3 | otadata, data, ota, 0x1D000, 0x2000 4 | phy_init, data, phy, 0x1F000, 0x1000 5 | app0, app, ota_0, 0x20000, 0x177000 6 | app1, app, ota_1, 0x1A0000, 0x177000 7 | littlefs, data, spiffs, 0x317000, 0xE1000 -------------------------------------------------------------------------------- /examples/esp-idf/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_AUTOSTART_ARDUINO=y 2 | # CONFIG_WS2812_LED_ENABLE is not set 3 | CONFIG_FREERTOS_HZ=1000 4 | 5 | CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y 6 | CONFIG_COMPILER_OPTIMIZATION_SIZE=y 7 | 8 | # 9 | # Serial flasher config 10 | # 11 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 12 | CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y 13 | CONFIG_ESPTOOLPY_FLASHSIZE="4MB" 14 | 15 | # 16 | # Partition Table 17 | # 18 | CONFIG_PARTITION_TABLE_CUSTOM=y 19 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_custom.csv" 20 | #CONFIG_PARTITION_TABLE_FILENAME="partitions_custom.csv" 21 | #CONFIG_PARTITION_TABLE_OFFSET=0xE000 22 | CONFIG_PARTITION_TABLE_MD5=y 23 | 24 | # 25 | # ESP HTTPS OTA 26 | # 27 | CONFIG_ESP_HTTPS_OTA_DECRYPT_CB=y 28 | CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y 29 | # end of ESP HTTPS OTA 30 | 31 | 32 | # 33 | # ESP HTTP client 34 | # 35 | CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y 36 | CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y 37 | CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y 38 | # end of ESP HTTP client 39 | 40 | # 41 | # HTTP Server 42 | # 43 | CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 44 | CONFIG_HTTPD_MAX_URI_LEN=512 45 | CONFIG_HTTPD_ERR_RESP_NO_DELAY=y 46 | CONFIG_HTTPD_PURGE_BUF_LEN=32 47 | # CONFIG_HTTPD_LOG_PURGE_DATA is not set 48 | CONFIG_HTTPD_WS_SUPPORT=y 49 | # end of HTTP Server 50 | 51 | # 52 | # ESP HTTPS server 53 | # 54 | CONFIG_ESP_HTTPS_SERVER_ENABLE=n 55 | # end of ESP HTTPS server 56 | 57 | 58 | # 59 | # TLS Key Exchange Methods 60 | # 61 | # 2 option require for arduino Arduino 62 | CONFIG_MBEDTLS_PSK_MODES=y 63 | CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y 64 | 65 | -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .clang_complete 3 | .gcc-flags.json 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | # Fortran module files 17 | *.mod 18 | # Compiled Static libraries 19 | *.lai 20 | *.la 21 | *.a 22 | *.lib 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | # Visual Studio/VisualMicro stuff 28 | Visual\ Micro 29 | *.sdf 30 | *.opensdf 31 | *.suo 32 | .pioenvs 33 | .piolibdeps 34 | .pio 35 | .vscode/c_cpp_properties.json 36 | .vscode/launch.json 37 | .vscode/settings.json 38 | .vscode/.browse.c_cpp.db* 39 | .vscode/ipch -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/.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 | -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/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 | -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/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 | -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/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 | [common] 12 | lib_deps = ArduinoMongoose 13 | monitor_speed = 115200 14 | monitor_port = /dev/ttyUSB1 15 | build_flags = 16 | -DENABLE_DEBUG 17 | # -DCS_ENABLE_STDIO 18 | -DMG_ENABLE_HTTP_STREAMING_MULTIPART=1 19 | 20 | build_flags_secure = 21 | -DSIMPLE_SERVER_SECURE 22 | -DMG_ENABLE_SSL=1 23 | 24 | # -DMG_SSL_IF=MG_SSL_IF_OPENSSL 25 | # -DKR_VERSION 26 | 27 | -DMG_SSL_MBED_DUMMY_RANDOM=1 28 | -DMG_SSL_IF=MG_SSL_IF_MBEDTLS 29 | -DMG_SSL_IF_MBEDTLS_FREE_CERTS=1 30 | -DMG_SSL_IF_MBEDTLS_MAX_FRAG_LEN=2048 31 | 32 | build_flags_auth = 33 | -DADMIN_USER='"admin"' 34 | -DADMIN_PASS='"admin"' 35 | -DADMIN_REALM='"esp_ota_http_server"' 36 | 37 | #[env:huzzah] 38 | #platform = espressif8266 39 | #board = huzzah 40 | #framework = arduino 41 | #monitor_speed = ${common.monitor_speed} 42 | #monitor_port = ${common.monitor_port} 43 | #lib_deps = ${common.lib_deps} 44 | #build_flags = ${common.build_flags} 45 | 46 | [env:esp-wrover-kit] 47 | platform = espressif32 48 | framework = arduino 49 | board = esp-wrover-kit 50 | monitor_speed = ${common.monitor_speed} 51 | monitor_port = ${common.monitor_port} 52 | lib_deps = ${common.lib_deps} 53 | build_flags = ${common.build_flags} 54 | 55 | [env:esp-wrover-kit-secure] 56 | platform = espressif32 57 | framework = arduino 58 | board = esp-wrover-kit 59 | monitor_speed = ${common.monitor_speed} 60 | monitor_port = ${common.monitor_port} 61 | lib_deps = ${common.lib_deps} 62 | build_flags = ${common.build_flags} ${common.build_flags_secure} 63 | 64 | [env:esp-wrover-kit-auth] 65 | extends = env:esp-wrover-kit 66 | build_flags = ${common.build_flags} ${common.build_flags_auth} -ggdb 67 | 68 | #[env:linux_x86_64] 69 | #platform = linux_x86_64 70 | #framework = arduino 71 | #board = generic 72 | #lib_deps = ${common.lib_deps} 73 | #build_flags = ${common.build_flags} 74 | #build_flags = -DSERIAL_TO_CONSOLE -------------------------------------------------------------------------------- /examples/old/esp_ota_http_server/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 | -------------------------------------------------------------------------------- /examples/old/simple_http_server/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .clang_complete 3 | .gcc-flags.json 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | # Fortran module files 17 | *.mod 18 | # Compiled Static libraries 19 | *.lai 20 | *.la 21 | *.a 22 | *.lib 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | # Visual Studio/VisualMicro stuff 28 | Visual\ Micro 29 | *.sdf 30 | *.opensdf 31 | *.suo 32 | .pioenvs 33 | .piolibdeps 34 | .pio 35 | .vscode/c_cpp_properties.json 36 | .vscode/launch.json 37 | .vscode/settings.json 38 | .vscode/.browse.c_cpp.db* 39 | .vscode/ipch -------------------------------------------------------------------------------- /examples/old/simple_http_server/.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 | -------------------------------------------------------------------------------- /examples/old/simple_http_server/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 | -------------------------------------------------------------------------------- /examples/old/simple_http_server/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 | -------------------------------------------------------------------------------- /examples/old/simple_http_server/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 | [common] 12 | lib_deps = ArduinoMongoose 13 | monitor_speed = 115200 14 | monitor_port = /dev/ttyUSB1 15 | build_flags = 16 | -DENABLE_DEBUG 17 | # -DCS_ENABLE_STDIO 18 | 19 | build_flags_secure = 20 | -DSIMPLE_SERVER_SECURE 21 | -DMG_ENABLE_SSL=1 22 | 23 | # -DMG_SSL_IF=MG_SSL_IF_OPENSSL 24 | # -DKR_VERSION 25 | 26 | -DMG_SSL_MBED_DUMMY_RANDOM=1 27 | -DMG_SSL_IF=MG_SSL_IF_MBEDTLS 28 | -DMG_SSL_IF_MBEDTLS_FREE_CERTS=1 29 | -DMG_SSL_IF_MBEDTLS_MAX_FRAG_LEN=2048 30 | 31 | [env:huzzah] 32 | platform = espressif8266 33 | board = huzzah 34 | framework = arduino 35 | monitor_speed = ${common.monitor_speed} 36 | monitor_port = ${common.monitor_port} 37 | lib_deps = ${common.lib_deps} 38 | build_flags = ${common.build_flags} 39 | 40 | [env:esp-wrover-kit] 41 | platform = espressif32 42 | framework = arduino 43 | board = esp-wrover-kit 44 | monitor_speed = ${common.monitor_speed} 45 | monitor_port = ${common.monitor_port} 46 | lib_deps = ${common.lib_deps} 47 | build_flags = ${common.build_flags} 48 | 49 | [env:esp-wrover-kit-secure] 50 | platform = espressif32 51 | framework = arduino 52 | board = esp-wrover-kit 53 | monitor_speed = ${common.monitor_speed} 54 | monitor_port = ${common.monitor_port} 55 | lib_deps = ${common.lib_deps} 56 | build_flags = ${common.build_flags} ${common.build_flags_secure} 57 | 58 | #[env:linux_x86_64] 59 | #platform = linux_x86_64 60 | #framework = arduino 61 | #board = generic 62 | #lib_deps = ${common.lib_deps} 63 | #build_flags = ${common.build_flags} 64 | #build_flags = -DSERIAL_TO_CONSOLE -------------------------------------------------------------------------------- /examples/old/simple_http_server/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 | -------------------------------------------------------------------------------- /examples/old/simple_http_server/test/tests.rest: -------------------------------------------------------------------------------- 1 | # Name: REST Client 2 | # Id: humao.rest-client 3 | # Description: REST Client for Visual Studio Code 4 | # Version: 0.21.3 5 | # Publisher: Huachao Mao 6 | # VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=humao.rest-client 7 | 8 | @baseUrl = http://172.16.0.87 9 | 10 | ### 11 | 12 | GET {{baseUrl}}/ HTTP/1.1 13 | 14 | ### 15 | 16 | GET {{baseUrl}}/get?message=Hello+World HTTP/1.1 17 | 18 | ### 19 | 20 | POST {{baseUrl}}/post HTTP/1.1 21 | Content-Type: application/x-www-form-urlencoded;charset=UTF-8 22 | 23 | message=Hello+World 24 | 25 | ### 26 | 27 | GET {{baseUrl}}/someRandomFile HTTP/1.1 28 | 29 | ### 30 | 31 | GET {{baseUrl}}/basic HTTP/1.1 32 | 33 | ### 34 | 35 | GET {{baseUrl}}/stream HTTP/1.1 36 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .clang_complete 3 | .gcc-flags.json 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | # Fortran module files 17 | *.mod 18 | # Compiled Static libraries 19 | *.lai 20 | *.la 21 | *.a 22 | *.lib 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | # Visual Studio/VisualMicro stuff 28 | Visual\ Micro 29 | *.sdf 30 | *.opensdf 31 | *.suo 32 | .pioenvs 33 | .piolibdeps 34 | .pio 35 | .vscode/c_cpp_properties.json 36 | .vscode/launch.json 37 | .vscode/settings.json 38 | .vscode/.browse.c_cpp.db* 39 | .vscode/ipch -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/.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 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/.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 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/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 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/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 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/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 | [common] 12 | lib_deps = ArduinoMongoose 13 | monitor_speed = 115200 14 | build_flags = 15 | 16 | [espressif8266] 17 | build_flags = -DMG_ESP8266 18 | 19 | [espressif32] 20 | build_flags = 21 | 22 | [env:huzzah] 23 | platform = espressif8266 24 | framework = arduino 25 | board = huzzah 26 | monitor_speed = ${common.monitor_speed} 27 | lib_deps = ${common.lib_deps} 28 | build_flags = 29 | ${espressif8266.build_flags} 30 | ${common.build_flags} 31 | 32 | [env:espwroverkit] 33 | platform = espressif32 34 | framework = arduino 35 | board = esp-wrover-kit 36 | monitor_speed = ${common.monitor_speed} 37 | lib_deps = ${common.lib_deps} 38 | build_flags = 39 | ${espressif32.build_flags} 40 | ${common.build_flags} 41 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/src/simplest_web_server.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Cesanta Software Limited 2 | // All rights reserved 3 | 4 | #include 5 | 6 | #ifdef ESP32 7 | #include 8 | #elif defined(ESP8266) 9 | #include 10 | #else 11 | #error Platform not supported 12 | #endif 13 | 14 | #include "mongoose.h" 15 | 16 | const char* ssid = "my-ssid"; 17 | const char* password = "my-password"; 18 | 19 | static const char *s_http_port = "80"; 20 | //static struct mg_serve_http_opts s_http_server_opts; 21 | 22 | static void ev_handler(struct mg_connection *nc, int ev, void *p, void *d) { 23 | static const char *reply_fmt = 24 | "HTTP/1.0 200 OK\r\n" 25 | "Connection: close\r\n" 26 | "Content-Type: text/plain\r\n" 27 | "\r\n" 28 | "Hello %s\n"; 29 | 30 | switch (ev) { 31 | case MG_EV_ACCEPT: { 32 | char addr[32]; 33 | mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), 34 | MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); 35 | Serial.printf("Connection %p from %s\n", nc, addr); 36 | break; 37 | } 38 | case MG_EV_HTTP_REQUEST: { 39 | char addr[32]; 40 | struct http_message *hm = (struct http_message *) p; 41 | mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), 42 | MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); 43 | Serial.printf("HTTP request from %s: %.*s %.*s\n", addr, (int) hm->method.len, 44 | hm->method.p, (int) hm->uri.len, hm->uri.p); 45 | mg_printf(nc, reply_fmt, addr); 46 | nc->flags |= MG_F_SEND_AND_CLOSE; 47 | break; 48 | } 49 | case MG_EV_CLOSE: { 50 | Serial.printf("Connection %p closed\n", nc); 51 | break; 52 | } 53 | } 54 | } 55 | 56 | struct mg_mgr mgr; 57 | struct mg_connection *nc; 58 | 59 | void setup() 60 | { 61 | Serial.begin(115200); 62 | 63 | Serial.print("Connecting to "); 64 | Serial.println(ssid); 65 | 66 | WiFi.begin(ssid, password); 67 | 68 | while (WiFi.status() != WL_CONNECTED) { 69 | delay(500); 70 | Serial.print("."); 71 | } 72 | 73 | Serial.println(""); 74 | Serial.println("WiFi connected"); 75 | Serial.println("IP address: "); 76 | Serial.println(WiFi.localIP()); 77 | 78 | mg_mgr_init(&mgr, NULL); 79 | Serial.printf("Starting web server on port %s\n", s_http_port); 80 | nc = mg_bind(&mgr, s_http_port, ev_handler, NULL); 81 | if (nc == NULL) { 82 | Serial.printf("Failed to create listener\n"); 83 | return; 84 | } 85 | 86 | // Set up HTTP server parameters 87 | mg_set_protocol_http_websocket(nc); 88 | // s_http_server_opts.document_root = "."; // Serve current directory 89 | // s_http_server_opts.enable_directory_listing = "yes"; 90 | } 91 | 92 | static uint32_t count = 0; 93 | void loop() 94 | { 95 | mg_mgr_poll(&mgr, 1000); 96 | //Serial.println(count++); 97 | } 98 | -------------------------------------------------------------------------------- /examples/old/simplest_web_server_esp/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 | -------------------------------------------------------------------------------- /examples/old/websocket_chat/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .clang_complete 3 | .gcc-flags.json 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | # Fortran module files 17 | *.mod 18 | # Compiled Static libraries 19 | *.lai 20 | *.la 21 | *.a 22 | *.lib 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | # Visual Studio/VisualMicro stuff 28 | Visual\ Micro 29 | *.sdf 30 | *.opensdf 31 | *.suo 32 | .pioenvs 33 | .piolibdeps 34 | .pio 35 | .vscode/c_cpp_properties.json 36 | .vscode/launch.json 37 | .vscode/settings.json 38 | .vscode/.browse.c_cpp.db* 39 | .vscode/ipch -------------------------------------------------------------------------------- /examples/old/websocket_chat/.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 | -------------------------------------------------------------------------------- /examples/old/websocket_chat/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 | -------------------------------------------------------------------------------- /examples/old/websocket_chat/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 | -------------------------------------------------------------------------------- /examples/old/websocket_chat/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 | [common] 12 | lib_deps = ArduinoMongoose 13 | monitor_speed = 115200 14 | monitor_port = /dev/ttyUSB2 15 | build_flags = 16 | -DENABLE_DEBUG 17 | # -DCS_ENABLE_STDIO 18 | 19 | build_flags_secure = 20 | -DSIMPLE_SERVER_SECURE 21 | -DMG_ENABLE_SSL=1 22 | 23 | # -DMG_SSL_IF=MG_SSL_IF_OPENSSL 24 | # -DKR_VERSION 25 | 26 | -DMG_SSL_MBED_DUMMY_RANDOM=1 27 | -DMG_SSL_IF=MG_SSL_IF_MBEDTLS 28 | -DMG_SSL_IF_MBEDTLS_FREE_CERTS=1 29 | -DMG_SSL_IF_MBEDTLS_MAX_FRAG_LEN=2048 30 | 31 | [env:huzzah] 32 | platform = espressif8266 33 | board = huzzah 34 | framework = arduino 35 | monitor_speed = ${common.monitor_speed} 36 | monitor_port = ${common.monitor_port} 37 | lib_deps = ${common.lib_deps} 38 | build_flags = ${common.build_flags} 39 | 40 | [env:esp-wrover-kit] 41 | platform = espressif32 42 | framework = arduino 43 | board = esp-wrover-kit 44 | monitor_speed = ${common.monitor_speed} 45 | monitor_port = ${common.monitor_port} 46 | lib_deps = ${common.lib_deps} 47 | build_flags = ${common.build_flags} 48 | 49 | [env:esp-wrover-kit-secure] 50 | platform = espressif32 51 | framework = arduino 52 | board = esp-wrover-kit 53 | monitor_speed = ${common.monitor_speed} 54 | monitor_port = ${common.monitor_port} 55 | lib_deps = ${common.lib_deps} 56 | build_flags = ${common.build_flags} ${common.build_flags_secure} 57 | 58 | #[env:linux_x86_64] 59 | #platform = linux_x86_64 60 | #framework = arduino 61 | #board = generic 62 | #lib_deps = ${common.lib_deps} 63 | #build_flags = ${common.build_flags} 64 | #build_flags = -DSERIAL_TO_CONSOLE -------------------------------------------------------------------------------- /examples/old/websocket_chat/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 | -------------------------------------------------------------------------------- /examples/old/websocket_chat/test/tests.rest: -------------------------------------------------------------------------------- 1 | # Name: REST Client 2 | # Id: humao.rest-client 3 | # Description: REST Client for Visual Studio Code 4 | # Version: 0.21.3 5 | # Publisher: Huachao Mao 6 | # VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=humao.rest-client 7 | 8 | @baseUrl = http://172.16.0.87 9 | 10 | ### 11 | 12 | GET {{baseUrl}}/ HTTP/1.1 13 | 14 | ### 15 | 16 | GET {{baseUrl}}/get?message=Hello+World HTTP/1.1 17 | 18 | ### 19 | 20 | POST {{baseUrl}}/post HTTP/1.1 21 | Content-Type: application/x-www-form-urlencoded;charset=UTF-8 22 | 23 | message=Hello+World 24 | 25 | ### 26 | 27 | GET {{baseUrl}}/someRandomFile HTTP/1.1 28 | 29 | ### 30 | 31 | GET {{baseUrl}}/basic HTTP/1.1 32 | 33 | ### 34 | 35 | GET {{baseUrl}}/stream HTTP/1.1 36 | -------------------------------------------------------------------------------- /examples/platformio/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | -------------------------------------------------------------------------------- /examples/platformio/data/custom.txt: -------------------------------------------------------------------------------- 1 | Custom text file. -------------------------------------------------------------------------------- /examples/platformio/data/img/request_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/platformio/data/img/request_flow.png -------------------------------------------------------------------------------- /examples/platformio/data/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx 4 | MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ 5 | UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 6 | ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T 7 | sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k 8 | qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd 9 | GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4 10 | sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb 11 | jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/ 12 | ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud 13 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3 14 | emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY 15 | W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx 16 | bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN 17 | ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl 18 | hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo= 19 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/platformio/data/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH 3 | JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw 4 | h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT 5 | aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al 6 | 3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg 7 | 0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB 8 | vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui 9 | f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9 10 | Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y 11 | JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX 12 | 49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc 13 | +3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6 14 | pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D 15 | 0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG 16 | YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV 17 | MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL 18 | CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin 19 | 7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1 20 | noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8 21 | 4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g 22 | Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/ 23 | nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3 24 | q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2 25 | lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB 26 | jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr 27 | v/t+MeGJP/0Zw8v/X2CFll96 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /examples/platformio/data/www-ap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PsychicHTTP SoftAP Demo 7 | 8 | 9 | 10 |
11 |

SoftAP Demo

12 |

You are connected to the ESP in SoftAP mode.

13 |
14 | 15 | -------------------------------------------------------------------------------- /examples/platformio/data/www/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/platformio/data/www/alien.png -------------------------------------------------------------------------------- /examples/platformio/data/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/platformio/data/www/favicon.ico -------------------------------------------------------------------------------- /examples/platformio/data/www/text.txt: -------------------------------------------------------------------------------- 1 | Test File. 2 | -------------------------------------------------------------------------------- /examples/platformio/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 | -------------------------------------------------------------------------------- /examples/platformio/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 | -------------------------------------------------------------------------------- /examples/platformio/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32-s3-devkitc-1 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | ; devmode: with this disabled make a symlink from platformio/lib to the PsychicHttp directory 19 | ;hoeken/PsychicHttp 20 | bblanchon/ArduinoJson 21 | board_build.filesystem = littlefs 22 | 23 | [env:default] 24 | build_flags = 25 | -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_WARN 26 | ;-D ENABLE_ASYNC 27 | 28 | ; [env:arduino3] 29 | ; platform = https://github.com/platformio/platform-espressif32.git 30 | ; platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master -------------------------------------------------------------------------------- /examples/platformio/src/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "Your_SSID" 2 | #define WIFI_PASS "Your_PASS" -------------------------------------------------------------------------------- /examples/platformio/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /examples/websockets/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/ 3 | .vscode/.browse.c_cpp.db* 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | .vscode/ipch 7 | src/_secret.h 8 | lib/PsychicHttp/ -------------------------------------------------------------------------------- /examples/websockets/data/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoeken/PsychicHttp/725f415a1352f86a3d47a94aee8ef9eec8aa2127/examples/websockets/data/www/favicon.ico -------------------------------------------------------------------------------- /examples/websockets/data/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PsychicHTTP Websocket Demo 7 | 8 | 9 | 10 |
11 |

Websocket Demo

12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 74 |
75 | 76 | -------------------------------------------------------------------------------- /examples/websockets/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 | -------------------------------------------------------------------------------- /examples/websockets/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 | -------------------------------------------------------------------------------- /examples/websockets/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] 12 | platform = espressif32 13 | framework = arduino 14 | board = esp32dev 15 | monitor_speed = 115200 16 | monitor_filters = esp32_exception_decoder 17 | lib_deps = 18 | ; devmode: with this disabled make a symlink from platformio/lib to the PsychicHttp directory 19 | ;hoeken/PsychicHttp 20 | bblanchon/ArduinoJson 21 | board_build.filesystem = littlefs 22 | 23 | [env:default] 24 | build_flags = 25 | -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_WARN -------------------------------------------------------------------------------- /examples/websockets/src/secret.h: -------------------------------------------------------------------------------- 1 | #define WIFI_SSID "Your_SSID" 2 | #define WIFI_PASS "Your_PASS" -------------------------------------------------------------------------------- /examples/websockets/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | version: "1.2.1" 3 | license: "MIT" 4 | description: "Asyncronous Webserver library for ESP32 + Arduino framework" 5 | url: "https://github.com/hoeken/PsychicHttp" 6 | repository: "https://github.com/hoeken/PsychicHttp" 7 | documentation: "https://h2zero.github.io/esp-nimble-cpp/" 8 | tags: 9 | - webserver 10 | - websocket 11 | - http 12 | - https 13 | 14 | dependencies: 15 | bblanchon/arduinojson: ^7.3.0 16 | urlencode: 17 | git: "https://github.com/dzungpv/urlencode.git" 18 | version: "cb71cbf2828683e5ff2b1afd89289d932ba8866b" 19 | espressif/arduino-esp32: 20 | matches: 21 | - if: "idf_version ^4" 22 | version: "^2" 23 | - if: "idf_version ^5.1" 24 | version: "^3.0" 25 | - if: "idf_version ^5.3" 26 | version: "^3.1" 27 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PsychicHttp", 3 | "version": "1.2.1", 4 | "description": "Arduino style wrapper around ESP-IDF HTTP library. HTTP server with SSL + websockets. Works on esp32 and probably esp8266", 5 | "keywords": "network,http,https,tcp,ssl,tls,websocket,espasyncwebserver", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/hoeken/PsychicHttp" 10 | }, 11 | "authors": 12 | [ 13 | { 14 | "name": "Zach Hoeken", 15 | "email": "hoeken@gmail.com", 16 | "maintainer": true 17 | } 18 | ], 19 | "license" : "MIT", 20 | "examples": [ 21 | { 22 | "name": "platformio", 23 | "base": "examples/platformio", 24 | "files": [ 25 | "src/main.cpp" 26 | ] 27 | } 28 | ], 29 | "frameworks": "arduino", 30 | "platforms": "espressif32", 31 | "dependencies": [ 32 | { 33 | "owner": "bblanchon", 34 | "name": "ArduinoJson", 35 | "version": "^7.0.4" 36 | }, 37 | { 38 | "owner": "plageoj", 39 | "name" : "UrlEncode", 40 | "version" : "^1.0.1" 41 | } 42 | ], 43 | "export": { 44 | "include": [ 45 | "examples/platformio", 46 | "src", 47 | "library.json", 48 | "library.properties", 49 | "LICENSE", 50 | "README.md" 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=PsychicHttp 2 | version=1.2.1 3 | author=Zach Hoeken 4 | maintainer=Zach Hoeken 5 | sentence=PsychicHttp is a robust webserver that supports http/https + websockets. 6 | paragraph=This library is based on the ESP-IDF HTTP Server library which is asynchronous, does http / https+ssl and supports websockets. 7 | category=Communication 8 | architectures=esp32 9 | url=https://github.com/hoeken/PsychicHttp 10 | includes=PsychicHttp.h 11 | depends=ArduinoJson,UrlEncode -------------------------------------------------------------------------------- /request flow.drawio: -------------------------------------------------------------------------------- 1 | 7Vxbd5s4EP41Pmf3wTkgAcaPza3Zbq/bbNM+yiAbNhi5ICd2f/0KIxmQFIypsZ1jpw+1hBCS5pv5ZgaJHryaLt4maBZ8ID6OesDwFz143QPANIDD/stqlnnNwIJ5xSQJfd6oqPga/sLiTl47D32cVhpSQiIazqqVHolj7NFKHUoS8lxtNiZR9akzNMFKxVcPRWrtQ+jTIK91waCov8PhJBBPNp1hfmWKRGM+kzRAPnkuVcGbHrxKCKH5r+niCkfZ4ol1efhr+RC9f3TevvuS/kT/Xv59//FbP+/sdptb1lNIcExbd+0/B97S/uJ9MrxvX76P0/f9+Gff5MvwhKI5XzA+WboUK5iQeezjrBezBy+fg5DirzPkZVefGWZYXUCnEb+8XiSDFcYkphwRbL3ZRXZbGE9Y0c6uhlF0RSKSrB4Dx3b2j99Vqs//srtpQh5x6Yqz+mNXGq4PX8cnnFC8KKGDr9dbTKaYJkvWRFwVIObYN21efi6QZA95XVBCkevwSsTRO1n3XUiI/eBC0gvsevkufbie3t/Yd9blDfz0bvHQ70NzG4EZVeH8hyldcoGgOSWsiiQ0IBMSo+g9ITPeriQ3Myvj2H+TqSIrjyLiPeZVt2E29NUzWIm3d9eCEtqmoCJCIxxdIu9xshqoEGhMYpx15TP15XMpBndT1LKHsYX8nnV2YYvij/VAWOF6USktRWkR0tJtrPSDDy/7XdyUFcQ9KUUJFXPnI9wObSmZJx6uUUEuP/agCaZ1kueQyhaoFrwJjhANn6r2TwdEfutnErKJrEEPbFgBPRyCahf5jPhdZYOzoSPbkDrKp6x0tNKL9XwaqYpWAODkNaU9UrXtoIpUbTtn10BtajHrRl2Cwd39/WdW8w/+Occp/T2+KwOAzfFyEqE0XRuPWulK/Ocj7I49Lc95Lh6Nu+Q5t6qpQGhqiedMoOE5awc0p52CpQjtB3MiT0x92xLdjtXeaaj2ptlQ7znq+sYFgIZbQV7f5N53WxITTch4nOJ6foKGdVB+shWMfyQKxDej5FUrQTdQ3YhA4c8b+wObVTWxljHYK9gcBWw3sT/jY/yAqBdkELpVTWxApqN52iLwu0XTMMpme4ejJ0xDD2noEkXhJGYFj8kfJ3o0rYNGpyjdr9DLaEINI8dj4Glp1HdGjt1puDiUPGdnoNKooQsXu6JRU40WP6dLLwi9OxT7EVvxs/MjOz+2uUfnRxvpaaR2it5Pi3B9/x6TXoCamH5XLpMNoC25TPtjMcuQWAxILNY2N2ANm9EhwydalpqtGCzVTErQrmSSLRfUj0um6Wp79iMfQVturoVLSd9XjJyxHnAiBqDLEbPUzoSuoOqgaWaH41Ga/ScM+Zm7f4sFZP9sr9ytR4WauLjGYzSPMrgWztvJ87cle12udWE3ZHC7K9mp+YvTi+0KMq5QccHMOyHjjXlzoUdHGBRam4LCpnQKZTo1O4su9Wus5jLOHuur8lib5vZbeKyOpST5Duix2m1VTNJVW3Z9d+Sx2rIqH6XHqqaTPuJnVnGV7+IISax1SA/jnBwyJSS/WXEbJhdAZ26luuMjxQmb0QWJP81wnAkRRdGImcFjkZ9vY9e3dPJzwQh2ugMEwqrpAoODJ4eGivxUx7KgRS9b9dCriqbKw4K2zBJpFRS2iba69O0205bm3VQt6jfSVnlnj0as9m8y1xpWktEWsNqalVw5ISN11LHjB9QgtUQBzJREJH3hxcLJc4Fra1IMe+UCoIapQZ5OYmSwEp2af1qTxQvXBXnUef8nwx6Sb+ZCt2lqQnZTdydzNVQ7Xf4AmrCnVlOOlD9Mw2ob1khGadgwEb8rAhG7GktwvA3jMA2OxXyMXQ/rCWPk2pa9PSjbE8YQNCSMzpxPCGoIg0cPPaC8o0hn2AvHzIoAwzvTw4v0MBCm+HDyVd25kyAH7cZstyE3CKU4Fm4wq6hybPNiWP5rSRTWVt3ujja0smmA0y6Tzes3HK9ub2ibHHV7vapNIZcVq+5kROcHHuTMrt0yGJc7GkCwV6VQXSnGdRQnf/yZ0fI5Bte4VPY+87H6E3iK0DwU55s6znJ7UW4OPLTcVE+YcUnAph16iJ5FVyO6g6ucmvVK8qNAbwoJhiTOZHgc0sMmi1IGOukNnQFE+4xRtNKzzD1K70TzV03PjtYh/kgjlIHV0uFSAmi5o44dLleBYp4N4ScLzwZEY/4HB2du9QVqgtMZiVN8kTLLcZaaRmpu00MR3fnJanRzULu/r+1adfZ8o90fHrfdbxtoy9sdlY52tRdLvPYRzg//FMJL45LbD7bcuzXY8d4tvSKpkcvpKpKhKlLtEY1j1ST56HJTTbLEkQaxed6W7PeONMmxqs8RX815aVxyewjr28vnfKT2HWnSkb0tOagmNd6Of9ya5LTXJAmBg272B8uaIcqvW5PUlIw4p0zprFf6VotxGzFlkrWMebW0qldVl5m/Vin717xKOcSW+cihh6I3/MI09P3VGxed21/VXuVzZ8q30PiIre10r7nbDiTh6T7kAsUOj7I2we3ddlYsvn2XA6H4giC8+R8=7Vtbc5s4FP41ntk+tGMQAvyYOLdNp9NOvTttn3ZkkDGNQA7It/z6FUayBcK3xNhMA34I5+iCdL5P5xwJ0gH9aHGfoMn4C/Ux6Zhdf9EBNx3TNLqmzf9kmmWucSyQK4Ik9EWljWIQvmDZUminoY/TQkVGKWHhpKj0aBxjjxV0KEnovFhtREnxqRMUYE0x8BDRtT9Cn41zrWs6G/0DDoOxfLJh9/KSCMnKYibpGPl0rqjAbQf0E0pZfhct+phkxpN2ue69/J493t0Yzy/92Xf/3v3nKviYd3Z3TJP1FBIcs9N2beZdzxCZCnuJubKlNGBCp7GPs06MDriej0OGBxPkZaVzThmuG7OIiOK1jbpcGNGYCUJwc/NC3iyMAy7CrDQkpE8JTVaPASOY/UQrRZ9fWWuW0CeslNiri5dEdIaGq+FmQ0hwGr6oMmWIKTInOFZl7IeqKHioaA60vkBphhOGFwr3BBr3mEaYJUteRZTyueVNxMoCUBBtvuEpsIVurHDUcoQSibURrPve4M9vBAWOoENPo8MPPHxAsU9w8jZiKFwwuE2uA4LSVPAkR1auTp1GRaL4CLsjr5IQnouHozoRc7sFxCwANcQMswqxugCTA1AQE3Clq2HxUZndPiJkiLynVIOQz5uVFnDBqDGNcQkBoUIkDGIuetzEnBvgOrNiyN3ulSiIQt/PHlNJjA11yn4CVjoRMWKrNmANWFyKbsVS7Dk6sOAEwBqfH8jEnz7+9yv4m4HH5+gruhe+XMWVxt/x8xSn7K8PjVmKELu+VbUUXXMIVr65LsQsGcDlUrQOXIpmXYgZGmIaTDj2r7KUJls3mdFDr4hMcVlwiyXLn6rwKxM+QSneLNTCm6WUFiH7KYMbv1dacWnTKBNkm+NgSuk08fD+OMJQEmC2w2YCC+wXcjgddAVUWIGp1CWYIBbOiplfFdDiCd9oyKercKrk3iEsdpHPW7RSU61yR3axI2Bbn3rqVew2N5PW7YqFayO8nph6jseD+oB6T5i1oX1baLfNM4b2SthARQT4OsFx6/4r3L/dvbT7tyrguktQhFu8qvA6NHOuDS89caZxn9C0xasSL/vSeNnvM73aFdH3pldWs9IroxhiofHa9Ao4uzuqOaFymkLF42i1ly6gWXTpljIy60R0sctp/Ra6cADRUqk2ySqkh/NbDnjruMr1jUJ9fpOP4KTcdf9Q7sJ3wl2zodx1zsBd/XT63wmhyG93sdt2sevIeLFdrORJe5B5YKYNL3+Q+U5PMnf5nL3xR/K8KQGodJQJwYmOMi3rNUeZbw1HcviHhiMIzxCODLPCteURqfVsVZ7t4md0hn5IdyHPdpzN93sfs1nep3sq71Pe6dvnSX+P9jfn2LoZ+pHl7YzzZ5DHsKY4nOZkv845P8+ohkw/tWxf4mwNEM6h79zqCxD68Uj7VmAHYBd/K2Dq28s/JKLbjY7ozqs/jQBbKFRzRHfgcRHdAWeI6GZjdtqnZq/7TthbTmybwt63HcdycfNZe159888B4PZ/ -------------------------------------------------------------------------------- /src/ChunkPrinter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ChunkPrinter.h" 3 | 4 | ChunkPrinter::ChunkPrinter(PsychicResponse *response, uint8_t *buffer, size_t len) : 5 | _response(response), 6 | _buffer(buffer), 7 | _length(len), 8 | _pos(0) 9 | {} 10 | 11 | ChunkPrinter::~ChunkPrinter() 12 | { 13 | flush(); 14 | } 15 | 16 | size_t ChunkPrinter::write(uint8_t c) 17 | { 18 | esp_err_t err; 19 | 20 | //if we're full, send a chunk 21 | if (_pos == _length) 22 | { 23 | _pos = 0; 24 | err = _response->sendChunk(_buffer, _length); 25 | 26 | if (err != ESP_OK) 27 | return 0; 28 | } 29 | 30 | _buffer[_pos] = c; 31 | _pos++; 32 | return 1; 33 | } 34 | 35 | size_t ChunkPrinter::write(const uint8_t *buffer, size_t size) 36 | { 37 | size_t written = 0; 38 | 39 | while (written < size) 40 | { 41 | size_t space = _length - _pos; 42 | size_t blockSize = std::min(space, size - written); 43 | 44 | memcpy(_buffer + _pos, buffer + written, blockSize); 45 | _pos += blockSize; 46 | 47 | if (_pos == _length) 48 | { 49 | _pos = 0; 50 | 51 | if (_response->sendChunk(_buffer, _length) != ESP_OK) 52 | return written; 53 | } 54 | written += blockSize; //Update if sent correctly. 55 | } 56 | return written; 57 | } 58 | 59 | void ChunkPrinter::flush() 60 | { 61 | if (_pos) 62 | { 63 | _response->sendChunk(_buffer, _pos); 64 | _pos = 0; 65 | } 66 | } 67 | 68 | size_t ChunkPrinter::copyFrom(Stream &stream) 69 | { 70 | size_t count = 0; 71 | 72 | while (stream.available()){ 73 | 74 | if (_pos == _length) 75 | { 76 | _response->sendChunk(_buffer, _length); 77 | _pos = 0; 78 | } 79 | 80 | size_t readBytes = stream.readBytes(_buffer + _pos, _length - _pos); 81 | _pos += readBytes; 82 | count += readBytes; 83 | } 84 | return count; 85 | } -------------------------------------------------------------------------------- /src/ChunkPrinter.h: -------------------------------------------------------------------------------- 1 | #ifndef ChunkPrinter_h 2 | #define ChunkPrinter_h 3 | 4 | #include "PsychicResponse.h" 5 | #include 6 | 7 | class ChunkPrinter : public Print 8 | { 9 | private: 10 | PsychicResponse *_response; 11 | uint8_t *_buffer; 12 | size_t _length; 13 | size_t _pos; 14 | 15 | public: 16 | ChunkPrinter(PsychicResponse *response, uint8_t *buffer, size_t len); 17 | ~ChunkPrinter(); 18 | 19 | size_t write(uint8_t c) override; 20 | size_t write(const uint8_t *buffer, size_t size) override; 21 | 22 | size_t copyFrom(Stream &stream); 23 | 24 | void flush() override; 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /src/PsychicClient.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicClient.h" 2 | #include "PsychicHttpServer.h" 3 | #include 4 | 5 | PsychicClient::PsychicClient(httpd_handle_t server, int socket) : 6 | _server(server), 7 | _socket(socket), 8 | _friend(NULL), 9 | isNew(false) 10 | {} 11 | 12 | PsychicClient::~PsychicClient() { 13 | } 14 | 15 | httpd_handle_t PsychicClient::server() { 16 | return _server; 17 | } 18 | 19 | int PsychicClient::socket() { 20 | return _socket; 21 | } 22 | 23 | // I'm not sure this is entirely safe to call. I was having issues with race conditions when highly loaded using this. 24 | esp_err_t PsychicClient::close() 25 | { 26 | esp_err_t err = httpd_sess_trigger_close(_server, _socket); 27 | //PsychicHttpServer::closeCallback(_server, _socket); // call this immediately so the client is taken off the list. 28 | 29 | return err; 30 | } 31 | 32 | IPAddress PsychicClient::localIP() 33 | { 34 | IPAddress address(0,0,0,0); 35 | 36 | char ipstr[INET6_ADDRSTRLEN]; 37 | struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing 38 | socklen_t addr_size = sizeof(addr); 39 | 40 | if (getsockname(_socket, (struct sockaddr *)&addr, &addr_size) < 0) { 41 | ESP_LOGE(PH_TAG, "Error getting client IP"); 42 | return address; 43 | } 44 | 45 | // Convert to IPv4 string 46 | inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr)); 47 | //ESP_LOGD(PH_TAG, "Client Local IP => %s", ipstr); 48 | address.fromString(ipstr); 49 | 50 | return address; 51 | } 52 | 53 | IPAddress PsychicClient::remoteIP() 54 | { 55 | IPAddress address(0,0,0,0); 56 | 57 | char ipstr[INET6_ADDRSTRLEN]; 58 | struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing 59 | socklen_t addr_size = sizeof(addr); 60 | 61 | if (getpeername(_socket, (struct sockaddr *)&addr, &addr_size) < 0) { 62 | ESP_LOGE(PH_TAG, "Error getting client IP"); 63 | return address; 64 | } 65 | 66 | // Convert to IPv4 string 67 | inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr)); 68 | //ESP_LOGD(PH_TAG, "Client Remote IP => %s", ipstr); 69 | address.fromString(ipstr); 70 | 71 | return address; 72 | } -------------------------------------------------------------------------------- /src/PsychicClient.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicClient_h 2 | #define PsychicClient_h 3 | 4 | #include "PsychicCore.h" 5 | 6 | /* 7 | * PsychicClient :: Generic wrapper around the ESP-IDF socket 8 | */ 9 | 10 | class PsychicClient { 11 | protected: 12 | httpd_handle_t _server; 13 | int _socket; 14 | 15 | public: 16 | PsychicClient(httpd_handle_t server, int socket); 17 | ~PsychicClient(); 18 | 19 | //no idea if this is the right way to do it or not, but lets see. 20 | //pointer to our derived class (eg. PsychicWebSocketConnection) 21 | void *_friend; 22 | 23 | bool isNew = false; 24 | 25 | bool operator==(PsychicClient& rhs) const { return _socket == rhs.socket(); } 26 | 27 | httpd_handle_t server(); 28 | int socket(); 29 | esp_err_t close(); 30 | 31 | IPAddress localIP(); 32 | IPAddress remoteIP(); 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /src/PsychicCore.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicCore_h 2 | #define PsychicCore_h 3 | 4 | #define PH_TAG "psychic" 5 | 6 | //version numbers 7 | #define PSYCHIC_HTTP_VERSION_MAJOR 1 8 | #define PSYCHIC_HTTP_VERSION_MINOR 1 9 | #define PSYCHIC_HTTP_VERSION_PATCH 0 10 | 11 | #ifndef MAX_COOKIE_SIZE 12 | #define MAX_COOKIE_SIZE 512 13 | #endif 14 | 15 | #ifndef FILE_CHUNK_SIZE 16 | #define FILE_CHUNK_SIZE 8*1024 17 | #endif 18 | 19 | #ifndef STREAM_CHUNK_SIZE 20 | #define STREAM_CHUNK_SIZE 1024 21 | #endif 22 | 23 | #ifndef MAX_UPLOAD_SIZE 24 | #define MAX_UPLOAD_SIZE (2048*1024) // 2MB 25 | #endif 26 | 27 | #ifndef MAX_REQUEST_BODY_SIZE 28 | #define MAX_REQUEST_BODY_SIZE (16*1024) //16K 29 | #endif 30 | 31 | #ifdef ARDUINO 32 | #include 33 | #endif 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "esp_random.h" 40 | #include "MD5Builder.h" 41 | #include 42 | #include "FS.h" 43 | #include 44 | 45 | enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH }; 46 | 47 | String urlDecode(const char* encoded); 48 | 49 | class PsychicHttpServer; 50 | class PsychicRequest; 51 | class PsychicWebSocketRequest; 52 | class PsychicClient; 53 | 54 | //filter function definition 55 | typedef std::function PsychicRequestFilterFunction; 56 | 57 | //client connect callback 58 | typedef std::function PsychicClientCallback; 59 | 60 | //callback definitions 61 | typedef std::function PsychicHttpRequestCallback; 62 | typedef std::function PsychicJsonRequestCallback; 63 | 64 | struct HTTPHeader { 65 | char * field; 66 | char * value; 67 | }; 68 | 69 | class DefaultHeaders { 70 | std::list _headers; 71 | 72 | public: 73 | DefaultHeaders() {} 74 | 75 | void addHeader(const String& field, const String& value) 76 | { 77 | addHeader(field.c_str(), value.c_str()); 78 | } 79 | 80 | void addHeader(const char * field, const char * value) 81 | { 82 | HTTPHeader header; 83 | 84 | //these are just going to stick around forever. 85 | header.field =(char *)malloc(strlen(field)+1); 86 | header.value = (char *)malloc(strlen(value)+1); 87 | 88 | strlcpy(header.field, field, strlen(field)+1); 89 | strlcpy(header.value, value, strlen(value)+1); 90 | 91 | _headers.push_back(header); 92 | } 93 | 94 | const std::list& getHeaders() { return _headers; } 95 | 96 | //delete the copy constructor, singleton class 97 | DefaultHeaders(DefaultHeaders const &) = delete; 98 | DefaultHeaders &operator=(DefaultHeaders const &) = delete; 99 | 100 | //single static class interface 101 | static DefaultHeaders &Instance() { 102 | static DefaultHeaders instance; 103 | return instance; 104 | } 105 | }; 106 | 107 | #endif //PsychicCore_h -------------------------------------------------------------------------------- /src/PsychicEndpoint.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicEndpoint.h" 2 | #include "PsychicHttpServer.h" 3 | 4 | PsychicEndpoint::PsychicEndpoint() : 5 | _server(NULL), 6 | _uri(""), 7 | _method(HTTP_GET), 8 | _handler(NULL) 9 | { 10 | } 11 | 12 | PsychicEndpoint::PsychicEndpoint(PsychicHttpServer *server, http_method method, const char * uri) : 13 | _server(server), 14 | _uri(uri), 15 | _method(method), 16 | _handler(NULL) 17 | { 18 | } 19 | 20 | PsychicEndpoint * PsychicEndpoint::setHandler(PsychicHandler *handler) 21 | { 22 | //clean up old / default handler 23 | if (_handler != NULL) 24 | delete _handler; 25 | 26 | //get our new pointer 27 | _handler = handler; 28 | 29 | //keep a pointer to the server 30 | _handler->_server = _server; 31 | 32 | return this; 33 | } 34 | 35 | PsychicHandler * PsychicEndpoint::handler() 36 | { 37 | return _handler; 38 | } 39 | 40 | String PsychicEndpoint::uri() { 41 | return _uri; 42 | } 43 | 44 | esp_err_t PsychicEndpoint::requestCallback(httpd_req_t *req) 45 | { 46 | #ifdef ENABLE_ASYNC 47 | if (is_on_async_worker_thread() == false) { 48 | if (submit_async_req(req, PsychicEndpoint::requestCallback) == ESP_OK) { 49 | return ESP_OK; 50 | } else { 51 | httpd_resp_set_status(req, "503 Busy"); 52 | httpd_resp_sendstr(req, "No workers available. Server busy."); 53 | return ESP_OK; 54 | } 55 | } 56 | #endif 57 | 58 | PsychicEndpoint *self = (PsychicEndpoint *)req->user_ctx; 59 | PsychicHandler *handler = self->handler(); 60 | PsychicRequest request(self->_server, req); 61 | 62 | //make sure we have a handler 63 | if (handler != NULL) 64 | { 65 | if (handler->filter(&request) && handler->canHandle(&request)) 66 | { 67 | //check our credentials 68 | if (handler->needsAuthentication(&request)) 69 | return handler->authenticate(&request); 70 | 71 | //pass it to our handler 72 | return handler->handleRequest(&request); 73 | } 74 | //pass it to our generic handlers 75 | else 76 | return PsychicHttpServer::notFoundHandler(req, HTTPD_500_INTERNAL_SERVER_ERROR); 77 | } 78 | else 79 | return request.reply(500, "text/html", "No handler registered."); 80 | } 81 | 82 | PsychicEndpoint* PsychicEndpoint::setFilter(PsychicRequestFilterFunction fn) { 83 | _handler->setFilter(fn); 84 | return this; 85 | } 86 | 87 | PsychicEndpoint* PsychicEndpoint::setAuthentication(const char *username, const char *password, HTTPAuthMethod method, const char *realm, const char *authFailMsg) { 88 | _handler->setAuthentication(username, password, method, realm, authFailMsg); 89 | return this; 90 | }; -------------------------------------------------------------------------------- /src/PsychicEndpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicEndpoint_h 2 | #define PsychicEndpoint_h 3 | 4 | #include "PsychicCore.h" 5 | 6 | class PsychicHandler; 7 | 8 | #ifdef ENABLE_ASYNC 9 | #include "async_worker.h" 10 | #endif 11 | 12 | class PsychicEndpoint 13 | { 14 | friend PsychicHttpServer; 15 | 16 | private: 17 | PsychicHttpServer *_server; 18 | String _uri; 19 | http_method _method; 20 | PsychicHandler *_handler; 21 | 22 | public: 23 | PsychicEndpoint(); 24 | PsychicEndpoint(PsychicHttpServer *server, http_method method, const char * uri); 25 | 26 | PsychicEndpoint *setHandler(PsychicHandler *handler); 27 | PsychicHandler *handler(); 28 | 29 | PsychicEndpoint* setFilter(PsychicRequestFilterFunction fn); 30 | PsychicEndpoint* setAuthentication(const char *username, const char *password, HTTPAuthMethod method = BASIC_AUTH, const char *realm = "", const char *authFailMsg = ""); 31 | 32 | String uri(); 33 | 34 | static esp_err_t requestCallback(httpd_req_t *req); 35 | }; 36 | 37 | #endif // PsychicEndpoint_h -------------------------------------------------------------------------------- /src/PsychicEventSource.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 PsychicEventSource_H_ 21 | #define PsychicEventSource_H_ 22 | 23 | #include "PsychicCore.h" 24 | #include "PsychicHandler.h" 25 | #include "PsychicClient.h" 26 | #include "PsychicResponse.h" 27 | 28 | class PsychicEventSource; 29 | class PsychicEventSourceResponse; 30 | class PsychicEventSourceClient; 31 | class PsychicResponse; 32 | 33 | typedef std::function PsychicEventSourceClientCallback; 34 | 35 | class PsychicEventSourceClient : public PsychicClient { 36 | friend PsychicEventSource; 37 | 38 | protected: 39 | uint32_t _lastId; 40 | 41 | public: 42 | PsychicEventSourceClient(PsychicClient *client); 43 | ~PsychicEventSourceClient(); 44 | 45 | uint32_t lastId() const { return _lastId; } 46 | void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); 47 | void sendEvent(const char *event); 48 | }; 49 | 50 | class PsychicEventSource : public PsychicHandler { 51 | private: 52 | PsychicEventSourceClientCallback _onOpen; 53 | PsychicEventSourceClientCallback _onClose; 54 | 55 | public: 56 | PsychicEventSource(); 57 | ~PsychicEventSource(); 58 | 59 | PsychicEventSourceClient * getClient(int socket) override; 60 | PsychicEventSourceClient * getClient(PsychicClient *client) override; 61 | void addClient(PsychicClient *client) override; 62 | void removeClient(PsychicClient *client) override; 63 | void openCallback(PsychicClient *client) override; 64 | void closeCallback(PsychicClient *client) override; 65 | 66 | PsychicEventSource *onOpen(PsychicEventSourceClientCallback fn); 67 | PsychicEventSource *onClose(PsychicEventSourceClientCallback fn); 68 | 69 | esp_err_t handleRequest(PsychicRequest *request) override final; 70 | 71 | void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); 72 | }; 73 | 74 | class PsychicEventSourceResponse: public PsychicResponse { 75 | public: 76 | PsychicEventSourceResponse(PsychicRequest *request); 77 | virtual esp_err_t send() override; 78 | }; 79 | 80 | String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect); 81 | 82 | #endif /* PsychicEventSource_H_ */ -------------------------------------------------------------------------------- /src/PsychicFileResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicFileResponse.h" 2 | #include "PsychicResponse.h" 3 | #include "PsychicRequest.h" 4 | 5 | 6 | PsychicFileResponse::PsychicFileResponse(PsychicRequest *request, FS &fs, const String& path, const String& contentType, bool download) 7 | : PsychicResponse(request) { 8 | //_code = 200; 9 | String _path(path); 10 | 11 | if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){ 12 | _path = _path+".gz"; 13 | addHeader("Content-Encoding", "gzip"); 14 | } 15 | 16 | _content = fs.open(_path, "r"); 17 | _contentLength = _content.size(); 18 | 19 | if(contentType == "") 20 | _setContentType(path); 21 | else 22 | setContentType(contentType.c_str()); 23 | 24 | int filenameStart = path.lastIndexOf('/') + 1; 25 | char buf[26+path.length()-filenameStart]; 26 | char* filename = (char*)path.c_str() + filenameStart; 27 | 28 | if(download) { 29 | // set filename and force download 30 | snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename); 31 | } else { 32 | // set filename and force rendering 33 | snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename); 34 | } 35 | addHeader("Content-Disposition", buf); 36 | } 37 | 38 | PsychicFileResponse::PsychicFileResponse(PsychicRequest *request, File content, const String& path, const String& contentType, bool download) 39 | : PsychicResponse(request) { 40 | String _path(path); 41 | 42 | if(!download && String(content.name()).endsWith(".gz") && !path.endsWith(".gz")){ 43 | addHeader("Content-Encoding", "gzip"); 44 | } 45 | 46 | _content = content; 47 | _contentLength = _content.size(); 48 | 49 | if(contentType == "") 50 | _setContentType(path); 51 | else 52 | setContentType(contentType.c_str()); 53 | 54 | int filenameStart = path.lastIndexOf('/') + 1; 55 | char buf[26+path.length()-filenameStart]; 56 | char* filename = (char*)path.c_str() + filenameStart; 57 | 58 | if(download) { 59 | snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename); 60 | } else { 61 | snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename); 62 | } 63 | addHeader("Content-Disposition", buf); 64 | } 65 | 66 | PsychicFileResponse::~PsychicFileResponse() 67 | { 68 | if(_content) 69 | _content.close(); 70 | } 71 | 72 | void PsychicFileResponse::_setContentType(const String& path){ 73 | const char *_contentType; 74 | 75 | if (path.endsWith(".html")) _contentType = "text/html"; 76 | else if (path.endsWith(".htm")) _contentType = "text/html"; 77 | else if (path.endsWith(".css")) _contentType = "text/css"; 78 | else if (path.endsWith(".json")) _contentType = "application/json"; 79 | else if (path.endsWith(".js")) _contentType = "application/javascript"; 80 | else if (path.endsWith(".png")) _contentType = "image/png"; 81 | else if (path.endsWith(".gif")) _contentType = "image/gif"; 82 | else if (path.endsWith(".jpg")) _contentType = "image/jpeg"; 83 | else if (path.endsWith(".ico")) _contentType = "image/x-icon"; 84 | else if (path.endsWith(".svg")) _contentType = "image/svg+xml"; 85 | else if (path.endsWith(".eot")) _contentType = "font/eot"; 86 | else if (path.endsWith(".woff")) _contentType = "font/woff"; 87 | else if (path.endsWith(".woff2")) _contentType = "font/woff2"; 88 | else if (path.endsWith(".ttf")) _contentType = "font/ttf"; 89 | else if (path.endsWith(".xml")) _contentType = "text/xml"; 90 | else if (path.endsWith(".pdf")) _contentType = "application/pdf"; 91 | else if (path.endsWith(".zip")) _contentType = "application/zip"; 92 | else if(path.endsWith(".gz")) _contentType = "application/x-gzip"; 93 | else _contentType = "text/plain"; 94 | 95 | setContentType(_contentType); 96 | } 97 | 98 | esp_err_t PsychicFileResponse::send() 99 | { 100 | esp_err_t err = ESP_OK; 101 | 102 | //just send small files directly 103 | size_t size = getContentLength(); 104 | if (size < FILE_CHUNK_SIZE) 105 | { 106 | uint8_t *buffer = (uint8_t *)malloc(size); 107 | if (buffer == NULL) 108 | { 109 | /* Respond with 500 Internal Server Error */ 110 | httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory."); 111 | return ESP_FAIL; 112 | } 113 | 114 | size_t readSize = _content.readBytes((char *)buffer, size); 115 | 116 | this->setContent(buffer, readSize); 117 | err = PsychicResponse::send(); 118 | 119 | free(buffer); 120 | } 121 | else 122 | { 123 | /* Retrieve the pointer to scratch buffer for temporary storage */ 124 | char *chunk = (char *)malloc(FILE_CHUNK_SIZE); 125 | if (chunk == NULL) 126 | { 127 | /* Respond with 500 Internal Server Error */ 128 | httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory."); 129 | return ESP_FAIL; 130 | } 131 | 132 | this->sendHeaders(); 133 | 134 | size_t chunksize; 135 | do { 136 | /* Read file in chunks into the scratch buffer */ 137 | chunksize = _content.readBytes(chunk, FILE_CHUNK_SIZE); 138 | if (chunksize > 0) 139 | { 140 | err = this->sendChunk((uint8_t *)chunk, chunksize); 141 | if (err != ESP_OK) 142 | break; 143 | } 144 | 145 | /* Keep looping till the whole file is sent */ 146 | } while (chunksize != 0); 147 | 148 | //keep track of our memory 149 | free(chunk); 150 | 151 | if (err == ESP_OK) 152 | { 153 | ESP_LOGD(PH_TAG, "File sending complete"); 154 | this->finishChunking(); 155 | } 156 | } 157 | 158 | return err; 159 | } 160 | -------------------------------------------------------------------------------- /src/PsychicFileResponse.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicFileResponse_h 2 | #define PsychicFileResponse_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicResponse.h" 6 | 7 | class PsychicRequest; 8 | 9 | class PsychicFileResponse: public PsychicResponse 10 | { 11 | using File = fs::File; 12 | using FS = fs::FS; 13 | private: 14 | File _content; 15 | void _setContentType(const String& path); 16 | public: 17 | PsychicFileResponse(PsychicRequest *request, FS &fs, const String& path, const String& contentType=String(), bool download=false); 18 | PsychicFileResponse(PsychicRequest *request, File content, const String& path, const String& contentType=String(), bool download=false); 19 | ~PsychicFileResponse(); 20 | esp_err_t send(); 21 | }; 22 | 23 | #endif // PsychicFileResponse_h -------------------------------------------------------------------------------- /src/PsychicHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicHandler.h" 2 | 3 | PsychicHandler::PsychicHandler() : 4 | _filter(NULL), 5 | _server(NULL), 6 | _username(""), 7 | _password(""), 8 | _method(DIGEST_AUTH), 9 | _realm(""), 10 | _authFailMsg(""), 11 | _subprotocol("") 12 | {} 13 | 14 | PsychicHandler::~PsychicHandler() { 15 | // actual PsychicClient deletion handled by PsychicServer 16 | // for (PsychicClient *client : _clients) 17 | // delete(client); 18 | _clients.clear(); 19 | } 20 | 21 | PsychicHandler* PsychicHandler::setFilter(PsychicRequestFilterFunction fn) { 22 | _filter = fn; 23 | return this; 24 | } 25 | 26 | bool PsychicHandler::filter(PsychicRequest *request){ 27 | return _filter == NULL || _filter(request); 28 | } 29 | 30 | void PsychicHandler::setSubprotocol(const String& subprotocol) { 31 | this->_subprotocol = subprotocol; 32 | } 33 | const char* PsychicHandler::getSubprotocol() const { 34 | return _subprotocol.c_str(); 35 | } 36 | 37 | PsychicHandler* PsychicHandler::setAuthentication(const char *username, const char *password, HTTPAuthMethod method, const char *realm, const char *authFailMsg) { 38 | _username = String(username); 39 | _password = String(password); 40 | _method = method; 41 | _realm = String(realm); 42 | _authFailMsg = String(authFailMsg); 43 | return this; 44 | }; 45 | 46 | bool PsychicHandler::needsAuthentication(PsychicRequest *request) { 47 | return (_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()); 48 | } 49 | 50 | esp_err_t PsychicHandler::authenticate(PsychicRequest *request) { 51 | return request->requestAuthentication(_method, _realm.c_str(), _authFailMsg.c_str()); 52 | } 53 | 54 | PsychicClient * PsychicHandler::checkForNewClient(PsychicClient *client) 55 | { 56 | PsychicClient *c = PsychicHandler::getClient(client); 57 | if (c == NULL) 58 | { 59 | c = client; 60 | addClient(c); 61 | c->isNew = true; 62 | } 63 | else 64 | c->isNew = false; 65 | 66 | return c; 67 | } 68 | 69 | void PsychicHandler::checkForClosedClient(PsychicClient *client) 70 | { 71 | if (hasClient(client)) 72 | { 73 | closeCallback(client); 74 | removeClient(client); 75 | } 76 | } 77 | 78 | void PsychicHandler::addClient(PsychicClient *client) { 79 | _clients.push_back(client); 80 | } 81 | 82 | void PsychicHandler::removeClient(PsychicClient *client) { 83 | _clients.remove(client); 84 | } 85 | 86 | PsychicClient * PsychicHandler::getClient(int socket) 87 | { 88 | //make sure the server has it too. 89 | if (!_server->hasClient(socket)) 90 | return NULL; 91 | 92 | //what about us? 93 | for (PsychicClient *client : _clients) 94 | if (client->socket() == socket) 95 | return client; 96 | 97 | //nothing found. 98 | return NULL; 99 | } 100 | 101 | PsychicClient * PsychicHandler::getClient(PsychicClient *client) { 102 | return PsychicHandler::getClient(client->socket()); 103 | } 104 | 105 | bool PsychicHandler::hasClient(PsychicClient *socket) { 106 | return PsychicHandler::getClient(socket) != NULL; 107 | } 108 | 109 | const std::list& PsychicHandler::getClientList() { 110 | return _clients; 111 | } -------------------------------------------------------------------------------- /src/PsychicHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicHandler_h 2 | #define PsychicHandler_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicRequest.h" 6 | 7 | class PsychicEndpoint; 8 | class PsychicHttpServer; 9 | 10 | /* 11 | * HANDLER :: Can be attached to any endpoint or as a generic request handler. 12 | */ 13 | 14 | class PsychicHandler { 15 | friend PsychicEndpoint; 16 | 17 | protected: 18 | PsychicRequestFilterFunction _filter; 19 | PsychicHttpServer *_server; 20 | 21 | String _username; 22 | String _password; 23 | HTTPAuthMethod _method; 24 | String _realm; 25 | String _authFailMsg; 26 | 27 | String _subprotocol; 28 | 29 | std::list _clients; 30 | 31 | public: 32 | PsychicHandler(); 33 | virtual ~PsychicHandler(); 34 | 35 | PsychicHandler* setFilter(PsychicRequestFilterFunction fn); 36 | bool filter(PsychicRequest *request); 37 | 38 | PsychicHandler* setAuthentication(const char *username, const char *password, HTTPAuthMethod method = BASIC_AUTH, const char *realm = "", const char *authFailMsg = ""); 39 | bool needsAuthentication(PsychicRequest *request); 40 | esp_err_t authenticate(PsychicRequest *request); 41 | 42 | virtual bool isWebSocket() { return false; }; 43 | 44 | void setSubprotocol(const String& subprotocol); 45 | const char* getSubprotocol() const; 46 | 47 | PsychicClient * checkForNewClient(PsychicClient *client); 48 | void checkForClosedClient(PsychicClient *client); 49 | 50 | virtual void addClient(PsychicClient *client); 51 | virtual void removeClient(PsychicClient *client); 52 | virtual PsychicClient * getClient(int socket); 53 | virtual PsychicClient * getClient(PsychicClient *client); 54 | virtual void openCallback(PsychicClient *client) {}; 55 | virtual void closeCallback(PsychicClient *client) {}; 56 | 57 | bool hasClient(PsychicClient *client); 58 | int count() { return _clients.size(); }; 59 | const std::list& getClientList(); 60 | 61 | //derived classes must implement these functions 62 | virtual bool canHandle(PsychicRequest *request) { return true; }; 63 | virtual esp_err_t handleRequest(PsychicRequest *request) = 0; 64 | }; 65 | 66 | #endif -------------------------------------------------------------------------------- /src/PsychicHttp.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicHttp_h 2 | #define PsychicHttp_h 3 | 4 | //#define ENABLE_ASYNC // This is something added in ESP-IDF 5.1.x where each request can be handled in its own thread 5 | 6 | #include 7 | #include "PsychicHttpServer.h" 8 | #include "PsychicRequest.h" 9 | #include "PsychicResponse.h" 10 | #include "PsychicEndpoint.h" 11 | #include "PsychicHandler.h" 12 | #include "PsychicStaticFileHandler.h" 13 | #include "PsychicFileResponse.h" 14 | #include "PsychicStreamResponse.h" 15 | #include "PsychicUploadHandler.h" 16 | #include "PsychicWebSocket.h" 17 | #include "PsychicEventSource.h" 18 | #include "PsychicJson.h" 19 | 20 | #ifdef ENABLE_ASYNC 21 | #include "async_worker.h" 22 | #endif 23 | 24 | #endif /* PsychicHttp_h */ -------------------------------------------------------------------------------- /src/PsychicHttpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicHttpServer_h 2 | #define PsychicHttpServer_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicClient.h" 6 | #include "PsychicHandler.h" 7 | 8 | class PsychicEndpoint; 9 | class PsychicHandler; 10 | class PsychicStaticFileHandler; 11 | 12 | class PsychicHttpServer 13 | { 14 | protected: 15 | bool _use_ssl = false; 16 | std::list _endpoints; 17 | std::list _handlers; 18 | std::list _clients; 19 | 20 | PsychicClientCallback _onOpen; 21 | PsychicClientCallback _onClose; 22 | 23 | esp_err_t _start(); 24 | virtual esp_err_t _startServer(); 25 | 26 | public: 27 | PsychicHttpServer(); 28 | virtual ~PsychicHttpServer(); 29 | 30 | //esp-idf specific stuff 31 | httpd_handle_t server; 32 | httpd_config_t config; 33 | 34 | //some limits on what we will accept 35 | unsigned long maxUploadSize; 36 | unsigned long maxRequestBodySize; 37 | 38 | PsychicEndpoint *defaultEndpoint; 39 | 40 | static void destroy(void *ctx); 41 | 42 | esp_err_t listen(uint16_t port); 43 | 44 | virtual void stop(); 45 | 46 | PsychicHandler& addHandler(PsychicHandler* handler); 47 | void removeHandler(PsychicHandler* handler); 48 | 49 | void addClient(PsychicClient *client); 50 | void removeClient(PsychicClient *client); 51 | PsychicClient* getClient(int socket); 52 | PsychicClient* getClient(httpd_req_t *req); 53 | bool hasClient(int socket); 54 | int count() { return _clients.size(); }; 55 | const std::list& getClientList(); 56 | 57 | PsychicEndpoint* on(const char* uri); 58 | PsychicEndpoint* on(const char* uri, http_method method); 59 | PsychicEndpoint* on(const char* uri, PsychicHandler *handler); 60 | PsychicEndpoint* on(const char* uri, http_method method, PsychicHandler *handler); 61 | PsychicEndpoint* on(const char* uri, PsychicHttpRequestCallback onRequest); 62 | PsychicEndpoint* on(const char* uri, http_method method, PsychicHttpRequestCallback onRequest); 63 | PsychicEndpoint* on(const char* uri, PsychicJsonRequestCallback onRequest); 64 | PsychicEndpoint* on(const char* uri, http_method method, PsychicJsonRequestCallback onRequest); 65 | 66 | static esp_err_t notFoundHandler(httpd_req_t *req, httpd_err_code_t err); 67 | static esp_err_t defaultNotFoundHandler(PsychicRequest *request); 68 | void onNotFound(PsychicHttpRequestCallback fn); 69 | 70 | void onOpen(PsychicClientCallback handler); 71 | void onClose(PsychicClientCallback handler); 72 | static esp_err_t openCallback(httpd_handle_t hd, int sockfd); 73 | static void closeCallback(httpd_handle_t hd, int sockfd); 74 | 75 | PsychicStaticFileHandler* serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL); 76 | }; 77 | 78 | bool ON_STA_FILTER(PsychicRequest *request); 79 | bool ON_AP_FILTER(PsychicRequest *request); 80 | 81 | #endif // PsychicHttpServer_h -------------------------------------------------------------------------------- /src/PsychicHttpsServer.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicHttpsServer.h" 2 | 3 | #ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE 4 | 5 | PsychicHttpsServer::PsychicHttpsServer() : PsychicHttpServer() 6 | { 7 | //for a SSL server 8 | ssl_config = HTTPD_SSL_CONFIG_DEFAULT(); 9 | ssl_config.httpd.open_fn = PsychicHttpServer::openCallback; 10 | ssl_config.httpd.close_fn = PsychicHttpServer::closeCallback; 11 | ssl_config.httpd.uri_match_fn = httpd_uri_match_wildcard; 12 | ssl_config.httpd.global_user_ctx = this; 13 | ssl_config.httpd.global_user_ctx_free_fn = destroy; 14 | ssl_config.httpd.max_uri_handlers = 20; 15 | 16 | // each SSL connection takes about 45kb of heap 17 | // a barebones sketch with PsychicHttp has ~150kb of heap available 18 | // if we set it higher than 2 and use all the connections, we get lots of memory errors. 19 | // not to mention there is no heap left over for the program itself. 20 | ssl_config.httpd.max_open_sockets = 2; 21 | } 22 | 23 | PsychicHttpsServer::~PsychicHttpsServer() {} 24 | 25 | esp_err_t PsychicHttpsServer::listen(uint16_t port, const char *cert, const char *private_key) 26 | { 27 | this->_use_ssl = true; 28 | 29 | this->ssl_config.port_secure = port; 30 | 31 | #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 2) 32 | this->ssl_config.servercert = (uint8_t *)cert; 33 | this->ssl_config.servercert_len = strlen(cert)+1; 34 | #else 35 | this->ssl_config.cacert_pem = (uint8_t *)cert; 36 | this->ssl_config.cacert_len = strlen(cert)+1; 37 | #endif 38 | 39 | this->ssl_config.prvtkey_pem = (uint8_t *)private_key; 40 | this->ssl_config.prvtkey_len = strlen(private_key)+1; 41 | 42 | return this->_start(); 43 | } 44 | 45 | esp_err_t PsychicHttpsServer::_startServer() 46 | { 47 | if (this->_use_ssl) 48 | return httpd_ssl_start(&this->server, &this->ssl_config); 49 | else 50 | return httpd_start(&this->server, &this->config); 51 | } 52 | 53 | void PsychicHttpsServer::stop() 54 | { 55 | if (this->_use_ssl) 56 | httpd_ssl_stop(this->server); 57 | else 58 | httpd_stop(this->server); 59 | } 60 | 61 | #endif // CONFIG_ESP_HTTPS_SERVER_ENABLE -------------------------------------------------------------------------------- /src/PsychicHttpsServer.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicHttpsServer_h 2 | #define PsychicHttpsServer_h 3 | 4 | #include 5 | 6 | #ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE 7 | 8 | #include "PsychicCore.h" 9 | #include "PsychicHttpServer.h" 10 | #include 11 | #if !CONFIG_HTTPD_WS_SUPPORT 12 | #error PsychicHttpsServer cannot be used unless HTTPD_WS_SUPPORT is enabled in esp-http-server component configuration 13 | #endif 14 | 15 | #define PSY_ENABLE_SSL //you can use this define in your code to enable/disable these features 16 | 17 | class PsychicHttpsServer : public PsychicHttpServer 18 | { 19 | protected: 20 | bool _use_ssl = false; 21 | 22 | public: 23 | PsychicHttpsServer(); 24 | ~PsychicHttpsServer(); 25 | 26 | httpd_ssl_config_t ssl_config; 27 | 28 | using PsychicHttpServer::listen; //keep the regular version 29 | esp_err_t listen(uint16_t port, const char *cert, const char *private_key); 30 | 31 | virtual esp_err_t _startServer() override final; 32 | virtual void stop() override final; 33 | }; 34 | 35 | #else 36 | #warning ESP-IDF https server support not enabled. 37 | #endif // CONFIG_ESP_HTTPS_SERVER_ENABLE 38 | 39 | #endif // PsychicHttpsServer_h 40 | -------------------------------------------------------------------------------- /src/PsychicJson.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicJson.h" 2 | 3 | #ifdef ARDUINOJSON_6_COMPATIBILITY 4 | PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray, size_t maxJsonBufferSize) : 5 | PsychicResponse(request), 6 | _jsonBuffer(maxJsonBufferSize) 7 | { 8 | setContentType(JSON_MIMETYPE); 9 | if (isArray) 10 | _root = _jsonBuffer.createNestedArray(); 11 | else 12 | _root = _jsonBuffer.createNestedObject(); 13 | } 14 | #else 15 | PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray) : PsychicResponse(request) 16 | { 17 | setContentType(JSON_MIMETYPE); 18 | if (isArray) 19 | _root = _jsonBuffer.add(); 20 | else 21 | _root = _jsonBuffer.add(); 22 | } 23 | #endif 24 | 25 | JsonVariant &PsychicJsonResponse::getRoot() { return _root; } 26 | 27 | size_t PsychicJsonResponse::getLength() 28 | { 29 | return measureJson(_root); 30 | } 31 | 32 | esp_err_t PsychicJsonResponse::send() 33 | { 34 | esp_err_t err = ESP_OK; 35 | size_t length = getLength(); 36 | size_t buffer_size; 37 | char *buffer; 38 | 39 | //how big of a buffer do we want? 40 | if (length < JSON_BUFFER_SIZE) 41 | buffer_size = length+1; 42 | else 43 | buffer_size = JSON_BUFFER_SIZE; 44 | 45 | buffer = (char *)malloc(buffer_size); 46 | if (buffer == NULL) { 47 | httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory."); 48 | return ESP_FAIL; 49 | } 50 | 51 | //send it in one shot or no? 52 | if (length < JSON_BUFFER_SIZE) 53 | { 54 | serializeJson(_root, buffer, buffer_size); 55 | 56 | this->setContent((uint8_t *)buffer, length); 57 | this->setContentType(JSON_MIMETYPE); 58 | 59 | err = PsychicResponse::send(); 60 | } 61 | else 62 | { 63 | //helper class that acts as a stream to print chunked responses 64 | ChunkPrinter dest(this, (uint8_t *)buffer, buffer_size); 65 | 66 | //keep our headers 67 | this->sendHeaders(); 68 | 69 | serializeJson(_root, dest); 70 | 71 | //send the last bits 72 | dest.flush(); 73 | 74 | //done with our chunked response too 75 | err = this->finishChunking(); 76 | } 77 | 78 | //let the buffer go 79 | free(buffer); 80 | 81 | return err; 82 | } 83 | 84 | #ifdef ARDUINOJSON_6_COMPATIBILITY 85 | PsychicJsonHandler::PsychicJsonHandler(size_t maxJsonBufferSize) : 86 | _onRequest(NULL), 87 | _maxJsonBufferSize(maxJsonBufferSize) 88 | {}; 89 | 90 | PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest, size_t maxJsonBufferSize) : 91 | _onRequest(onRequest), 92 | _maxJsonBufferSize(maxJsonBufferSize) 93 | {} 94 | #else 95 | PsychicJsonHandler::PsychicJsonHandler() : 96 | _onRequest(NULL) 97 | {}; 98 | 99 | PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest) : 100 | _onRequest(onRequest) 101 | {} 102 | #endif 103 | 104 | void PsychicJsonHandler::onRequest(PsychicJsonRequestCallback fn) { _onRequest = fn; } 105 | 106 | esp_err_t PsychicJsonHandler::handleRequest(PsychicRequest *request) 107 | { 108 | //process basic stuff 109 | PsychicWebHandler::handleRequest(request); 110 | 111 | if (_onRequest) 112 | { 113 | #ifdef ARDUINOJSON_6_COMPATIBILITY 114 | DynamicJsonDocument jsonBuffer(this->_maxJsonBufferSize); 115 | DeserializationError error = deserializeJson(jsonBuffer, request->body()); 116 | if (error) 117 | return request->reply(400); 118 | 119 | JsonVariant json = jsonBuffer.as(); 120 | #else 121 | JsonDocument jsonBuffer; 122 | DeserializationError error = deserializeJson(jsonBuffer, request->body()); 123 | if (error) 124 | return request->reply(400); 125 | 126 | JsonVariant json = jsonBuffer.as(); 127 | #endif 128 | 129 | return _onRequest(request, json); 130 | } 131 | else 132 | return request->reply(500); 133 | } -------------------------------------------------------------------------------- /src/PsychicJson.h: -------------------------------------------------------------------------------- 1 | // PsychicJson.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 | Ported to PsychicHttp by Zach Hoeken 6 | 7 | */ 8 | #ifndef PSYCHIC_JSON_H_ 9 | #define PSYCHIC_JSON_H_ 10 | 11 | #include "PsychicRequest.h" 12 | #include "PsychicWebHandler.h" 13 | #include "ChunkPrinter.h" 14 | #include 15 | 16 | #if ARDUINOJSON_VERSION_MAJOR == 6 17 | #define ARDUINOJSON_6_COMPATIBILITY 18 | #ifndef DYNAMIC_JSON_DOCUMENT_SIZE 19 | #define DYNAMIC_JSON_DOCUMENT_SIZE 4096 20 | #endif 21 | #endif 22 | 23 | 24 | #ifndef JSON_BUFFER_SIZE 25 | #define JSON_BUFFER_SIZE 4*1024 26 | #endif 27 | 28 | constexpr const char *JSON_MIMETYPE = "application/json"; 29 | 30 | /* 31 | * Json Response 32 | * */ 33 | 34 | class PsychicJsonResponse : public PsychicResponse 35 | { 36 | protected: 37 | #ifdef ARDUINOJSON_5_COMPATIBILITY 38 | DynamicJsonBuffer _jsonBuffer; 39 | #elif ARDUINOJSON_VERSION_MAJOR == 6 40 | DynamicJsonDocument _jsonBuffer; 41 | #else 42 | JsonDocument _jsonBuffer; 43 | #endif 44 | 45 | JsonVariant _root; 46 | size_t _contentLength; 47 | 48 | public: 49 | #ifdef ARDUINOJSON_5_COMPATIBILITY 50 | PsychicJsonResponse(PsychicRequest *request, bool isArray = false); 51 | #elif ARDUINOJSON_VERSION_MAJOR == 6 52 | PsychicJsonResponse(PsychicRequest *request, bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE); 53 | #else 54 | PsychicJsonResponse(PsychicRequest *request, bool isArray = false); 55 | #endif 56 | 57 | ~PsychicJsonResponse() {} 58 | 59 | JsonVariant &getRoot(); 60 | size_t getLength(); 61 | 62 | virtual esp_err_t send() override; 63 | }; 64 | 65 | class PsychicJsonHandler : public PsychicWebHandler 66 | { 67 | protected: 68 | PsychicJsonRequestCallback _onRequest; 69 | #if ARDUINOJSON_VERSION_MAJOR == 6 70 | const size_t _maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE; 71 | #endif 72 | 73 | public: 74 | #ifdef ARDUINOJSON_5_COMPATIBILITY 75 | PsychicJsonHandler(); 76 | PsychicJsonHandler(PsychicJsonRequestCallback onRequest); 77 | #elif ARDUINOJSON_VERSION_MAJOR == 6 78 | PsychicJsonHandler(size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE); 79 | PsychicJsonHandler(PsychicJsonRequestCallback onRequest, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE); 80 | #else 81 | PsychicJsonHandler(); 82 | PsychicJsonHandler(PsychicJsonRequestCallback onRequest); 83 | #endif 84 | 85 | void onRequest(PsychicJsonRequestCallback fn); 86 | virtual esp_err_t handleRequest(PsychicRequest *request) override; 87 | }; 88 | 89 | #endif -------------------------------------------------------------------------------- /src/PsychicRequest.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicRequest_h 2 | #define PsychicRequest_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicHttpServer.h" 6 | #include "PsychicClient.h" 7 | #include "PsychicWebParameter.h" 8 | #include "PsychicResponse.h" 9 | 10 | typedef std::map SessionData; 11 | 12 | enum Disposition { NONE, INLINE, ATTACHMENT, FORM_DATA}; 13 | 14 | struct ContentDisposition { 15 | Disposition disposition; 16 | String filename; 17 | String name; 18 | }; 19 | 20 | class PsychicRequest { 21 | friend PsychicHttpServer; 22 | 23 | protected: 24 | PsychicHttpServer *_server; 25 | httpd_req_t *_req; 26 | SessionData *_session; 27 | PsychicClient *_client; 28 | 29 | http_method _method; 30 | String _uri; 31 | String _query; 32 | String _body; 33 | 34 | std::list _params; 35 | 36 | void _addParams(const String& params, bool post); 37 | void _parseGETParams(); 38 | void _parsePOSTParams(); 39 | 40 | const String _extractParam(const String& authReq, const String& param, const char delimit); 41 | const String _getRandomHexString(); 42 | 43 | public: 44 | PsychicRequest(PsychicHttpServer *server, httpd_req_t *req); 45 | virtual ~PsychicRequest(); 46 | 47 | void *_tempObject; 48 | 49 | PsychicHttpServer * server(); 50 | httpd_req_t * request(); 51 | virtual PsychicClient * client(); 52 | 53 | bool isMultipart(); 54 | esp_err_t loadBody(); 55 | 56 | const String header(const char *name); 57 | bool hasHeader(const char *name); 58 | 59 | static void freeSession(void *ctx); 60 | bool hasSessionKey(const String& key); 61 | const String getSessionKey(const String& key); 62 | void setSessionKey(const String& key, const String& value); 63 | 64 | bool hasCookie(const char * key); 65 | const String getCookie(const char * key); 66 | 67 | http_method method(); // returns the HTTP method used as enum value (eg. HTTP_GET) 68 | const String methodStr(); // returns the HTTP method used as a string (eg. "GET") 69 | const String path(); // returns the request path (eg /page?foo=bar returns "/page") 70 | const String& uri(); // returns the full request uri (eg /page?foo=bar) 71 | const String& query(); // returns the request query data (eg /page?foo=bar returns "foo=bar") 72 | const String host(); // returns the requested host (request to http://psychic.local/foo will return "psychic.local") 73 | const String contentType(); // returns the Content-Type header value 74 | size_t contentLength(); // returns the Content-Length header value 75 | const String& body(); // returns the body of the request 76 | const ContentDisposition getContentDisposition(); 77 | 78 | const String& queryString() { return query(); } //compatability function. same as query() 79 | const String& url() { return uri(); } //compatability function. same as uri() 80 | 81 | void loadParams(); 82 | PsychicWebParameter * addParam(PsychicWebParameter *param); 83 | PsychicWebParameter * addParam(const String &name, const String &value, bool decode = true, bool post = false); 84 | bool hasParam(const char *key); 85 | PsychicWebParameter * getParam(const char *name); 86 | 87 | const String getFilename(); 88 | 89 | bool authenticate(const char * username, const char * password); 90 | esp_err_t requestAuthentication(HTTPAuthMethod mode, const char* realm, const char* authFailMsg); 91 | 92 | esp_err_t redirect(const char *url); 93 | esp_err_t reply(int code); 94 | esp_err_t reply(const char *content); 95 | esp_err_t reply(int code, const char *contentType, const char *content); 96 | }; 97 | 98 | #endif // PsychicRequest_h -------------------------------------------------------------------------------- /src/PsychicResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicResponse.h" 2 | #include "PsychicRequest.h" 3 | #include 4 | 5 | PsychicResponse::PsychicResponse(PsychicRequest *request) : 6 | _request(request), 7 | _code(200), 8 | _status(""), 9 | _contentLength(0), 10 | _body("") 11 | { 12 | } 13 | 14 | PsychicResponse::~PsychicResponse() 15 | { 16 | //clean up our header variables. we have to do this on desctruct since httpd_resp_send doesn't store copies 17 | for (HTTPHeader header : _headers) 18 | { 19 | free(header.field); 20 | free(header.value); 21 | } 22 | _headers.clear(); 23 | } 24 | 25 | void PsychicResponse::addHeader(const char *field, const char *value) 26 | { 27 | //these get freed after send by the destructor 28 | HTTPHeader header; 29 | header.field =(char *)malloc(strlen(field)+1); 30 | header.value = (char *)malloc(strlen(value)+1); 31 | 32 | strlcpy(header.field, field, strlen(field)+1); 33 | strlcpy(header.value, value, strlen(value)+1); 34 | 35 | _headers.push_back(header); 36 | } 37 | 38 | void PsychicResponse::setCookie(const char *name, const char *value, unsigned long secondsFromNow, const char *extras) 39 | { 40 | time_t now = time(nullptr); 41 | 42 | String output; 43 | output = urlEncode(name) + "=" + urlEncode(value); 44 | 45 | //if current time isn't modern, default to using max age 46 | if (now < 1700000000) 47 | output += "; Max-Age=" + String(secondsFromNow); 48 | //otherwise, set an expiration date 49 | else 50 | { 51 | time_t expirationTimestamp = now + secondsFromNow; 52 | 53 | // Convert the expiration timestamp to a formatted string for the "expires" attribute 54 | struct tm* tmInfo = gmtime(&expirationTimestamp); 55 | char expires[30]; 56 | strftime(expires, sizeof(expires), "%a, %d %b %Y %H:%M:%S GMT", tmInfo); 57 | output += "; Expires=" + String(expires); 58 | } 59 | 60 | //did we get any extras? 61 | if (strlen(extras)) 62 | output += "; " + String(extras); 63 | 64 | //okay, add it in. 65 | addHeader("Set-Cookie", output.c_str()); 66 | } 67 | 68 | void PsychicResponse::setCode(int code) 69 | { 70 | _code = code; 71 | } 72 | 73 | void PsychicResponse::setContentType(const char *contentType) 74 | { 75 | httpd_resp_set_type(_request->request(), contentType); 76 | } 77 | 78 | void PsychicResponse::setContent(const char *content) 79 | { 80 | _body = content; 81 | setContentLength(strlen(content)); 82 | } 83 | 84 | void PsychicResponse::setContent(const uint8_t *content, size_t len) 85 | { 86 | _body = (char *)content; 87 | setContentLength(len); 88 | } 89 | 90 | const char * PsychicResponse::getContent() 91 | { 92 | return _body; 93 | } 94 | 95 | size_t PsychicResponse::getContentLength() 96 | { 97 | return _contentLength; 98 | } 99 | 100 | esp_err_t PsychicResponse::send() 101 | { 102 | //esp-idf makes you set the whole status. 103 | sprintf(_status, "%u %s", _code, http_status_reason(_code)); 104 | httpd_resp_set_status(_request->request(), _status); 105 | 106 | //our headers too 107 | this->sendHeaders(); 108 | 109 | //now send it off 110 | esp_err_t err = httpd_resp_send(_request->request(), getContent(), getContentLength()); 111 | 112 | //did something happen? 113 | if (err != ESP_OK) 114 | ESP_LOGE(PH_TAG, "Send response failed (%s)", esp_err_to_name(err)); 115 | 116 | return err; 117 | } 118 | 119 | void PsychicResponse::sendHeaders() 120 | { 121 | //get our global headers out of the way first 122 | for (HTTPHeader header : DefaultHeaders::Instance().getHeaders()) 123 | httpd_resp_set_hdr(_request->request(), header.field, header.value); 124 | 125 | //now do our individual headers 126 | for (HTTPHeader header : _headers) 127 | httpd_resp_set_hdr(this->_request->request(), header.field, header.value); 128 | 129 | // DO NOT RELEASE HEADERS HERE... released in the PsychicResponse destructor after they have been sent. 130 | // httpd_resp_set_hdr just passes on the pointer, but its needed after this call. 131 | // clean up our header variables after send 132 | // for (HTTPHeader header : _headers) 133 | // { 134 | // free(header.field); 135 | // free(header.value); 136 | // } 137 | // _headers.clear(); 138 | } 139 | 140 | esp_err_t PsychicResponse::sendChunk(uint8_t *chunk, size_t chunksize) 141 | { 142 | /* Send the buffer contents as HTTP response chunk */ 143 | esp_err_t err = httpd_resp_send_chunk(this->_request->request(), (char *)chunk, chunksize); 144 | if (err != ESP_OK) 145 | { 146 | ESP_LOGE(PH_TAG, "File sending failed (%s)", esp_err_to_name(err)); 147 | 148 | /* Abort sending file */ 149 | httpd_resp_sendstr_chunk(this->_request->request(), NULL); 150 | 151 | /* Respond with 500 Internal Server Error */ 152 | httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file"); 153 | } 154 | 155 | return err; 156 | } 157 | 158 | esp_err_t PsychicResponse::finishChunking() 159 | { 160 | /* Respond with an empty chunk to signal HTTP response completion */ 161 | return httpd_resp_send_chunk(this->_request->request(), NULL, 0); 162 | } -------------------------------------------------------------------------------- /src/PsychicResponse.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicResponse_h 2 | #define PsychicResponse_h 3 | 4 | #include "PsychicCore.h" 5 | #include "time.h" 6 | 7 | class PsychicRequest; 8 | 9 | class PsychicResponse 10 | { 11 | protected: 12 | PsychicRequest *_request; 13 | 14 | int _code; 15 | char _status[60]; 16 | std::list _headers; 17 | int64_t _contentLength; 18 | const char * _body; 19 | 20 | public: 21 | PsychicResponse(PsychicRequest *request); 22 | virtual ~PsychicResponse(); 23 | 24 | void setCode(int code); 25 | 26 | void setContentType(const char *contentType); 27 | void setContentLength(int64_t contentLength) { _contentLength = contentLength; } 28 | int64_t getContentLength(int64_t contentLength) { return _contentLength; } 29 | 30 | void addHeader(const char *field, const char *value); 31 | 32 | void setCookie(const char *key, const char *value, unsigned long max_age = 60*60*24*30, const char *extras = ""); 33 | 34 | void setContent(const char *content); 35 | void setContent(const uint8_t *content, size_t len); 36 | 37 | const char * getContent(); 38 | size_t getContentLength(); 39 | 40 | virtual esp_err_t send(); 41 | void sendHeaders(); 42 | esp_err_t sendChunk(uint8_t *chunk, size_t chunksize); 43 | esp_err_t finishChunking(); 44 | }; 45 | 46 | #endif // PsychicResponse_h -------------------------------------------------------------------------------- /src/PsychicStaticFileHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicStaticFileHandler_h 2 | #define PsychicStaticFileHandler_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicWebHandler.h" 6 | #include "PsychicRequest.h" 7 | #include "PsychicResponse.h" 8 | #include "PsychicFileResponse.h" 9 | 10 | class PsychicStaticFileHandler : public PsychicWebHandler { 11 | using File = fs::File; 12 | using FS = fs::FS; 13 | private: 14 | bool _getFile(PsychicRequest *request); 15 | bool _fileExists(const String& path); 16 | uint8_t _countBits(const uint8_t value) const; 17 | protected: 18 | FS _fs; 19 | File _file; 20 | String _filename; 21 | String _uri; 22 | String _path; 23 | String _default_file; 24 | String _cache_control; 25 | String _last_modified; 26 | bool _isDir; 27 | bool _gzipFirst; 28 | uint8_t _gzipStats; 29 | public: 30 | PsychicStaticFileHandler(const char* uri, FS& fs, const char* path, const char* cache_control); 31 | bool canHandle(PsychicRequest *request) override; 32 | esp_err_t handleRequest(PsychicRequest *request) override; 33 | PsychicStaticFileHandler& setIsDir(bool isDir); 34 | PsychicStaticFileHandler& setDefaultFile(const char* filename); 35 | PsychicStaticFileHandler& setCacheControl(const char* cache_control); 36 | PsychicStaticFileHandler& setLastModified(const char* last_modified); 37 | PsychicStaticFileHandler& setLastModified(struct tm* last_modified); 38 | //PsychicStaticFileHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;} 39 | }; 40 | 41 | #endif /* PsychicHttp_h */ -------------------------------------------------------------------------------- /src/PsychicStreamResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicStreamResponse.h" 2 | #include "PsychicResponse.h" 3 | #include "PsychicRequest.h" 4 | 5 | PsychicStreamResponse::PsychicStreamResponse(PsychicRequest *request, const String& contentType) 6 | : PsychicResponse(request), _buffer(NULL) { 7 | 8 | setContentType(contentType.c_str()); 9 | addHeader("Content-Disposition", "inline"); 10 | } 11 | 12 | 13 | PsychicStreamResponse::PsychicStreamResponse(PsychicRequest *request, const String& contentType, const String& name) 14 | : PsychicResponse(request), _buffer(NULL) { 15 | 16 | setContentType(contentType.c_str()); 17 | 18 | char buf[26+name.length()]; 19 | snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", name.c_str()); 20 | addHeader("Content-Disposition", buf); 21 | } 22 | 23 | 24 | PsychicStreamResponse::~PsychicStreamResponse() 25 | { 26 | endSend(); 27 | } 28 | 29 | 30 | esp_err_t PsychicStreamResponse::beginSend() 31 | { 32 | if(_buffer) 33 | return ESP_OK; 34 | 35 | //Buffer to hold ChunkPrinter and stream buffer. Using placement new will keep us at a single allocation. 36 | _buffer = (uint8_t*)malloc(STREAM_CHUNK_SIZE + sizeof(ChunkPrinter)); 37 | 38 | if(!_buffer) 39 | { 40 | /* Respond with 500 Internal Server Error */ 41 | httpd_resp_send_err(_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory."); 42 | return ESP_FAIL; 43 | } 44 | 45 | _printer = new (_buffer) ChunkPrinter(this, _buffer + sizeof(ChunkPrinter), STREAM_CHUNK_SIZE); 46 | 47 | sendHeaders(); 48 | return ESP_OK; 49 | } 50 | 51 | 52 | esp_err_t PsychicStreamResponse::endSend() 53 | { 54 | esp_err_t err = ESP_OK; 55 | 56 | if(!_buffer) 57 | err = ESP_FAIL; 58 | else 59 | { 60 | _printer->~ChunkPrinter(); //flushed on destruct 61 | err = finishChunking(); 62 | free(_buffer); 63 | _buffer = NULL; 64 | } 65 | return err; 66 | } 67 | 68 | 69 | void PsychicStreamResponse::flush() 70 | { 71 | if(_buffer) 72 | _printer->flush(); 73 | } 74 | 75 | 76 | size_t PsychicStreamResponse::write(uint8_t data) 77 | { 78 | return _buffer ? _printer->write(data) : 0; 79 | } 80 | 81 | 82 | size_t PsychicStreamResponse::write(const uint8_t *buffer, size_t size) 83 | { 84 | return _buffer ? _printer->write(buffer, size) : 0; 85 | } 86 | 87 | 88 | size_t PsychicStreamResponse::copyFrom(Stream &stream) 89 | { 90 | if(_buffer) 91 | return _printer->copyFrom(stream); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /src/PsychicStreamResponse.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicStreamResponse_h 2 | #define PsychicStreamResponse_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicResponse.h" 6 | #include "ChunkPrinter.h" 7 | 8 | class PsychicRequest; 9 | 10 | class PsychicStreamResponse : public PsychicResponse, public Print 11 | { 12 | private: 13 | ChunkPrinter *_printer; 14 | uint8_t *_buffer; 15 | public: 16 | 17 | PsychicStreamResponse(PsychicRequest *request, const String& contentType); 18 | PsychicStreamResponse(PsychicRequest *request, const String& contentType, const String& name); //Download 19 | 20 | ~PsychicStreamResponse(); 21 | 22 | esp_err_t beginSend(); 23 | esp_err_t endSend(); 24 | 25 | void flush() override; 26 | 27 | size_t write(uint8_t data) override; 28 | size_t write(const uint8_t *buffer, size_t size) override; 29 | 30 | size_t copyFrom(Stream &stream); 31 | 32 | using Print::write; 33 | }; 34 | 35 | #endif // PsychicStreamResponse_h 36 | -------------------------------------------------------------------------------- /src/PsychicUploadHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicUploadHandler_h 2 | #define PsychicUploadHandler_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicHttpServer.h" 6 | #include "PsychicRequest.h" 7 | #include "PsychicWebHandler.h" 8 | #include "PsychicWebParameter.h" 9 | 10 | //callback definitions 11 | typedef std::function PsychicUploadCallback; 12 | 13 | /* 14 | * HANDLER :: Can be attached to any endpoint or as a generic request handler. 15 | */ 16 | 17 | class PsychicUploadHandler : public PsychicWebHandler { 18 | protected: 19 | PsychicUploadCallback _uploadCallback; 20 | 21 | PsychicRequest *_request; 22 | 23 | String _temp; 24 | size_t _parsedLength; 25 | uint8_t _multiParseState; 26 | String _boundary; 27 | uint8_t _boundaryPosition; 28 | size_t _itemStartIndex; 29 | size_t _itemSize; 30 | String _itemName; 31 | String _itemFilename; 32 | String _itemType; 33 | String _itemValue; 34 | uint8_t *_itemBuffer; 35 | size_t _itemBufferIndex; 36 | bool _itemIsFile; 37 | 38 | esp_err_t _basicUploadHandler(PsychicRequest *request); 39 | esp_err_t _multipartUploadHandler(PsychicRequest *request); 40 | 41 | void _handleUploadByte(uint8_t data, bool last); 42 | void _parseMultipartPostByte(uint8_t data, bool last); 43 | 44 | public: 45 | PsychicUploadHandler(); 46 | ~PsychicUploadHandler(); 47 | 48 | bool canHandle(PsychicRequest *request) override; 49 | esp_err_t handleRequest(PsychicRequest *request) override; 50 | 51 | PsychicUploadHandler * onUpload(PsychicUploadCallback fn); 52 | }; 53 | 54 | enum { 55 | EXPECT_BOUNDARY, 56 | PARSE_HEADERS, 57 | WAIT_FOR_RETURN1, 58 | EXPECT_FEED1, 59 | EXPECT_DASH1, 60 | EXPECT_DASH2, 61 | BOUNDARY_OR_DATA, 62 | DASH3_OR_RETURN2, 63 | EXPECT_FEED2, 64 | PARSING_FINISHED, 65 | PARSE_ERROR 66 | }; 67 | 68 | #endif // PsychicUploadHandler_h -------------------------------------------------------------------------------- /src/PsychicWebHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "PsychicWebHandler.h" 2 | 3 | PsychicWebHandler::PsychicWebHandler() : 4 | PsychicHandler(), 5 | _requestCallback(NULL), 6 | _onOpen(NULL), 7 | _onClose(NULL) 8 | {} 9 | PsychicWebHandler::~PsychicWebHandler() {} 10 | 11 | bool PsychicWebHandler::canHandle(PsychicRequest *request) { 12 | return true; 13 | } 14 | 15 | esp_err_t PsychicWebHandler::handleRequest(PsychicRequest *request) 16 | { 17 | //lookup our client 18 | PsychicClient *client = checkForNewClient(request->client()); 19 | if (client->isNew) 20 | openCallback(client); 21 | 22 | /* Request body cannot be larger than a limit */ 23 | if (request->contentLength() > request->server()->maxRequestBodySize) 24 | { 25 | ESP_LOGE(PH_TAG, "Request body too large : %d bytes", request->contentLength()); 26 | 27 | /* Respond with 400 Bad Request */ 28 | char error[60]; 29 | sprintf(error, "Request body must be less than %lu bytes!", request->server()->maxRequestBodySize); 30 | httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error); 31 | 32 | /* Return failure to close underlying connection else the incoming file content will keep the socket busy */ 33 | return ESP_FAIL; 34 | } 35 | 36 | //get our body loaded up. 37 | esp_err_t err = request->loadBody(); 38 | if (err != ESP_OK) 39 | return err; 40 | 41 | //load our params in. 42 | request->loadParams(); 43 | 44 | //okay, pass on to our callback. 45 | if (this->_requestCallback != NULL) 46 | err = this->_requestCallback(request); 47 | 48 | return err; 49 | } 50 | 51 | PsychicWebHandler * PsychicWebHandler::onRequest(PsychicHttpRequestCallback fn) { 52 | _requestCallback = fn; 53 | return this; 54 | } 55 | 56 | void PsychicWebHandler::openCallback(PsychicClient *client) { 57 | if (_onOpen != NULL) 58 | _onOpen(client); 59 | } 60 | 61 | void PsychicWebHandler::closeCallback(PsychicClient *client) { 62 | if (_onClose != NULL) 63 | _onClose(getClient(client)); 64 | } 65 | 66 | PsychicWebHandler * PsychicWebHandler::onOpen(PsychicClientCallback fn) { 67 | _onOpen = fn; 68 | return this; 69 | } 70 | 71 | PsychicWebHandler * PsychicWebHandler::onClose(PsychicClientCallback fn) { 72 | _onClose = fn; 73 | return this; 74 | } -------------------------------------------------------------------------------- /src/PsychicWebHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicWebHandler_h 2 | #define PsychicWebHandler_h 3 | 4 | // #include "PsychicCore.h" 5 | // #include "PsychicHttpServer.h" 6 | // #include "PsychicRequest.h" 7 | #include "PsychicHandler.h" 8 | 9 | /* 10 | * HANDLER :: Can be attached to any endpoint or as a generic request handler. 11 | */ 12 | 13 | class PsychicWebHandler : public PsychicHandler { 14 | protected: 15 | PsychicHttpRequestCallback _requestCallback; 16 | PsychicClientCallback _onOpen; 17 | PsychicClientCallback _onClose; 18 | 19 | public: 20 | PsychicWebHandler(); 21 | ~PsychicWebHandler(); 22 | 23 | virtual bool canHandle(PsychicRequest *request) override; 24 | virtual esp_err_t handleRequest(PsychicRequest *request) override; 25 | PsychicWebHandler * onRequest(PsychicHttpRequestCallback fn); 26 | 27 | virtual void openCallback(PsychicClient *client); 28 | virtual void closeCallback(PsychicClient *client); 29 | 30 | PsychicWebHandler *onOpen(PsychicClientCallback fn); 31 | PsychicWebHandler *onClose(PsychicClientCallback fn); 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /src/PsychicWebParameter.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicWebParameter_h 2 | #define PsychicWebParameter_h 3 | 4 | /* 5 | * PARAMETER :: Chainable object to hold GET/POST and FILE parameters 6 | * */ 7 | 8 | class PsychicWebParameter { 9 | private: 10 | String _name; 11 | String _value; 12 | size_t _size; 13 | bool _isForm; 14 | bool _isFile; 15 | 16 | public: 17 | PsychicWebParameter(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){} 18 | const String& name() const { return _name; } 19 | const String& value() const { return _value; } 20 | size_t size() const { return _size; } 21 | bool isPost() const { return _isForm; } 22 | bool isFile() const { return _isFile; } 23 | }; 24 | 25 | #endif //PsychicWebParameter_h -------------------------------------------------------------------------------- /src/PsychicWebSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef PsychicWebSocket_h 2 | #define PsychicWebSocket_h 3 | 4 | #include "PsychicCore.h" 5 | #include "PsychicRequest.h" 6 | 7 | class PsychicWebSocketRequest; 8 | class PsychicWebSocketClient; 9 | 10 | //callback function definitions 11 | typedef std::function PsychicWebSocketClientCallback; 12 | typedef std::function PsychicWebSocketFrameCallback; 13 | 14 | class PsychicWebSocketClient : public PsychicClient 15 | { 16 | public: 17 | PsychicWebSocketClient(PsychicClient *client); 18 | ~PsychicWebSocketClient(); 19 | 20 | esp_err_t sendMessage(httpd_ws_frame_t * ws_pkt); 21 | esp_err_t sendMessage(httpd_ws_type_t op, const void *data, size_t len); 22 | esp_err_t sendMessage(const char *buf); 23 | }; 24 | 25 | class PsychicWebSocketRequest : public PsychicRequest 26 | { 27 | private: 28 | PsychicWebSocketClient _client; 29 | 30 | public: 31 | PsychicWebSocketRequest(PsychicRequest *req); 32 | virtual ~PsychicWebSocketRequest(); 33 | 34 | PsychicWebSocketClient * client() override; 35 | 36 | esp_err_t reply(httpd_ws_frame_t * ws_pkt); 37 | esp_err_t reply(httpd_ws_type_t op, const void *data, size_t len); 38 | esp_err_t reply(const char *buf); 39 | }; 40 | 41 | class PsychicWebSocketHandler : public PsychicHandler { 42 | protected: 43 | PsychicWebSocketClientCallback _onOpen; 44 | PsychicWebSocketFrameCallback _onFrame; 45 | PsychicWebSocketClientCallback _onClose; 46 | 47 | public: 48 | PsychicWebSocketHandler(); 49 | ~PsychicWebSocketHandler(); 50 | 51 | PsychicWebSocketClient * getClient(int socket) override; 52 | PsychicWebSocketClient * getClient(PsychicClient *client) override; 53 | void addClient(PsychicClient *client) override; 54 | void removeClient(PsychicClient *client) override; 55 | void openCallback(PsychicClient *client) override; 56 | void closeCallback(PsychicClient *client) override; 57 | 58 | bool isWebSocket() override final; 59 | esp_err_t handleRequest(PsychicRequest *request) override; 60 | 61 | PsychicWebSocketHandler *onOpen(PsychicWebSocketClientCallback fn); 62 | PsychicWebSocketHandler *onFrame(PsychicWebSocketFrameCallback fn); 63 | PsychicWebSocketHandler *onClose(PsychicWebSocketClientCallback fn); 64 | 65 | void sendAll(httpd_ws_frame_t * ws_pkt); 66 | void sendAll(httpd_ws_type_t op, const void *data, size_t len); 67 | void sendAll(const char *buf); 68 | }; 69 | 70 | #endif // PsychicWebSocket_h -------------------------------------------------------------------------------- /src/TemplatePrinter.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************ 2 | 3 | TemplatePrinter Class 4 | 5 | A basic templating engine for a stream of text. 6 | This wraps the Arduino Print interface and writes to any 7 | Print interface. 8 | 9 | Written by Christopher Andrews (https://github.com/Chris--A) 10 | 11 | ************************************************************/ 12 | 13 | #include "TemplatePrinter.h" 14 | 15 | void TemplatePrinter::resetParam(bool flush){ 16 | if(flush && _inParam){ 17 | _stream.write(_delimiter); 18 | 19 | if(_paramPos) 20 | _stream.print(_paramBuffer); 21 | } 22 | 23 | memset(_paramBuffer, 0, sizeof(_paramBuffer)); 24 | _paramPos = 0; 25 | _inParam = false; 26 | } 27 | 28 | 29 | void TemplatePrinter::flush(){ 30 | resetParam(true); 31 | _stream.flush(); 32 | } 33 | 34 | size_t TemplatePrinter::write(uint8_t data){ 35 | 36 | if(data == _delimiter){ 37 | 38 | // End of parameter, send to callback 39 | if(_inParam){ 40 | 41 | // On false, return the parameter place holder as is: not a parameter 42 | // Bug fix: ignore parameters that are zero length. 43 | if(!_paramPos || !_cb(_stream, _paramBuffer)){ 44 | resetParam(true); 45 | _stream.write(data); 46 | }else{ 47 | resetParam(false); 48 | } 49 | 50 | // Start collecting parameter 51 | }else{ 52 | _inParam = true; 53 | } 54 | }else{ 55 | 56 | // Are we collecting 57 | if(_inParam){ 58 | 59 | // Is param still valid 60 | if(isalnum(data) || data == '_'){ 61 | 62 | // Total param len must be 63, 1 for null. 63 | if(_paramPos < sizeof(_paramBuffer) - 1){ 64 | _paramBuffer[_paramPos++] = data; 65 | 66 | // Not a valid param 67 | }else{ 68 | resetParam(true); 69 | } 70 | }else{ 71 | resetParam(true); 72 | _stream.write(data); 73 | } 74 | 75 | // Just output 76 | }else{ 77 | _stream.write(data); 78 | } 79 | } 80 | return 1; 81 | } 82 | 83 | size_t TemplatePrinter::copyFrom(Stream &stream){ 84 | size_t count = 0; 85 | 86 | while(stream.available()) 87 | count += this->write(stream.read()); 88 | 89 | return count; 90 | } 91 | -------------------------------------------------------------------------------- /src/TemplatePrinter.h: -------------------------------------------------------------------------------- 1 | #ifndef TemplatePrinter_h 2 | #define TemplatePrinter_h 3 | 4 | #include "PsychicCore.h" 5 | #include 6 | 7 | /************************************************************ 8 | 9 | TemplatePrinter Class 10 | 11 | A basic templating engine for a stream of text. 12 | This wraps the Arduino Print interface and writes to any 13 | Print interface. 14 | 15 | Written by Christopher Andrews (https://github.com/Chris--A) 16 | 17 | ************************************************************/ 18 | 19 | class TemplatePrinter; 20 | 21 | typedef std::function TemplateCallback; 22 | typedef std::function TemplateSourceCallback; 23 | 24 | class TemplatePrinter : public Print{ 25 | private: 26 | bool _inParam; 27 | char _paramBuffer[64]; 28 | uint8_t _paramPos; 29 | Print &_stream; 30 | TemplateCallback _cb; 31 | char _delimiter; 32 | 33 | void resetParam(bool flush); 34 | 35 | public: 36 | using Print::write; 37 | 38 | static void start(Print &stream, TemplateCallback cb, TemplateSourceCallback entry){ 39 | TemplatePrinter printer(stream, cb); 40 | entry(printer); 41 | } 42 | 43 | TemplatePrinter(Print &stream, TemplateCallback cb, const char delimeter = '%') : _stream(stream), _cb(cb), _delimiter(delimeter) { resetParam(false); } 44 | ~TemplatePrinter(){ flush(); } 45 | 46 | void flush() override; 47 | size_t write(uint8_t data) override; 48 | size_t copyFrom(Stream &stream); 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/async_worker.h: -------------------------------------------------------------------------------- 1 | #ifndef async_worker_h 2 | #define async_worker_h 3 | 4 | #include "PsychicCore.h" 5 | #include "freertos/FreeRTOS.h" 6 | #include "freertos/semphr.h" 7 | 8 | #define ASYNC_WORKER_TASK_PRIORITY 5 9 | #define ASYNC_WORKER_TASK_STACK_SIZE (4*1024) 10 | #define ASYNC_WORKER_COUNT 8 11 | 12 | // Async requests are queued here while they wait to be processed by the workers 13 | static QueueHandle_t async_req_queue; 14 | 15 | // Track the number of free workers at any given time 16 | static SemaphoreHandle_t worker_ready_count; 17 | 18 | // Each worker has its own thread 19 | static TaskHandle_t worker_handles[ASYNC_WORKER_COUNT]; 20 | 21 | typedef esp_err_t (*httpd_req_handler_t)(httpd_req_t *req); 22 | 23 | typedef struct { 24 | httpd_req_t* req; 25 | httpd_req_handler_t handler; 26 | } httpd_async_req_t; 27 | 28 | bool is_on_async_worker_thread(void); 29 | esp_err_t submit_async_req(httpd_req_t *req, httpd_req_handler_t handler); 30 | void async_req_worker_task(void *p); 31 | void start_async_req_workers(void); 32 | 33 | esp_err_t httpd_req_async_handler_begin(httpd_req_t *r, httpd_req_t **out); 34 | esp_err_t httpd_req_async_handler_complete(httpd_req_t *r); 35 | 36 | #endif //async_worker_h -------------------------------------------------------------------------------- /src/http_status.cpp: -------------------------------------------------------------------------------- 1 | #include "http_status.h" 2 | 3 | bool http_informational(int code) 4 | { 5 | return code >= 100 && code < 200; 6 | } 7 | 8 | bool http_success(int code) 9 | { 10 | return code >= 200 && code < 300; 11 | } 12 | 13 | bool http_redirection(int code) 14 | { 15 | return code >= 300 && code < 400; 16 | } 17 | 18 | bool http_client_error(int code) 19 | { 20 | return code >= 400 && code < 500; 21 | } 22 | 23 | bool http_server_error(int code) 24 | { 25 | return code >= 500 && code < 600; 26 | } 27 | 28 | bool http_failure(int code) 29 | { 30 | return code >= 400 && code < 600; 31 | } 32 | 33 | const char *http_status_group(int code) 34 | { 35 | if (http_informational(code)) 36 | return "Informational"; 37 | 38 | if (http_success(code)) 39 | return "Success"; 40 | 41 | if (http_redirection(code)) 42 | return "Redirection"; 43 | 44 | if (http_client_error(code)) 45 | return "Client Error"; 46 | 47 | if (http_server_error(code)) 48 | return "Server Error"; 49 | 50 | return "Unknown"; 51 | } 52 | 53 | const char *http_status_reason(int code) 54 | { 55 | switch (code) 56 | { 57 | /*####### 1xx - Informational #######*/ 58 | case 100: 59 | return "Continue"; 60 | case 101: 61 | return "Switching Protocols"; 62 | case 102: 63 | return "Processing"; 64 | case 103: 65 | return "Early Hints"; 66 | 67 | /*####### 2xx - Successful #######*/ 68 | case 200: 69 | return "OK"; 70 | case 201: 71 | return "Created"; 72 | case 202: 73 | return "Accepted"; 74 | case 203: 75 | return "Non-Authoritative Information"; 76 | case 204: 77 | return "No Content"; 78 | case 205: 79 | return "Reset Content"; 80 | case 206: 81 | return "Partial Content"; 82 | case 207: 83 | return "Multi-Status"; 84 | case 208: 85 | return "Already Reported"; 86 | case 226: 87 | return "IM Used"; 88 | 89 | /*####### 3xx - Redirection #######*/ 90 | case 300: 91 | return "Multiple Choices"; 92 | case 301: 93 | return "Moved Permanently"; 94 | case 302: 95 | return "Found"; 96 | case 303: 97 | return "See Other"; 98 | case 304: 99 | return "Not Modified"; 100 | case 305: 101 | return "Use Proxy"; 102 | case 307: 103 | return "Temporary Redirect"; 104 | case 308: 105 | return "Permanent Redirect"; 106 | 107 | /*####### 4xx - Client Error #######*/ 108 | case 400: 109 | return "Bad Request"; 110 | case 401: 111 | return "Unauthorized"; 112 | case 402: 113 | return "Payment Required"; 114 | case 403: 115 | return "Forbidden"; 116 | case 404: 117 | return "Not Found"; 118 | case 405: 119 | return "Method Not Allowed"; 120 | case 406: 121 | return "Not Acceptable"; 122 | case 407: 123 | return "Proxy Authentication Required"; 124 | case 408: 125 | return "Request Timeout"; 126 | case 409: 127 | return "Conflict"; 128 | case 410: 129 | return "Gone"; 130 | case 411: 131 | return "Length Required"; 132 | case 412: 133 | return "Precondition Failed"; 134 | case 413: 135 | return "Content Too Large"; 136 | case 414: 137 | return "URI Too Long"; 138 | case 415: 139 | return "Unsupported Media Type"; 140 | case 416: 141 | return "Range Not Satisfiable"; 142 | case 417: 143 | return "Expectation Failed"; 144 | case 418: 145 | return "I'm a teapot"; 146 | case 421: 147 | return "Misdirected Request"; 148 | case 422: 149 | return "Unprocessable Content"; 150 | case 423: 151 | return "Locked"; 152 | case 424: 153 | return "Failed Dependency"; 154 | case 425: 155 | return "Too Early"; 156 | case 426: 157 | return "Upgrade Required"; 158 | case 428: 159 | return "Precondition Required"; 160 | case 429: 161 | return "Too Many Requests"; 162 | case 431: 163 | return "Request Header Fields Too Large"; 164 | case 451: 165 | return "Unavailable For Legal Reasons"; 166 | 167 | /*####### 5xx - Server Error #######*/ 168 | case 500: 169 | return "Internal Server Error"; 170 | case 501: 171 | return "Not Implemented"; 172 | case 502: 173 | return "Bad Gateway"; 174 | case 503: 175 | return "Service Unavailable"; 176 | case 504: 177 | return "Gateway Timeout"; 178 | case 505: 179 | return "HTTP Version Not Supported"; 180 | case 506: 181 | return "Variant Also Negotiates"; 182 | case 507: 183 | return "Insufficient Storage"; 184 | case 508: 185 | return "Loop Detected"; 186 | case 510: 187 | return "Not Extended"; 188 | case 511: 189 | return "Network Authentication Required"; 190 | 191 | default: 192 | return "Unknown"; 193 | } 194 | } -------------------------------------------------------------------------------- /src/http_status.h: -------------------------------------------------------------------------------- 1 | #ifndef MICRO_HTTP_STATUS_H 2 | #define MICRO_HTTP_STATUS_H 3 | 4 | #include 5 | 6 | bool http_informational(int code); 7 | bool http_success(int code); 8 | bool http_redirection(int code); 9 | bool http_client_error(int code); 10 | bool http_server_error(int code); 11 | bool http_failure(int code); 12 | const char *http_status_group(int code); 13 | const char *http_status_reason(int code); 14 | 15 | #endif // MICRO_HTTP_STATUS_H --------------------------------------------------------------------------------