mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
2
.github/workflows/pre_release.yml
vendored
2
.github/workflows/pre_release.yml
vendored
@@ -50,6 +50,8 @@ jobs:
|
|||||||
- name: Build all PIO target environments from default_envs
|
- name: Build all PIO target environments from default_envs
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
|
env:
|
||||||
|
NO_BUILD_WEBUI: true
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
id: 'automatic_releases'
|
id: 'automatic_releases'
|
||||||
|
|||||||
2
.github/workflows/tagged_release.yml
vendored
2
.github/workflows/tagged_release.yml
vendored
@@ -44,6 +44,8 @@ jobs:
|
|||||||
- name: Build all PIO target environments from default_envs
|
- name: Build all PIO target environments from default_envs
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
|
env:
|
||||||
|
NO_BUILD_WEBUI: true
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
uses: emsesp/action-automatic-releases@v1.0.0
|
uses: emsesp/action-automatic-releases@v1.0.0
|
||||||
|
|||||||
11
.github/workflows/test_release.yml
vendored
11
.github/workflows/test_release.yml
vendored
@@ -12,24 +12,30 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Enable Corepack
|
||||||
run: corepack enable
|
run: corepack enable
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.11'
|
||||||
|
|
||||||
- name: Use Node.js 20.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: '20.x'
|
||||||
|
|
||||||
- name: Get EMS-ESP source code and version
|
- name: Get EMS-ESP source code and version
|
||||||
id: build_info
|
id: build_info
|
||||||
run: |
|
run: |
|
||||||
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/version.h | awk -F'"' '{print $2}'`
|
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/version.h | awk -F'"' '{print $2}'`
|
||||||
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -U platformio
|
pip install -U platformio
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Build WebUI
|
||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
@@ -38,9 +44,13 @@ jobs:
|
|||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn build
|
yarn build
|
||||||
yarn webUI
|
yarn webUI
|
||||||
|
|
||||||
- name: Build all target environments from default_envs
|
- name: Build all target environments from default_envs
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
|
env:
|
||||||
|
NO_BUILD_WEBUI: true
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
id: 'automatic_releases'
|
id: 'automatic_releases'
|
||||||
uses: emsesp/action-automatic-releases@v1.0.0
|
uses: emsesp/action-automatic-releases@v1.0.0
|
||||||
@@ -52,3 +62,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
CHANGELOG_LATEST.md
|
CHANGELOG_LATEST.md
|
||||||
./build/firmware/*.*
|
./build/firmware/*.*
|
||||||
|
|
||||||
|
|||||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -12,17 +12,15 @@ cppcheck.out.xml
|
|||||||
# platformio
|
# platformio
|
||||||
.pio
|
.pio
|
||||||
pio_local.ini
|
pio_local.ini
|
||||||
*_old
|
|
||||||
|
|
||||||
# OS specific
|
# OS specific
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*Thumbs.db
|
*Thumbs.db
|
||||||
|
|
||||||
# web specfic
|
# web specific
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
/data/www
|
/data/www
|
||||||
/lib/framework/WWWData.h
|
|
||||||
/interface/build
|
/interface/build
|
||||||
node_modules
|
node_modules
|
||||||
/interface/.eslintcache
|
/interface/.eslintcache
|
||||||
@@ -35,6 +33,9 @@ stats.html
|
|||||||
analyse.html
|
analyse.html
|
||||||
interface/vite.config.ts.timestamp*
|
interface/vite.config.ts.timestamp*
|
||||||
*.local
|
*.local
|
||||||
|
src/ESP32React/WWWData.h
|
||||||
|
.yarn/*
|
||||||
|
.yarnrc.yml
|
||||||
|
|
||||||
# i18n generated files
|
# i18n generated files
|
||||||
interface/src/i18n/i18n-react.tsx
|
interface/src/i18n/i18n-react.tsx
|
||||||
@@ -66,3 +67,12 @@ words-found-verbose.txt
|
|||||||
|
|
||||||
# sonarlint
|
# sonarlint
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
|
||||||
|
# pioarduino + hybrid
|
||||||
|
managed_components
|
||||||
|
dependencies.lock
|
||||||
|
CMakeLists.txt
|
||||||
|
.dummy/*
|
||||||
|
logs/*
|
||||||
|
sdkconfig.*
|
||||||
|
sdkconfig_tasmota_esp32
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -40,26 +40,20 @@ MAKEFLAGS += -j $(JOBS) -l $(JOBS)
|
|||||||
# INCLUDES is a list of directories containing header files
|
# INCLUDES is a list of directories containing header files
|
||||||
# LIBRARIES is a list of directories containing libraries, this must be the top level containing include and lib
|
# LIBRARIES is a list of directories containing libraries, this must be the top level containing include and lib
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
#TARGET := $(notdir $(CURDIR))
|
|
||||||
TARGET := emsesp
|
TARGET := emsesp
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := src src/* lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src lib/PButton lib/semver lib/espMqttClient/src lib/espMqttClient/src/*
|
SOURCES := src/core src/devices src/web src/test lib_standalone lib/semver lib/espMqttClient/src lib/espMqttClient/src/* lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/PButton
|
||||||
INCLUDES := src lib_standalone lib/espMqttClient/src lib/espMqttClient/src/Transport lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src lib/semver lib/* src/devices
|
INCLUDES := src/core src/devices src/web src/test lib/* lib_standalone lib/semver lib/espMqttClient/src lib/espMqttClient/src/Transport lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src
|
||||||
LIBRARIES :=
|
LIBRARIES :=
|
||||||
|
|
||||||
CPPCHECK = cppcheck
|
CPPCHECK = cppcheck
|
||||||
# CHECKFLAGS = -q --force --std=c++17
|
CHECKFLAGS = -q --force --std=gnu++17
|
||||||
CHECKFLAGS = -q --force --std=c++11
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Languages Standard
|
# Languages Standard
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
C_STANDARD := -std=c17
|
C_STANDARD := -std=c17
|
||||||
CXX_STANDARD := -std=gnu++14
|
CXX_STANDARD := -std=gnu++17
|
||||||
|
|
||||||
# C_STANDARD := -std=c11
|
|
||||||
# CXX_STANDARD := -std=c++11
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Defined Symbols
|
# Defined Symbols
|
||||||
@@ -68,7 +62,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO
|
|||||||
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
|
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
|
||||||
DEFINES += $(ARGS)
|
DEFINES += $(ARGS)
|
||||||
|
|
||||||
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.1-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S3\"
|
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.2-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S3\"
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
@@ -108,7 +102,7 @@ CPPFLAGS += -Os
|
|||||||
|
|
||||||
CFLAGS += $(CPPFLAGS)
|
CFLAGS += $(CPPFLAGS)
|
||||||
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum
|
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum
|
||||||
CFLAGS += -Wno-tautological-constant-out-of-range-compare -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture -Wno-sign-compare
|
CFLAGS += -Wno-unused-parameter -Wno-missing-braces -Wno-sign-compare
|
||||||
CXXFLAGS += $(CFLAGS) -MMD
|
CXXFLAGS += $(CFLAGS) -MMD
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|||||||
44
boards/c3_mini_4M.json
Normal file
44
boards/c3_mini_4M.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32c3_out.ld"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DARDUINO_LOLIN_C3_MINI",
|
||||||
|
"-DARDUINO_USB_MODE=1",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "160000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [
|
||||||
|
[
|
||||||
|
"0X303A",
|
||||||
|
"0x1001"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"mcu": "esp32c3",
|
||||||
|
"variant": "lolin_c3_mini"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32c3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "WEMOS LOLIN C3 Mini",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "4MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 4194304,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"url": "https://www.wemos.cc/en/latest/c3/c3_mini.html",
|
||||||
|
"vendor": "WEMOS"
|
||||||
|
}
|
||||||
47
boards/s2_4M_P.json
Normal file
47
boards/s2_4M_P.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s2_out.ld"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DTASMOTA_SDK",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"hwids": [
|
||||||
|
[
|
||||||
|
"0X303A",
|
||||||
|
"0x80C2"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"mcu": "esp32s2",
|
||||||
|
"variant": "lolin_s2_mini"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s2.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "WEMOS LOLIN S2 Mini",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "4MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 4194304,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://www.wemos.cc/en/latest/s2/s2_mini.html",
|
||||||
|
"vendor": "WEMOS"
|
||||||
|
}
|
||||||
40
boards/s3_16M_P.json
Normal file
40
boards/s3_16M_P.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_USB_MODE=1",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "esp32s3"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Espressif Generic ESP32-S3 16M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"speed": 230400
|
||||||
|
},
|
||||||
|
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
37
boards/s3_32M_P.json
Normal file
37
boards/s3_32M_P.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino":{
|
||||||
|
"memory_type": "opi_opi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": "-DBOARD_HAS_PSRAM",
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "opi",
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "esp32s3"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Espressif Generic ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "32MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"speed": 230400
|
||||||
|
},
|
||||||
|
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
35
boards/s_16M.json
Normal file
35
boards/s_16M.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": "-DTASMOTA_SDK",
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"mcu": "esp32",
|
||||||
|
"variant": "esp32"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi",
|
||||||
|
"ethernet"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Espressif Generic ESP32 16M Flash, Tasmota 4608KB Code/OTA, 2MB FS",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"speed": 230400
|
||||||
|
},
|
||||||
|
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
35
boards/s_16M_P.json
Normal file
35
boards/s_16M_P.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": "-DBOARD_HAS_PSRAM",
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"mcu": "esp32",
|
||||||
|
"variant": "esp32"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi",
|
||||||
|
"ethernet"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Espressif Generic ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"speed": 230400
|
||||||
|
},
|
||||||
|
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
34
boards/s_4M.json
Normal file
34
boards/s_4M.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": "-DTASMOTA_SDK",
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "40000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"mcu": "esp32",
|
||||||
|
"variant": "esp32"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Espressif Generic ESP32 4M Flash, Tasmota 4608KB Code/OTA, 2MB FS",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "4MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 4194304,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"speed": 230400
|
||||||
|
},
|
||||||
|
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
"**/i18n/**",
|
"**/i18n/**",
|
||||||
"/project-words.txt",
|
"/project-words.txt",
|
||||||
"Makefile",
|
"Makefile",
|
||||||
|
"**/*.ini",
|
||||||
|
"**/*.json",
|
||||||
"src/modbus_entity_parameters.hpp"
|
"src/modbus_entity_parameters.hpp"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"@alova/adapter-xhr": "2.1.0",
|
"@alova/adapter-xhr": "2.1.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@mui/icons-material": "^6.3.0",
|
"@mui/icons-material": "^6.3.1",
|
||||||
"@mui/material": "^6.3.0",
|
"@mui/material": "^6.3.1",
|
||||||
"@table-library/react-table-library": "4.1.7",
|
"@table-library/react-table-library": "4.1.7",
|
||||||
"alova": "3.2.7",
|
"alova": "3.2.7",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"@babel/core": "^7.26.0",
|
"@babel/core": "^7.26.0",
|
||||||
"@eslint/js": "^9.17.0",
|
"@eslint/js": "^9.17.0",
|
||||||
"@preact/compat": "^18.3.1",
|
"@preact/compat": "^18.3.1",
|
||||||
"@preact/preset-vite": "^2.9.3",
|
"@preact/preset-vite": "^2.9.4",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.0",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.1",
|
||||||
"@types/formidable": "^3",
|
"@types/formidable": "^3",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.5",
|
||||||
"@types/react": "^19.0.2",
|
"@types/react": "^19.0.2",
|
||||||
"@types/react-dom": "^19.0.2",
|
"@types/react-dom": "^19.0.2",
|
||||||
"concurrently": "^9.1.2",
|
"concurrently": "^9.1.2",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
"rollup-plugin-visualizer": "^5.13.1",
|
"rollup-plugin-visualizer": "^5.13.1",
|
||||||
"terser": "^5.37.0",
|
"terser": "^5.37.0",
|
||||||
"typescript-eslint": "8.19.0",
|
"typescript-eslint": "8.19.0",
|
||||||
"vite": "^6.0.6",
|
"vite": "^6.0.7",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"vite-tsconfig-paths": "^5.1.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import zlib from 'zlib';
|
|||||||
|
|
||||||
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
||||||
const INDENT = ' ';
|
const INDENT = ' ';
|
||||||
const outputPath = '../lib/framework/WWWData.h';
|
const outputPath = '../src/ESP32React/WWWData.h';
|
||||||
const sourcePath = './dist';
|
const sourcePath = './dist';
|
||||||
const bytesPerLine = 20;
|
const bytesPerLine = 20;
|
||||||
var totalSize = 0;
|
var totalSize = 0;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { IconContext } from 'react-icons/lib';
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||||
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
|
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
|
||||||
@@ -235,7 +236,10 @@ const Dashboard = () => {
|
|||||||
<Grid container spacing={0} justifyContent="flex-start">
|
<Grid container spacing={0} justifyContent="flex-start">
|
||||||
<Grid size={11}>
|
<Grid size={11}>
|
||||||
<Typography mb={2} variant="body1" color="warning">
|
<Typography mb={2} variant="body1" color="warning">
|
||||||
{LL.DASHBOARD_1()}.
|
{LL.DASHBOARD_1()}
|
||||||
|
<ConstructionIcon
|
||||||
|
sx={{ color: '#9e9e9e', fontSize: 20, verticalAlign: 'middle' }}
|
||||||
|
/>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,6 @@ const LayoutMenu = () => {
|
|||||||
>
|
>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.MODULES()}
|
primary={LL.MODULES()}
|
||||||
primaryTypographyProps={{
|
|
||||||
fontWeight: '600',
|
|
||||||
mb: '2px',
|
|
||||||
color: 'lightblue'
|
|
||||||
}}
|
|
||||||
// secondary={
|
// secondary={
|
||||||
// LL.CUSTOMIZATIONS() +
|
// LL.CUSTOMIZATIONS() +
|
||||||
// ', ' +
|
// ', ' +
|
||||||
@@ -92,6 +87,13 @@ const LayoutMenu = () => {
|
|||||||
// color: menuOpen ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0.5)'
|
// color: menuOpen ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0.5)'
|
||||||
// }}
|
// }}
|
||||||
sx={{ my: 0 }}
|
sx={{ my: 0 }}
|
||||||
|
slotProps={{
|
||||||
|
primary: {
|
||||||
|
fontWeight: '600',
|
||||||
|
mb: '2px',
|
||||||
|
color: 'lightblue'
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<KeyboardArrowDown
|
<KeyboardArrowDown
|
||||||
sx={{
|
sx={{
|
||||||
@@ -132,7 +134,6 @@ const LayoutMenu = () => {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<List style={{ marginTop: `auto` }}>
|
<List style={{ marginTop: `auto` }}>
|
||||||
<LayoutMenuItem
|
<LayoutMenuItem
|
||||||
icon={AssessmentIcon}
|
icon={AssessmentIcon}
|
||||||
@@ -158,7 +159,6 @@ const LayoutMenu = () => {
|
|||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
id={id}
|
id={id}
|
||||||
open={open}
|
open={open}
|
||||||
|
|||||||
@@ -347,4 +347,4 @@ const nl: Translation = {
|
|||||||
UPGRADE: 'Upgraden'
|
UPGRADE: 'Upgraden'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
@@ -782,38 +782,38 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/core-downloads-tracker@npm:^6.3.0":
|
"@mui/core-downloads-tracker@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/core-downloads-tracker@npm:6.3.0"
|
resolution: "@mui/core-downloads-tracker@npm:6.3.1"
|
||||||
checksum: 10c0/56a421866c727a7c785247212a5f04cb5dd8a2b46b2badce5065ea8d6eb04e5ac8b4f981d4c33beebd866d803ea87328a79ec9baeba32611275f9805ceb0a074
|
checksum: 10c0/a996ad8db6bd8c981c4e2e2d243526c838dd29f0bbe7dc5ab6933be357e41f748781d322b1decf79ae1c9abba24190162559d84deedcb7c8824a68754dddf216
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/icons-material@npm:^6.3.0":
|
"@mui/icons-material@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/icons-material@npm:6.3.0"
|
resolution: "@mui/icons-material@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@mui/material": ^6.3.0
|
"@mui/material": ^6.3.1
|
||||||
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/42fd80f5a95a7736f567bf9181c4986c78f7dd3d129610a822070f0d3dd2cc86c6dfd6444468bfd9e3a616890e5c9f4722f84218eb1d020bb75f2fab15d2526f
|
checksum: 10c0/edaf71b7368c14cfbfed6f475ef96187871a010e972b9e7608d23cadae5ce52a3a6888b32453721dc1d86e2e7ad9c61aadde83ba5cd94363782bf83803d1ab36
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/material@npm:^6.3.0":
|
"@mui/material@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/material@npm:6.3.0"
|
resolution: "@mui/material@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
"@mui/core-downloads-tracker": "npm:^6.3.0"
|
"@mui/core-downloads-tracker": "npm:^6.3.1"
|
||||||
"@mui/system": "npm:^6.3.0"
|
"@mui/system": "npm:^6.3.1"
|
||||||
"@mui/types": "npm:^7.2.20"
|
"@mui/types": "npm:^7.2.21"
|
||||||
"@mui/utils": "npm:^6.3.0"
|
"@mui/utils": "npm:^6.3.1"
|
||||||
"@popperjs/core": "npm:^2.11.8"
|
"@popperjs/core": "npm:^2.11.8"
|
||||||
"@types/react-transition-group": "npm:^4.4.12"
|
"@types/react-transition-group": "npm:^4.4.12"
|
||||||
clsx: "npm:^2.1.1"
|
clsx: "npm:^2.1.1"
|
||||||
@@ -824,7 +824,7 @@ __metadata:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@emotion/react": ^11.5.0
|
"@emotion/react": ^11.5.0
|
||||||
"@emotion/styled": ^11.3.0
|
"@emotion/styled": ^11.3.0
|
||||||
"@mui/material-pigment-css": ^6.3.0
|
"@mui/material-pigment-css": ^6.3.1
|
||||||
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
@@ -837,16 +837,16 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/9a21ea88e79e19105916db8df1e2da95f5216dd57678000992d2bdfaa611772acd28c085fd058b474cfc846363b2165a9e587f9100bfd142edefffa4762323f8
|
checksum: 10c0/7fb91acd9bc021dde78e70d495a2abd69d0e2df35e526e0730e060c3177bb10cc3058ee27c72b5ec9bc7622d9c2ef99831b89f511f6700bc3717f979e2cb0152
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/private-theming@npm:^6.3.0":
|
"@mui/private-theming@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/private-theming@npm:6.3.0"
|
resolution: "@mui/private-theming@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
"@mui/utils": "npm:^6.3.0"
|
"@mui/utils": "npm:^6.3.1"
|
||||||
prop-types: "npm:^15.8.1"
|
prop-types: "npm:^15.8.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
@@ -854,13 +854,13 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/57d0b429914b6095b3605e99ea2c23b8ad834220426bed6938ef60b2f8eaaa2fbf800ffdfcf6e59b88e74900adb60a9c1f5ea25338b2254e1530e0bf7ee04f1f
|
checksum: 10c0/aafaca0d7e5fd4d83c2cade28b7de554c0d848595f8f23f26c8f7daf3fc664053c9c81342d44d24e0a04a4813b58d6f0c1d135ae2775380acda91468a21f9684
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/styled-engine@npm:^6.3.0":
|
"@mui/styled-engine@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/styled-engine@npm:6.3.0"
|
resolution: "@mui/styled-engine@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
"@emotion/cache": "npm:^11.13.5"
|
"@emotion/cache": "npm:^11.13.5"
|
||||||
@@ -877,19 +877,19 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
"@emotion/styled":
|
"@emotion/styled":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/840053c3dedcd2299e713839e2fae3fad5faa943c491bf54e513ae0c68d3dec7acef8e234e1632b89de4bcb2bdf9fe08553faf89f85ae2cd8588ca197d0ecd55
|
checksum: 10c0/81bbf8f2016b1c7debbbaab1a44ebaf8e494e8c9d32d2201b28f8c653a082177f6570fef779bf835bad1a9120af219a64b1d7a9a8a569c9c07045f00affe6b87
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/system@npm:^6.3.0":
|
"@mui/system@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/system@npm:6.3.0"
|
resolution: "@mui/system@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
"@mui/private-theming": "npm:^6.3.0"
|
"@mui/private-theming": "npm:^6.3.1"
|
||||||
"@mui/styled-engine": "npm:^6.3.0"
|
"@mui/styled-engine": "npm:^6.3.1"
|
||||||
"@mui/types": "npm:^7.2.20"
|
"@mui/types": "npm:^7.2.21"
|
||||||
"@mui/utils": "npm:^6.3.0"
|
"@mui/utils": "npm:^6.3.1"
|
||||||
clsx: "npm:^2.1.1"
|
clsx: "npm:^2.1.1"
|
||||||
csstype: "npm:^3.1.3"
|
csstype: "npm:^3.1.3"
|
||||||
prop-types: "npm:^15.8.1"
|
prop-types: "npm:^15.8.1"
|
||||||
@@ -905,28 +905,28 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/ee50e38919b3f86fbd6978d06959189a5903223156c1355bc0ff251d553f2eda8ffafe2fa006da2e00e12947f6c8efd7f796bbb6cc5c472106400c2ed8e6dd1e
|
checksum: 10c0/49613b001f7e60c7ed70f3e2ee3ffc4f3a2719509e4f9ec18faf73a354597b8d894d0ee8861bf3a5b5db763efca36bcfb75989505c88e009c1627b114bac88ef
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/types@npm:^7.2.20":
|
"@mui/types@npm:^7.2.21":
|
||||||
version: 7.2.20
|
version: 7.2.21
|
||||||
resolution: "@mui/types@npm:7.2.20"
|
resolution: "@mui/types@npm:7.2.21"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/257285386903fe0705ac6d53d0ece700323b7bc9be5239ab448b2c6523965b3cadbb636f2aec8ff60354180f53daf78df687d6828a75ad220b0f71fb5a117b5e
|
checksum: 10c0/c0038ae402a3cfb2805a19167362fb5ac2ca1403f0ef3dad688d1e2276afe757b69d5fb1e3af4cd0e985b9221d287fd863c5b00f29fd07a276c7de9e3423a0f3
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mui/utils@npm:^6.3.0":
|
"@mui/utils@npm:^6.3.1":
|
||||||
version: 6.3.0
|
version: 6.3.1
|
||||||
resolution: "@mui/utils@npm:6.3.0"
|
resolution: "@mui/utils@npm:6.3.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.26.0"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
"@mui/types": "npm:^7.2.20"
|
"@mui/types": "npm:^7.2.21"
|
||||||
"@types/prop-types": "npm:^15.7.14"
|
"@types/prop-types": "npm:^15.7.14"
|
||||||
clsx: "npm:^2.1.1"
|
clsx: "npm:^2.1.1"
|
||||||
prop-types: "npm:^15.8.1"
|
prop-types: "npm:^15.8.1"
|
||||||
@@ -937,7 +937,7 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@types/react":
|
"@types/react":
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/7059664a5471d93f3593f83816c5c3cc81e7d0879842edf2a302db324c430d349bd88dd93bffad8f8349271b45e27f18f31e0341e13408ccc65b1af247b33efd
|
checksum: 10c0/b111bca7ad065b1028714d55a8df90267c47a72ffb2bfad7a1709cef0d5d9036b463855d431b3606967c9351c7ee23f1dee02457b2f3ed02513744f0173eb00c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1013,9 +1013,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@preact/preset-vite@npm:^2.9.3":
|
"@preact/preset-vite@npm:^2.9.4":
|
||||||
version: 2.9.3
|
version: 2.9.4
|
||||||
resolution: "@preact/preset-vite@npm:2.9.3"
|
resolution: "@preact/preset-vite@npm:2.9.4"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame": "npm:^7.22.13"
|
"@babel/code-frame": "npm:^7.22.13"
|
||||||
"@babel/plugin-transform-react-jsx": "npm:^7.22.15"
|
"@babel/plugin-transform-react-jsx": "npm:^7.22.15"
|
||||||
@@ -1032,7 +1032,7 @@ __metadata:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@babel/core": 7.x
|
"@babel/core": 7.x
|
||||||
vite: 2.x || 3.x || 4.x || 5.x || 6.x
|
vite: 2.x || 3.x || 4.x || 5.x || 6.x
|
||||||
checksum: 10c0/61f7a9869dd7a5eb145851622cb219bf7dfffea770641a85d4e5560a9e263af4f07cbea3795d44abec7efaaa789b33f7dd20f6f99e14ce9a3a202dd584013efe
|
checksum: 10c0/a42aab866ef1ea4d2dac82be3a5b5c207c5e030d429cc5dbe88a259da0a52a1fd8f21f77d1ce2bef82a803b854f7653a579aed0aa7eca371108e5308ba43bc2f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1240,9 +1240,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@trivago/prettier-plugin-sort-imports@npm:^5.2.0":
|
"@trivago/prettier-plugin-sort-imports@npm:^5.2.1":
|
||||||
version: 5.2.0
|
version: 5.2.1
|
||||||
resolution: "@trivago/prettier-plugin-sort-imports@npm:5.2.0"
|
resolution: "@trivago/prettier-plugin-sort-imports@npm:5.2.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/generator": "npm:^7.26.2"
|
"@babel/generator": "npm:^7.26.2"
|
||||||
"@babel/parser": "npm:^7.26.2"
|
"@babel/parser": "npm:^7.26.2"
|
||||||
@@ -1254,7 +1254,7 @@ __metadata:
|
|||||||
"@vue/compiler-sfc": 3.x
|
"@vue/compiler-sfc": 3.x
|
||||||
prettier: 2.x - 3.x
|
prettier: 2.x - 3.x
|
||||||
prettier-plugin-svelte: 3.x
|
prettier-plugin-svelte: 3.x
|
||||||
svelte: 4.x
|
svelte: 4.x || 5.x
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@vue/compiler-sfc":
|
"@vue/compiler-sfc":
|
||||||
optional: true
|
optional: true
|
||||||
@@ -1262,7 +1262,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
svelte:
|
svelte:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/73ebdea1f5cef609e1bf7ed7a276916770de210d29e512dfcdac68fafd05cc155f5aec5962bcce65952d24e43aeee81bc58caf37c8d298e7d7f23d4851534405
|
checksum: 10c0/fd782f84d44c61159dce099775a86ebb5082b5e5eea205ec71d6fede3cf079aafb8f9a9979d5742ff0126598a37098cf679d5bad268320907513f2984df3d501
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1402,12 +1402,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:*, @types/node@npm:^22.10.2":
|
"@types/node@npm:*, @types/node@npm:^22.10.5":
|
||||||
version: 22.10.2
|
version: 22.10.5
|
||||||
resolution: "@types/node@npm:22.10.2"
|
resolution: "@types/node@npm:22.10.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: "npm:~6.20.0"
|
undici-types: "npm:~6.20.0"
|
||||||
checksum: 10c0/2c7b71a040f1ef5320938eca8ebc946e6905caa9bbf3d5665d9b3774a8d15ea9fab1582b849a6d28c7fc80756a62c5666bc66b69f42f4d5dafd1ccb193cdb4ac
|
checksum: 10c0/6a0e7d1fe6a86ef6ee19c3c6af4c15542e61aea2f4cee655b6252efb356795f1f228bc8299921e82924e80ff8eca29b74d9dd0dd5cc1a90983f892f740b480df
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1591,14 +1591,14 @@ __metadata:
|
|||||||
"@emotion/react": "npm:^11.14.0"
|
"@emotion/react": "npm:^11.14.0"
|
||||||
"@emotion/styled": "npm:^11.14.0"
|
"@emotion/styled": "npm:^11.14.0"
|
||||||
"@eslint/js": "npm:^9.17.0"
|
"@eslint/js": "npm:^9.17.0"
|
||||||
"@mui/icons-material": "npm:^6.3.0"
|
"@mui/icons-material": "npm:^6.3.1"
|
||||||
"@mui/material": "npm:^6.3.0"
|
"@mui/material": "npm:^6.3.1"
|
||||||
"@preact/compat": "npm:^18.3.1"
|
"@preact/compat": "npm:^18.3.1"
|
||||||
"@preact/preset-vite": "npm:^2.9.3"
|
"@preact/preset-vite": "npm:^2.9.4"
|
||||||
"@table-library/react-table-library": "npm:4.1.7"
|
"@table-library/react-table-library": "npm:4.1.7"
|
||||||
"@trivago/prettier-plugin-sort-imports": "npm:^5.2.0"
|
"@trivago/prettier-plugin-sort-imports": "npm:^5.2.1"
|
||||||
"@types/formidable": "npm:^3"
|
"@types/formidable": "npm:^3"
|
||||||
"@types/node": "npm:^22.10.2"
|
"@types/node": "npm:^22.10.5"
|
||||||
"@types/react": "npm:^19.0.2"
|
"@types/react": "npm:^19.0.2"
|
||||||
"@types/react-dom": "npm:^19.0.2"
|
"@types/react-dom": "npm:^19.0.2"
|
||||||
alova: "npm:3.2.7"
|
alova: "npm:3.2.7"
|
||||||
@@ -1621,7 +1621,7 @@ __metadata:
|
|||||||
typesafe-i18n: "npm:^5.26.2"
|
typesafe-i18n: "npm:^5.26.2"
|
||||||
typescript: "npm:^5.7.2"
|
typescript: "npm:^5.7.2"
|
||||||
typescript-eslint: "npm:8.19.0"
|
typescript-eslint: "npm:8.19.0"
|
||||||
vite: "npm:^6.0.6"
|
vite: "npm:^6.0.7"
|
||||||
vite-plugin-imagemin: "npm:^0.6.1"
|
vite-plugin-imagemin: "npm:^0.6.1"
|
||||||
vite-tsconfig-paths: "npm:^5.1.4"
|
vite-tsconfig-paths: "npm:^5.1.4"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@@ -6839,9 +6839,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vite@npm:^6.0.6":
|
"vite@npm:^6.0.7":
|
||||||
version: 6.0.6
|
version: 6.0.7
|
||||||
resolution: "vite@npm:6.0.6"
|
resolution: "vite@npm:6.0.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: "npm:^0.24.2"
|
esbuild: "npm:^0.24.2"
|
||||||
fsevents: "npm:~2.3.3"
|
fsevents: "npm:~2.3.3"
|
||||||
@@ -6887,7 +6887,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
bin:
|
bin:
|
||||||
vite: bin/vite.js
|
vite: bin/vite.js
|
||||||
checksum: 10c0/144c3f80a7920a4b2fa14f00f99b58ece246455ca9313561a67a227b45dadac3343e406d3c1dbfafa79992ac88f54cb2b040b229997e432daf47594fe8cacec2
|
checksum: 10c0/ae81047b4290a7206b9394a39a782d509e9610462e7946422ba22d5bc615b5a322c07e33d7bf9dd0b3312ec3f5c63353b725913d1519324bfdf539b4f1e03f52
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
Version 7.2.1
|
|
||||||
|
|
||||||
From https://github.com/bblanchon/ArduinoJson/releases
|
|
||||||
|
|
||||||
MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright © 2014-2024, Benoit BLANCHON
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# AsyncTCP
|
|
||||||
|
|
||||||

|
|
||||||
A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev) for [ESPHome](https://esphome.io).
|
|
||||||
|
|
||||||
### Async TCP Library for ESP32 Arduino
|
|
||||||
|
|
||||||
This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs.
|
|
||||||
|
|
||||||
This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
|
|
||||||
|
|
||||||
## AsyncClient and AsyncServer
|
|
||||||
|
|
||||||
The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous TCP library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ASYNCTCP_H_
|
|
||||||
#define ASYNCTCP_H_
|
|
||||||
|
|
||||||
#define ASYNCTCP_VERSION "3.2.14"
|
|
||||||
#define ASYNCTCP_VERSION_MAJOR 3
|
|
||||||
#define ASYNCTCP_VERSION_MINOR 2
|
|
||||||
#define ASYNCTCP_VERSION_REVISION 14
|
|
||||||
#define ASYNCTCP_FORK_mathieucarbou
|
|
||||||
|
|
||||||
#include "IPAddress.h"
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
#include "IPv6Address.h"
|
|
||||||
#endif
|
|
||||||
#include <functional>
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/ip6_addr.h"
|
|
||||||
|
|
||||||
#ifndef LIBRETINY
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
extern "C" {
|
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
extern "C" {
|
|
||||||
#include <semphr.h>
|
|
||||||
#include <lwip/pbuf.h>
|
|
||||||
}
|
|
||||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
|
|
||||||
#define CONFIG_ASYNC_TCP_USE_WDT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//If core is not defined, then we are running in Arduino or PIO
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
|
|
||||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
|
|
||||||
// Note default was 1 and previously set to 0 for EMS-ESP
|
|
||||||
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// EMS-ESP: stack usage measured: ESP32: ~2.3K, ESP32S3: ~3.5k
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
|
|
||||||
#define CONFIG_ASYNC_TCP_STACK_SIZE 6144
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_PRIORITY
|
|
||||||
#define CONFIG_ASYNC_TCP_PRIORITY 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// EMS-ESP: maybe enlarge queue to 64 or 128 see https://github.com/emsesp/EMS-ESP32/issues/177
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE
|
|
||||||
#define CONFIG_ASYNC_TCP_QUEUE_SIZE 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME
|
|
||||||
#define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncClient;
|
|
||||||
|
|
||||||
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
|
|
||||||
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
|
|
||||||
|
|
||||||
typedef std::function<void(void *, AsyncClient *)> AcConnectHandler;
|
|
||||||
typedef std::function<void(void *, AsyncClient *, size_t len, uint32_t time)> AcAckHandler;
|
|
||||||
typedef std::function<void(void *, AsyncClient *, int8_t error)> AcErrorHandler;
|
|
||||||
typedef std::function<void(void *, AsyncClient *, void * data, size_t len)> AcDataHandler;
|
|
||||||
typedef std::function<void(void *, AsyncClient *, struct pbuf * pb)> AcPacketHandler;
|
|
||||||
typedef std::function<void(void *, AsyncClient *, uint32_t time)> AcTimeoutHandler;
|
|
||||||
|
|
||||||
struct tcp_pcb;
|
|
||||||
struct ip_addr;
|
|
||||||
|
|
||||||
class AsyncClient {
|
|
||||||
public:
|
|
||||||
AsyncClient(tcp_pcb * pcb = 0);
|
|
||||||
~AsyncClient();
|
|
||||||
|
|
||||||
AsyncClient & operator=(const AsyncClient & other);
|
|
||||||
AsyncClient & operator+=(const AsyncClient & other);
|
|
||||||
|
|
||||||
bool operator==(const AsyncClient & other);
|
|
||||||
|
|
||||||
bool operator!=(const AsyncClient & other) {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
bool connect(const IPAddress & ip, uint16_t port);
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
bool connect(const IPv6Address & ip, uint16_t port);
|
|
||||||
#endif
|
|
||||||
bool connect(const char * host, uint16_t port);
|
|
||||||
void close(bool now = false);
|
|
||||||
void stop();
|
|
||||||
int8_t abort();
|
|
||||||
bool free();
|
|
||||||
|
|
||||||
bool canSend(); //ack is not pending
|
|
||||||
size_t space(); //space available in the TCP window
|
|
||||||
size_t add(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //add for sending
|
|
||||||
bool send(); //send all data added with the method above
|
|
||||||
|
|
||||||
//write equals add()+send()
|
|
||||||
size_t write(const char * data);
|
|
||||||
size_t write(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
|
|
||||||
|
|
||||||
uint8_t state();
|
|
||||||
bool connecting();
|
|
||||||
bool connected();
|
|
||||||
bool disconnecting();
|
|
||||||
bool disconnected();
|
|
||||||
bool freeable(); //disconnected or disconnecting
|
|
||||||
|
|
||||||
uint16_t getMss();
|
|
||||||
|
|
||||||
uint32_t getRxTimeout();
|
|
||||||
void setRxTimeout(uint32_t timeout); //no RX data timeout for the connection in seconds
|
|
||||||
|
|
||||||
uint32_t getAckTimeout();
|
|
||||||
void setAckTimeout(uint32_t timeout); //no ACK timeout for the last sent packet in milliseconds
|
|
||||||
|
|
||||||
void setNoDelay(bool nodelay);
|
|
||||||
bool getNoDelay();
|
|
||||||
|
|
||||||
void setKeepAlive(uint32_t ms, uint8_t cnt);
|
|
||||||
|
|
||||||
uint32_t getRemoteAddress();
|
|
||||||
uint16_t getRemotePort();
|
|
||||||
uint32_t getLocalAddress();
|
|
||||||
uint16_t getLocalPort();
|
|
||||||
#if LWIP_IPV6
|
|
||||||
ip6_addr_t getRemoteAddress6();
|
|
||||||
ip6_addr_t getLocalAddress6();
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
IPv6Address remoteIP6();
|
|
||||||
IPv6Address localIP6();
|
|
||||||
#else
|
|
||||||
IPAddress remoteIP6();
|
|
||||||
IPAddress localIP6();
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//compatibility
|
|
||||||
IPAddress remoteIP();
|
|
||||||
uint16_t remotePort();
|
|
||||||
IPAddress localIP();
|
|
||||||
uint16_t localPort();
|
|
||||||
|
|
||||||
void onConnect(AcConnectHandler cb, void * arg = 0); //on successful connect
|
|
||||||
void onDisconnect(AcConnectHandler cb, void * arg = 0); //disconnected
|
|
||||||
void onAck(AcAckHandler cb, void * arg = 0); //ack received
|
|
||||||
void onError(AcErrorHandler cb, void * arg = 0); //unsuccessful connect or error
|
|
||||||
void onData(AcDataHandler cb, void * arg = 0); //data received (called if onPacket is not used)
|
|
||||||
void onPacket(AcPacketHandler cb, void * arg = 0); //data received
|
|
||||||
void onTimeout(AcTimeoutHandler cb, void * arg = 0); //ack timeout
|
|
||||||
void onPoll(AcConnectHandler cb, void * arg = 0); //every 125ms when connected
|
|
||||||
|
|
||||||
void ackPacket(struct pbuf * pb); //ack pbuf from onPacket
|
|
||||||
size_t ack(size_t len); //ack data that you have not acked using the method below
|
|
||||||
void ackLater() {
|
|
||||||
_ack_pcb = false;
|
|
||||||
} //will not ack the current packet. Call from onData
|
|
||||||
|
|
||||||
const char * errorToString(int8_t error);
|
|
||||||
const char * stateToString();
|
|
||||||
|
|
||||||
//Do not use any of the functions below!
|
|
||||||
static int8_t _s_poll(void * arg, struct tcp_pcb * tpcb);
|
|
||||||
static int8_t _s_recv(void * arg, struct tcp_pcb * tpcb, struct pbuf * pb, int8_t err);
|
|
||||||
static int8_t _s_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
|
|
||||||
static int8_t _s_lwip_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
|
|
||||||
static void _s_error(void * arg, int8_t err);
|
|
||||||
static int8_t _s_sent(void * arg, struct tcp_pcb * tpcb, uint16_t len);
|
|
||||||
static int8_t _s_connected(void * arg, struct tcp_pcb * tpcb, int8_t err);
|
|
||||||
static void _s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
|
|
||||||
|
|
||||||
int8_t _recv(tcp_pcb * pcb, pbuf * pb, int8_t err);
|
|
||||||
tcp_pcb * pcb() {
|
|
||||||
return _pcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool _connect(ip_addr_t addr, uint16_t port);
|
|
||||||
|
|
||||||
tcp_pcb * _pcb;
|
|
||||||
int8_t _closed_slot;
|
|
||||||
|
|
||||||
AcConnectHandler _connect_cb;
|
|
||||||
void * _connect_cb_arg;
|
|
||||||
AcConnectHandler _discard_cb;
|
|
||||||
void * _discard_cb_arg;
|
|
||||||
AcAckHandler _sent_cb;
|
|
||||||
void * _sent_cb_arg;
|
|
||||||
AcErrorHandler _error_cb;
|
|
||||||
void * _error_cb_arg;
|
|
||||||
AcDataHandler _recv_cb;
|
|
||||||
void * _recv_cb_arg;
|
|
||||||
AcPacketHandler _pb_cb;
|
|
||||||
void * _pb_cb_arg;
|
|
||||||
AcTimeoutHandler _timeout_cb;
|
|
||||||
void * _timeout_cb_arg;
|
|
||||||
AcConnectHandler _poll_cb;
|
|
||||||
void * _poll_cb_arg;
|
|
||||||
|
|
||||||
bool _ack_pcb;
|
|
||||||
uint32_t _tx_last_packet;
|
|
||||||
uint32_t _rx_ack_len;
|
|
||||||
uint32_t _rx_last_packet;
|
|
||||||
uint32_t _rx_timeout;
|
|
||||||
uint32_t _rx_last_ack;
|
|
||||||
uint32_t _ack_timeout;
|
|
||||||
uint16_t _connect_port;
|
|
||||||
|
|
||||||
int8_t _close();
|
|
||||||
void _free_closed_slot();
|
|
||||||
bool _allocate_closed_slot();
|
|
||||||
int8_t _connected(tcp_pcb * pcb, int8_t err);
|
|
||||||
void _error(int8_t err);
|
|
||||||
int8_t _poll(tcp_pcb * pcb);
|
|
||||||
int8_t _sent(tcp_pcb * pcb, uint16_t len);
|
|
||||||
int8_t _fin(tcp_pcb * pcb, int8_t err);
|
|
||||||
int8_t _lwip_fin(tcp_pcb * pcb, int8_t err);
|
|
||||||
void _dns_found(struct ip_addr * ipaddr);
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncClient * prev;
|
|
||||||
AsyncClient * next;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncServer {
|
|
||||||
public:
|
|
||||||
AsyncServer(IPAddress addr, uint16_t port);
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
AsyncServer(IPv6Address addr, uint16_t port);
|
|
||||||
#endif
|
|
||||||
AsyncServer(uint16_t port);
|
|
||||||
~AsyncServer();
|
|
||||||
void onClient(AcConnectHandler cb, void * arg);
|
|
||||||
void begin();
|
|
||||||
void end();
|
|
||||||
void setNoDelay(bool nodelay);
|
|
||||||
bool getNoDelay();
|
|
||||||
uint8_t status();
|
|
||||||
|
|
||||||
//Do not use any of the functions below!
|
|
||||||
static int8_t _s_accept(void * arg, tcp_pcb * newpcb, int8_t err);
|
|
||||||
static int8_t _s_accepted(void * arg, AsyncClient * client);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uint16_t _port;
|
|
||||||
bool _bind4 = false;
|
|
||||||
bool _bind6 = false;
|
|
||||||
IPAddress _addr;
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
IPv6Address _addr6;
|
|
||||||
#endif
|
|
||||||
bool _noDelay;
|
|
||||||
tcp_pcb * _pcb;
|
|
||||||
AcConnectHandler _connect_cb;
|
|
||||||
void * _connect_cb_arg;
|
|
||||||
|
|
||||||
int8_t _accept(tcp_pcb * newpcb, int8_t err);
|
|
||||||
int8_t _accepted(AsyncClient * client);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ASYNCTCP_H_ */
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
# ESP Async WebServer
|
|
||||||
|
|
||||||
[](https://opensource.org/license/lgpl-3-0/)
|
|
||||||
[](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
|
|
||||||
[](https://registry.platformio.org/libraries/mathieucarbou/ESP%20Async%20WebServer)
|
|
||||||
|
|
||||||
Async Web Server for ESP31B
|
|
||||||
|
|
||||||
This is using <https://github.com/mathieucarbou/ESPAsyncWebServer>
|
|
||||||
|
|
||||||
This fork is based on <https://github.com/yubox-node-org/ESPAsyncWebServer> and includes all the concurrency fixes.
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
- SPIFFSEditor is removed
|
|
||||||
- Arduino Json 7 compatibility
|
|
||||||
- Deployed in PlatformIO registry and Arduino IDE library manager
|
|
||||||
- CI
|
|
||||||
- Only supports ESP32
|
|
||||||
- Resurrected `AsyncWebSocketMessageBuffer` and `makeBuffer()` in order to make the fork API-compatible with the original library from me-no-dev regarding WebSocket.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Usage and API stays the same as the original library.
|
|
||||||
Please look at the original libraries for more examples and documentation.
|
|
||||||
|
|
||||||
[https://github.com/yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer)
|
|
||||||
|
|
||||||
## `AsyncWebSocketMessageBuffer` and `makeBuffer()`
|
|
||||||
|
|
||||||
The fork from `yubox-node-org` introduces some breaking API changes compared to the original library, especially regarding the use of `std::shared_ptr<std::vector<uint8_t>>` for WebSocket.
|
|
||||||
|
|
||||||
This fork is compatible with the original library from `me-no-dev` regarding WebSocket, and wraps the optimizations done by `yubox-node-org` in the `AsyncWebSocketMessageBuffer` class.
|
|
||||||
So you have the choice of which API to use.
|
|
||||||
I strongly suggest to use the optimized API from `yubox-node-org` as it is much more efficient.
|
|
||||||
|
|
||||||
Here is an example for serializing a Json document in a websocket message buffer. This code is compatible with any forks, but not optimized:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void send(JsonDocument& doc) {
|
|
||||||
const size_t len = measureJson(doc);
|
|
||||||
|
|
||||||
// original API from me-no-dev
|
|
||||||
AsyncWebSocketMessageBuffer* buffer = _ws->makeBuffer(len);
|
|
||||||
assert(buffer); // up to you to keep or remove this
|
|
||||||
serializeJson(doc, buffer->get(), len);
|
|
||||||
_ws->textAll(buffer);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is an example for serializing a Json document in a more optimized way, and compatible with both forks:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void send(JsonDocument& doc) {
|
|
||||||
const size_t len = measureJson(doc);
|
|
||||||
|
|
||||||
#if defined(ASYNCWEBSERVER_FORK_mathieucarbou)
|
|
||||||
|
|
||||||
// this fork (originally from yubox-node-org), uses another API with shared pointer that better support concurrent use cases then the original project
|
|
||||||
auto buffer = std::make_shared<std::vector<uint8_t>>(len);
|
|
||||||
assert(buffer); // up to you to keep or remove this
|
|
||||||
serializeJson(doc, buffer->data(), len);
|
|
||||||
_ws->textAll(std::move(buffer));
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// original API from me-no-dev
|
|
||||||
AsyncWebSocketMessageBuffer* buffer = _ws->makeBuffer(len);
|
|
||||||
assert(buffer); // up to you to keep or remove this
|
|
||||||
serializeJson(doc, buffer->get(), len);
|
|
||||||
_ws->textAll(buffer);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "AsyncEventSource.h"
|
|
||||||
|
|
||||||
static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
|
||||||
String ev = "";
|
|
||||||
|
|
||||||
if(reconnect){
|
|
||||||
ev += "retry: ";
|
|
||||||
ev += String(reconnect);
|
|
||||||
ev += "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id){
|
|
||||||
ev += "id: ";
|
|
||||||
ev += String(id);
|
|
||||||
ev += "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event != NULL){
|
|
||||||
ev += "event: ";
|
|
||||||
ev += String(event);
|
|
||||||
ev += "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message != NULL){
|
|
||||||
size_t messageLen = strlen(message);
|
|
||||||
char * lineStart = (char *)message;
|
|
||||||
char * lineEnd;
|
|
||||||
do {
|
|
||||||
char * nextN = strchr(lineStart, '\n');
|
|
||||||
char * nextR = strchr(lineStart, '\r');
|
|
||||||
if(nextN == NULL && nextR == NULL){
|
|
||||||
size_t llen = ((char *)message + messageLen) - lineStart;
|
|
||||||
char * ldata = (char *)malloc(llen+1);
|
|
||||||
if(ldata != NULL){
|
|
||||||
memcpy(ldata, lineStart, llen);
|
|
||||||
ldata[llen] = 0;
|
|
||||||
ev += "data: ";
|
|
||||||
ev += ldata;
|
|
||||||
ev += "\r\n\r\n";
|
|
||||||
free(ldata);
|
|
||||||
}
|
|
||||||
lineStart = (char *)message + messageLen;
|
|
||||||
} else {
|
|
||||||
char * nextLine = NULL;
|
|
||||||
if(nextN != NULL && nextR != NULL){
|
|
||||||
if(nextR < nextN){
|
|
||||||
lineEnd = nextR;
|
|
||||||
if(nextN == (nextR + 1))
|
|
||||||
nextLine = nextN + 1;
|
|
||||||
else
|
|
||||||
nextLine = nextR + 1;
|
|
||||||
} else {
|
|
||||||
lineEnd = nextN;
|
|
||||||
if(nextR == (nextN + 1))
|
|
||||||
nextLine = nextR + 1;
|
|
||||||
else
|
|
||||||
nextLine = nextN + 1;
|
|
||||||
}
|
|
||||||
} else if(nextN != NULL){
|
|
||||||
lineEnd = nextN;
|
|
||||||
nextLine = nextN + 1;
|
|
||||||
} else {
|
|
||||||
lineEnd = nextR;
|
|
||||||
nextLine = nextR + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t llen = lineEnd - lineStart;
|
|
||||||
char * ldata = (char *)malloc(llen+1);
|
|
||||||
if(ldata != NULL){
|
|
||||||
memcpy(ldata, lineStart, llen);
|
|
||||||
ldata[llen] = 0;
|
|
||||||
ev += "data: ";
|
|
||||||
ev += ldata;
|
|
||||||
ev += "\r\n";
|
|
||||||
free(ldata);
|
|
||||||
}
|
|
||||||
lineStart = nextLine;
|
|
||||||
if(lineStart == ((char *)message + messageLen))
|
|
||||||
ev += "\r\n";
|
|
||||||
}
|
|
||||||
} while(lineStart < ((char *)message + messageLen));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message
|
|
||||||
|
|
||||||
AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len)
|
|
||||||
: _data(nullptr), _len(len), _sent(0), _acked(0)
|
|
||||||
{
|
|
||||||
_data = (uint8_t*)malloc(_len+1);
|
|
||||||
if(_data == nullptr){
|
|
||||||
_len = 0;
|
|
||||||
} else {
|
|
||||||
memcpy(_data, data, len);
|
|
||||||
_data[_len] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncEventSourceMessage::~AsyncEventSourceMessage() {
|
|
||||||
if(_data != NULL)
|
|
||||||
free(_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncEventSourceMessage::ack(size_t len) {
|
|
||||||
// If the whole message is now acked...
|
|
||||||
if(_acked + len > _len){
|
|
||||||
// Return the number of extra bytes acked (they will be carried on to the next message)
|
|
||||||
const size_t extra = _acked + len - _len;
|
|
||||||
_acked = _len;
|
|
||||||
return extra;
|
|
||||||
}
|
|
||||||
// Return that no extra bytes left.
|
|
||||||
_acked += len;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncEventSourceMessage::write_buffer(AsyncClient *client) {
|
|
||||||
if (!client->canSend())
|
|
||||||
return 0;
|
|
||||||
const size_t len = _len - _sent;
|
|
||||||
if(client->space() < len){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t sent = client->add((const char *)_data, len);
|
|
||||||
_sent += sent;
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncEventSourceMessage::send(AsyncClient *client) {
|
|
||||||
size_t sent = write_buffer(client);
|
|
||||||
client->send();
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client
|
|
||||||
|
|
||||||
AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server)
|
|
||||||
: _messageQueue(LinkedList<AsyncEventSourceMessage *>([](AsyncEventSourceMessage *m){ delete m; }))
|
|
||||||
{
|
|
||||||
_client = request->client();
|
|
||||||
_server = server;
|
|
||||||
_lastId = 0;
|
|
||||||
if(request->hasHeader("Last-Event-ID"))
|
|
||||||
_lastId = atoi(request->getHeader("Last-Event-ID")->value().c_str());
|
|
||||||
|
|
||||||
_client->setRxTimeout(0);
|
|
||||||
_client->onError(NULL, NULL);
|
|
||||||
_client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this);
|
|
||||||
_client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this);
|
|
||||||
_client->onData(NULL, NULL);
|
|
||||||
_client->onTimeout([this](void *r, AsyncClient* c __attribute__((unused)), uint32_t time){ ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this);
|
|
||||||
_client->onDisconnect([this](void *r, AsyncClient* c){ ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this);
|
|
||||||
|
|
||||||
_server->_addClient(this);
|
|
||||||
delete request;
|
|
||||||
|
|
||||||
_client->setNoDelay(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncEventSourceClient::~AsyncEventSourceClient(){
|
|
||||||
_messageQueue.free();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage *dataMessage){
|
|
||||||
if(dataMessage == NULL)
|
|
||||||
return;
|
|
||||||
if(!connected()){
|
|
||||||
delete dataMessage;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){
|
|
||||||
ets_printf("AsyncEventSourceClient: ERROR: Queue is full, communications too slow, dropping event");
|
|
||||||
delete dataMessage;
|
|
||||||
} else {
|
|
||||||
_messageQueue.add(dataMessage);
|
|
||||||
}
|
|
||||||
if(_client->canSend())
|
|
||||||
_runQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){
|
|
||||||
_runQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onPoll(){
|
|
||||||
if(!_messageQueue.isEmpty()){
|
|
||||||
_runQueue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){
|
|
||||||
_client->close(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onDisconnect(){
|
|
||||||
_client = NULL;
|
|
||||||
_server->_handleDisconnect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::close(){
|
|
||||||
if(_client != NULL)
|
|
||||||
_client->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::write(const char * message, size_t len){
|
|
||||||
_queueMessage(new AsyncEventSourceMessage(message, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
|
||||||
String ev = generateEventMessage(message, event, id, reconnect);
|
|
||||||
_queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceClient::_runQueue(){
|
|
||||||
#if defined(ESP32)
|
|
||||||
if(!this->_messageQueue_mutex.try_lock()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if(this->_messageQueue_processing){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->_messageQueue_processing = true;
|
|
||||||
#endif // ESP32
|
|
||||||
|
|
||||||
size_t total_bytes_written = 0;
|
|
||||||
for(auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i)
|
|
||||||
{
|
|
||||||
if(!(*i)->sent()) {
|
|
||||||
size_t bytes_written = (*i)->write_buffer(_client);
|
|
||||||
total_bytes_written += bytes_written;
|
|
||||||
if(bytes_written == 0)
|
|
||||||
break;
|
|
||||||
// todo: there is a further optimization to write a partial event to squeeze the last few bytes into the outgoing tcp send buffer, in
|
|
||||||
// fact all of this code is already set up to do so, it's only write_buffer that needs to be updated to allow it instead of
|
|
||||||
// returning zero when the full event won't fit into what's left of the buffer
|
|
||||||
// todo: windows is taking 40-50ms to send an ack back while it waits for more data which won't come since this code must wait for ack first
|
|
||||||
// due to system resource limitations - if the dashboard javascript just sends a single byte back per event received (which this
|
|
||||||
// code would of course throw away as meaningless) then windows (or whatever other host runs the webbrower) will piggyback an ack
|
|
||||||
// onto that outgoing packet for us, reducing roundtrip ack latency and potentially as much as trippling throughput again
|
|
||||||
// (measured: ESP-01: 20ms to send another packet after ack received, windows: 40-50ms to ack after receiving a packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(total_bytes_written > 0)
|
|
||||||
_client->send();
|
|
||||||
|
|
||||||
size_t len = total_bytes_written;
|
|
||||||
while(len && !_messageQueue.isEmpty()){
|
|
||||||
len = _messageQueue.front()->ack(len);
|
|
||||||
if(_messageQueue.front()->finished()){
|
|
||||||
_messageQueue.remove(_messageQueue.front());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ESP32)
|
|
||||||
this->_messageQueue_mutex.unlock();
|
|
||||||
#else
|
|
||||||
this->_messageQueue_processing = false;
|
|
||||||
#endif // ESP32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
|
|
||||||
AsyncEventSource::AsyncEventSource(const String& url)
|
|
||||||
: _url(url)
|
|
||||||
, _clients(LinkedList<AsyncEventSourceClient *>([](AsyncEventSourceClient *c){ delete c; }))
|
|
||||||
, _connectcb(NULL)
|
|
||||||
{}
|
|
||||||
|
|
||||||
AsyncEventSource::~AsyncEventSource(){
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::onConnect(ArEventHandlerFunction cb){
|
|
||||||
_connectcb = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::_addClient(AsyncEventSourceClient * client){
|
|
||||||
/*char * temp = (char *)malloc(2054);
|
|
||||||
if(temp != NULL){
|
|
||||||
memset(temp+1,' ',2048);
|
|
||||||
temp[0] = ':';
|
|
||||||
temp[2049] = '\r';
|
|
||||||
temp[2050] = '\n';
|
|
||||||
temp[2051] = '\r';
|
|
||||||
temp[2052] = '\n';
|
|
||||||
temp[2053] = 0;
|
|
||||||
client->write((const char *)temp, 2053);
|
|
||||||
free(temp);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
_clients.add(client);
|
|
||||||
if(_connectcb)
|
|
||||||
_connectcb(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){
|
|
||||||
_clients.remove(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::close(){
|
|
||||||
for(const auto &c: _clients){
|
|
||||||
if(c->connected())
|
|
||||||
c->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pmb fix
|
|
||||||
size_t AsyncEventSource::avgPacketsWaiting() const {
|
|
||||||
if(_clients.isEmpty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size_t aql=0;
|
|
||||||
uint32_t nConnectedClients=0;
|
|
||||||
|
|
||||||
for(const auto &c: _clients){
|
|
||||||
if(c->connected()) {
|
|
||||||
aql+=c->packetsWaiting();
|
|
||||||
++nConnectedClients;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return aql / nConnectedClients;
|
|
||||||
return ((aql) + (nConnectedClients/2))/(nConnectedClients); // round up
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
|
||||||
|
|
||||||
|
|
||||||
String ev = generateEventMessage(message, event, id, reconnect);
|
|
||||||
for(const auto &c: _clients){
|
|
||||||
if(c->connected()) {
|
|
||||||
c->write(ev.c_str(), ev.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncEventSource::count() const {
|
|
||||||
return _clients.count_if([](AsyncEventSourceClient *c){
|
|
||||||
return c->connected();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){
|
|
||||||
if(request->method() != HTTP_GET || !request->url().equals(_url)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
request->addInterestingHeader("Last-Event-ID");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){
|
|
||||||
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
request->send(new AsyncEventSourceResponse(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response
|
|
||||||
|
|
||||||
AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){
|
|
||||||
_server = server;
|
|
||||||
_code = 200;
|
|
||||||
_contentType = "text/event-stream";
|
|
||||||
_sendContentLength = false;
|
|
||||||
addHeader("Cache-Control", "no-cache");
|
|
||||||
addHeader("Connection","keep-alive");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSourceResponse::_respond(AsyncWebServerRequest *request){
|
|
||||||
String out = _assembleHead(request->version());
|
|
||||||
request->client()->write(out.c_str(), _headLength);
|
|
||||||
_state = RESPONSE_WAIT_ACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time __attribute__((unused))){
|
|
||||||
if(len){
|
|
||||||
new AsyncEventSourceClient(request, _server);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef ASYNCEVENTSOURCE_H_
|
|
||||||
#define ASYNCEVENTSOURCE_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
#if defined(ESP32) || defined(LIBRETINY)
|
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#else
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ESP32)
|
|
||||||
#include <mutex>
|
|
||||||
#endif // ESP32
|
|
||||||
|
|
||||||
#ifndef SSE_MAX_QUEUED_MESSAGES
|
|
||||||
#define SSE_MAX_QUEUED_MESSAGES 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
|
|
||||||
#include "AsyncWebSynchronization.h"
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#include <Hash.h>
|
|
||||||
#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
|
|
||||||
#include <../src/Hash.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ESP32) || defined(LIBRETINY)
|
|
||||||
#define DEFAULT_MAX_SSE_CLIENTS 8
|
|
||||||
#else
|
|
||||||
#define DEFAULT_MAX_SSE_CLIENTS 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncEventSource;
|
|
||||||
class AsyncEventSourceResponse;
|
|
||||||
class AsyncEventSourceClient;
|
|
||||||
typedef std::function<void(AsyncEventSourceClient *client)> ArEventHandlerFunction;
|
|
||||||
|
|
||||||
class AsyncEventSourceMessage {
|
|
||||||
private:
|
|
||||||
uint8_t * _data;
|
|
||||||
size_t _len;
|
|
||||||
size_t _sent;
|
|
||||||
//size_t _ack;
|
|
||||||
size_t _acked;
|
|
||||||
public:
|
|
||||||
AsyncEventSourceMessage(const char * data, size_t len);
|
|
||||||
~AsyncEventSourceMessage();
|
|
||||||
size_t ack(size_t len);
|
|
||||||
size_t write_buffer(AsyncClient *client);
|
|
||||||
size_t send(AsyncClient *client);
|
|
||||||
bool finished(){ return _acked == _len; }
|
|
||||||
bool sent() { return _sent == _len; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncEventSourceClient {
|
|
||||||
private:
|
|
||||||
AsyncClient *_client;
|
|
||||||
AsyncEventSource *_server;
|
|
||||||
uint32_t _lastId;
|
|
||||||
#if defined(ESP32)
|
|
||||||
std::mutex _messageQueue_mutex;
|
|
||||||
#else
|
|
||||||
bool _messageQueue_processing{false};
|
|
||||||
#endif // ESP32
|
|
||||||
LinkedList<AsyncEventSourceMessage *> _messageQueue;
|
|
||||||
void _queueMessage(AsyncEventSourceMessage *dataMessage);
|
|
||||||
void _runQueue();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server);
|
|
||||||
~AsyncEventSourceClient();
|
|
||||||
|
|
||||||
AsyncClient* client(){ return _client; }
|
|
||||||
void close();
|
|
||||||
void write(const char * message, size_t len);
|
|
||||||
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
|
|
||||||
bool connected() const { return (_client != NULL) && _client->connected(); }
|
|
||||||
uint32_t lastId() const { return _lastId; }
|
|
||||||
size_t packetsWaiting() const { return _messageQueue.length(); }
|
|
||||||
|
|
||||||
//system callbacks (do not call)
|
|
||||||
void _onAck(size_t len, uint32_t time);
|
|
||||||
void _onPoll();
|
|
||||||
void _onTimeout(uint32_t time);
|
|
||||||
void _onDisconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncEventSource: public AsyncWebHandler {
|
|
||||||
private:
|
|
||||||
String _url;
|
|
||||||
LinkedList<AsyncEventSourceClient *> _clients;
|
|
||||||
ArEventHandlerFunction _connectcb;
|
|
||||||
public:
|
|
||||||
AsyncEventSource(const String& url);
|
|
||||||
~AsyncEventSource();
|
|
||||||
|
|
||||||
const char * url() const { return _url.c_str(); }
|
|
||||||
void close();
|
|
||||||
void onConnect(ArEventHandlerFunction cb);
|
|
||||||
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
|
|
||||||
size_t count() const; //number clinets connected
|
|
||||||
size_t avgPacketsWaiting() const;
|
|
||||||
|
|
||||||
//system callbacks (do not call)
|
|
||||||
void _addClient(AsyncEventSourceClient * client);
|
|
||||||
void _handleDisconnect(AsyncEventSourceClient * client);
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncEventSourceResponse: public AsyncWebServerResponse {
|
|
||||||
private:
|
|
||||||
String _content;
|
|
||||||
AsyncEventSource *_server;
|
|
||||||
public:
|
|
||||||
AsyncEventSourceResponse(AsyncEventSource *server);
|
|
||||||
void _respond(AsyncWebServerRequest *request);
|
|
||||||
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
|
||||||
bool _sourceValid() const { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ASYNCEVENTSOURCE_H_ */
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
// AsyncJson.h
|
|
||||||
|
|
||||||
#ifndef ASYNC_JSON_H_
|
|
||||||
#define ASYNC_JSON_H_
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
#include <Print.h>
|
|
||||||
|
|
||||||
constexpr const char * JSON_MIMETYPE = "application/json";
|
|
||||||
constexpr const char * MSGPACK_MIMETYPE = "application/msgpack";
|
|
||||||
|
|
||||||
class ChunkPrint : public Print {
|
|
||||||
private:
|
|
||||||
uint8_t * _destination;
|
|
||||||
size_t _to_skip;
|
|
||||||
size_t _to_write;
|
|
||||||
size_t _pos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ChunkPrint(uint8_t * destination, size_t from, size_t len)
|
|
||||||
: _destination(destination)
|
|
||||||
, _to_skip(from)
|
|
||||||
, _to_write(len)
|
|
||||||
, _pos{0} {
|
|
||||||
}
|
|
||||||
virtual ~ChunkPrint() {
|
|
||||||
}
|
|
||||||
size_t write(uint8_t c) {
|
|
||||||
if (_to_skip > 0) {
|
|
||||||
_to_skip--;
|
|
||||||
return 1;
|
|
||||||
} else if (_to_write > 0) {
|
|
||||||
_to_write--;
|
|
||||||
_destination[_pos++] = c;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t write(const uint8_t * buffer, size_t size) {
|
|
||||||
return this->Print::write(buffer, size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// added msgPack by proddy for EMS-ESP
|
|
||||||
class AsyncJsonResponse : public AsyncAbstractResponse {
|
|
||||||
protected:
|
|
||||||
JsonDocument _jsonBuffer;
|
|
||||||
JsonVariant _root;
|
|
||||||
bool _isValid;
|
|
||||||
bool _isMsgPack;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncJsonResponse(bool isArray = false, bool isMsgPack = false)
|
|
||||||
: _isValid{false}
|
|
||||||
, _isMsgPack{isMsgPack} {
|
|
||||||
_code = 200;
|
|
||||||
_contentType = (isMsgPack) ? MSGPACK_MIMETYPE : JSON_MIMETYPE;
|
|
||||||
if (isArray)
|
|
||||||
_root = _jsonBuffer.add<JsonArray>();
|
|
||||||
else
|
|
||||||
_root = _jsonBuffer.add<JsonObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncJsonResponse() {
|
|
||||||
}
|
|
||||||
JsonVariant getRoot() {
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return _isValid;
|
|
||||||
}
|
|
||||||
size_t setLength() {
|
|
||||||
_contentLength = _isMsgPack ? measureMsgPack(_root) : measureJson(_root);
|
|
||||||
|
|
||||||
if (_contentLength) {
|
|
||||||
_isValid = true;
|
|
||||||
}
|
|
||||||
return _contentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getSize() {
|
|
||||||
return _jsonBuffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t _fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
ChunkPrint dest(data, _sentLength, len);
|
|
||||||
_isMsgPack ? serializeMsgPack(_root, dest) : serializeJson(_root, dest);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// class PrettyAsyncJsonResponse : public AsyncJsonResponse {
|
|
||||||
// public:
|
|
||||||
// PrettyAsyncJsonResponse(bool isArray = false)
|
|
||||||
// : AsyncJsonResponse{isArray} {
|
|
||||||
// }
|
|
||||||
// size_t setLength() {
|
|
||||||
// _contentLength = measureJsonPretty(_root);
|
|
||||||
// if (_contentLength) {
|
|
||||||
// _isValid = true;
|
|
||||||
// }
|
|
||||||
// return _contentLength;
|
|
||||||
// }
|
|
||||||
// size_t _fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
// ChunkPrint dest(data, _sentLength, len);
|
|
||||||
// serializeJsonPretty(_root, dest);
|
|
||||||
// return len;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction;
|
|
||||||
|
|
||||||
class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
|
|
||||||
private:
|
|
||||||
protected:
|
|
||||||
const String _uri;
|
|
||||||
WebRequestMethodComposite _method;
|
|
||||||
ArJsonRequestHandlerFunction _onRequest;
|
|
||||||
size_t _contentLength;
|
|
||||||
size_t _maxContentLength;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest)
|
|
||||||
: _uri(uri)
|
|
||||||
, _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH)
|
|
||||||
, _onRequest(onRequest)
|
|
||||||
, _maxContentLength(16384) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMethod(WebRequestMethodComposite method) {
|
|
||||||
_method = method;
|
|
||||||
}
|
|
||||||
void setMaxContentLength(int maxContentLength) {
|
|
||||||
_maxContentLength = maxContentLength;
|
|
||||||
}
|
|
||||||
void onRequest(ArJsonRequestHandlerFunction fn) {
|
|
||||||
_onRequest = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest * request) override final {
|
|
||||||
if (!_onRequest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
WebRequestMethodComposite request_method = request->method();
|
|
||||||
|
|
||||||
if (!(_method & request_method))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
request->addInterestingHeader("ANY");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest * request) override final {
|
|
||||||
if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if (_onRequest) {
|
|
||||||
if (request->method() == HTTP_GET) {
|
|
||||||
JsonVariant json;
|
|
||||||
_onRequest(request, json);
|
|
||||||
return;
|
|
||||||
} else if (request->_tempObject != NULL) {
|
|
||||||
JsonDocument jsonBuffer;
|
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
|
|
||||||
if (!error) {
|
|
||||||
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
|
||||||
_onRequest(request, json);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request->send(_contentLength > _maxContentLength ? 413 : 400);
|
|
||||||
} else {
|
|
||||||
request->send(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) override final {
|
|
||||||
}
|
|
||||||
virtual void handleBody(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total) override final {
|
|
||||||
if (_onRequest) {
|
|
||||||
_contentLength = total;
|
|
||||||
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
|
|
||||||
request->_tempObject = malloc(total);
|
|
||||||
}
|
|
||||||
if (request->_tempObject != NULL) {
|
|
||||||
memcpy((uint8_t *)(request->_tempObject) + index, data, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual bool isRequestHandlerTrivial() override final {
|
|
||||||
return _onRequest ? false : true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,398 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef ASYNCWEBSOCKET_H_
|
|
||||||
#define ASYNCWEBSOCKET_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#ifndef WS_MAX_QUEUED_MESSAGES
|
|
||||||
#define WS_MAX_QUEUED_MESSAGES 32
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#ifndef WS_MAX_QUEUED_MESSAGES
|
|
||||||
#define WS_MAX_QUEUED_MESSAGES 8
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
|
|
||||||
#include "AsyncWebSynchronization.h"
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <deque>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#include <Hash.h>
|
|
||||||
#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
|
|
||||||
#include <../src/Hash.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#define DEFAULT_MAX_WS_CLIENTS 8
|
|
||||||
#else
|
|
||||||
#define DEFAULT_MAX_WS_CLIENTS 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncWebSocket;
|
|
||||||
class AsyncWebSocketResponse;
|
|
||||||
class AsyncWebSocketClient;
|
|
||||||
class AsyncWebSocketControl;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/** Message type as defined by enum AwsFrameType.
|
|
||||||
* Note: Applications will only see WS_TEXT and WS_BINARY.
|
|
||||||
* All other types are handled by the library. */
|
|
||||||
uint8_t message_opcode;
|
|
||||||
/** Frame number of a fragmented message. */
|
|
||||||
uint32_t num;
|
|
||||||
/** Is this the last frame in a fragmented message ?*/
|
|
||||||
uint8_t final;
|
|
||||||
/** Is this frame masked? */
|
|
||||||
uint8_t masked;
|
|
||||||
/** Message type as defined by enum AwsFrameType.
|
|
||||||
* This value is the same as message_opcode for non-fragmented
|
|
||||||
* messages, but may also be WS_CONTINUATION in a fragmented message. */
|
|
||||||
uint8_t opcode;
|
|
||||||
/** Length of the current frame.
|
|
||||||
* This equals the total length of the message if num == 0 && final == true */
|
|
||||||
uint64_t len;
|
|
||||||
/** Mask key */
|
|
||||||
uint8_t mask[4];
|
|
||||||
/** Offset of the data inside the current frame. */
|
|
||||||
uint64_t index;
|
|
||||||
} AwsFrameInfo;
|
|
||||||
|
|
||||||
typedef enum { WS_DISCONNECTED, WS_CONNECTED, WS_DISCONNECTING } AwsClientStatus;
|
|
||||||
typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PING, WS_PONG } AwsFrameType;
|
|
||||||
typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus;
|
|
||||||
typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType;
|
|
||||||
|
|
||||||
class AsyncWebSocketMessageBuffer {
|
|
||||||
friend AsyncWebSocket;
|
|
||||||
friend AsyncWebSocketClient;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<std::vector<uint8_t>> _buffer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebSocketMessageBuffer();
|
|
||||||
AsyncWebSocketMessageBuffer(size_t size);
|
|
||||||
AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
|
|
||||||
~AsyncWebSocketMessageBuffer();
|
|
||||||
bool reserve(size_t size);
|
|
||||||
uint8_t * get() {
|
|
||||||
return _buffer->data();
|
|
||||||
}
|
|
||||||
size_t length() const {
|
|
||||||
return _buffer->size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncWebSocketMessage {
|
|
||||||
private:
|
|
||||||
std::shared_ptr<std::vector<uint8_t>> _WSbuffer;
|
|
||||||
uint8_t _opcode{WS_TEXT};
|
|
||||||
bool _mask{false};
|
|
||||||
AwsMessageStatus _status{WS_MSG_ERROR};
|
|
||||||
size_t _sent{};
|
|
||||||
size_t _ack{};
|
|
||||||
size_t _acked{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebSocketMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
|
||||||
|
|
||||||
bool finished() const {
|
|
||||||
return _status != WS_MSG_SENDING;
|
|
||||||
}
|
|
||||||
bool betweenFrames() const {
|
|
||||||
return _acked == _ack;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ack(size_t len, uint32_t time);
|
|
||||||
size_t send(AsyncClient * client);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncWebSocketClient {
|
|
||||||
private:
|
|
||||||
AsyncClient * _client;
|
|
||||||
AsyncWebSocket * _server;
|
|
||||||
uint32_t _clientId;
|
|
||||||
AwsClientStatus _status;
|
|
||||||
|
|
||||||
AsyncWebLock _lock;
|
|
||||||
|
|
||||||
std::deque<AsyncWebSocketControl> _controlQueue;
|
|
||||||
std::deque<AsyncWebSocketMessage> _messageQueue;
|
|
||||||
bool closeWhenFull = true;
|
|
||||||
|
|
||||||
uint8_t _pstate;
|
|
||||||
AwsFrameInfo _pinfo;
|
|
||||||
|
|
||||||
uint32_t _lastMessageTime;
|
|
||||||
uint32_t _keepAlivePeriod;
|
|
||||||
|
|
||||||
void _queueControl(uint8_t opcode, const uint8_t * data = NULL, size_t len = 0, bool mask = false);
|
|
||||||
void _queueMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
|
||||||
void _runQueue();
|
|
||||||
void _clearQueue();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void * _tempObject;
|
|
||||||
|
|
||||||
AsyncWebSocketClient(AsyncWebServerRequest * request, AsyncWebSocket * server);
|
|
||||||
~AsyncWebSocketClient();
|
|
||||||
|
|
||||||
//client id increments for the given server
|
|
||||||
uint32_t id() const {
|
|
||||||
return _clientId;
|
|
||||||
}
|
|
||||||
AwsClientStatus status() const {
|
|
||||||
return _status;
|
|
||||||
}
|
|
||||||
AsyncClient * client() {
|
|
||||||
return _client;
|
|
||||||
}
|
|
||||||
const AsyncClient * client() const {
|
|
||||||
return _client;
|
|
||||||
}
|
|
||||||
AsyncWebSocket * server() {
|
|
||||||
return _server;
|
|
||||||
}
|
|
||||||
const AsyncWebSocket * server() const {
|
|
||||||
return _server;
|
|
||||||
}
|
|
||||||
AwsFrameInfo const & pinfo() const {
|
|
||||||
return _pinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - If "true" (default), the connection will be closed if the message queue is full.
|
|
||||||
// This is the default behavior in yubox-node-org, which is not silently discarding messages but instead closes the connection.
|
|
||||||
// The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again,
|
|
||||||
// and so on, causing a resource exhaustion.
|
|
||||||
//
|
|
||||||
// - If "false", the incoming message will be discarded if the queue is full.
|
|
||||||
// This is the default behavior in the original ESPAsyncWebServer library from me-no-dev.
|
|
||||||
// This behavior allows the best performance at the expense of unreliable message delivery in case the queue is full (some messages may be lost).
|
|
||||||
//
|
|
||||||
// - In any case, when the queue is full, a message is logged.
|
|
||||||
// - IT is recommended to use the methods queueIsFull(), availableForWriteAll(), availableForWrite(clientId) to check if the queue is full before sending a message.
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
// - can be set in the onEvent listener when connecting (event type is: WS_EVT_CONNECT)
|
|
||||||
//
|
|
||||||
// Use cases:,
|
|
||||||
// - if using websocket to send logging messages, maybe some loss is acceptable.
|
|
||||||
// - But if using websocket to send UI update messages, maybe the connection should be closed and the UI redrawn.
|
|
||||||
void setCloseClientOnQueueFull(bool close) {
|
|
||||||
closeWhenFull = close;
|
|
||||||
}
|
|
||||||
bool willCloseClientOnQueueFull() const {
|
|
||||||
return closeWhenFull;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress remoteIP() const;
|
|
||||||
uint16_t remotePort() const;
|
|
||||||
|
|
||||||
bool shouldBeDeleted() const {
|
|
||||||
return !_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
//control frames
|
|
||||||
void close(uint16_t code = 0, const char * message = NULL);
|
|
||||||
void ping(const uint8_t * data = NULL, size_t len = 0);
|
|
||||||
|
|
||||||
//set auto-ping period in seconds. disabled if zero (default)
|
|
||||||
void keepAlivePeriod(uint16_t seconds) {
|
|
||||||
_keepAlivePeriod = seconds * 1000;
|
|
||||||
}
|
|
||||||
uint16_t keepAlivePeriod() {
|
|
||||||
return (uint16_t)(_keepAlivePeriod / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
//data packets
|
|
||||||
void message(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false) {
|
|
||||||
_queueMessage(buffer, opcode, mask);
|
|
||||||
}
|
|
||||||
bool queueIsFull() const;
|
|
||||||
size_t queueLen() const;
|
|
||||||
|
|
||||||
size_t printf(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
#ifndef ESP32
|
|
||||||
size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void text(std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
void text(const uint8_t * message, size_t len);
|
|
||||||
void text(const char * message, size_t len);
|
|
||||||
void text(const char * message);
|
|
||||||
void text(const String & message);
|
|
||||||
void text(const __FlashStringHelper * message);
|
|
||||||
void text(AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
|
|
||||||
void binary(std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
void binary(const uint8_t * message, size_t len);
|
|
||||||
void binary(const char * message, size_t len);
|
|
||||||
void binary(const char * message);
|
|
||||||
void binary(const String & message);
|
|
||||||
void binary(const __FlashStringHelper * message, size_t len);
|
|
||||||
void binary(AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
|
|
||||||
bool canSend() const;
|
|
||||||
|
|
||||||
//system callbacks (do not call)
|
|
||||||
void _onAck(size_t len, uint32_t time);
|
|
||||||
void _onError(int8_t);
|
|
||||||
void _onPoll();
|
|
||||||
void _onTimeout(uint32_t time);
|
|
||||||
void _onDisconnect();
|
|
||||||
void _onData(void * pbuf, size_t plen);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::function<bool(AsyncWebServerRequest * request)> AwsHandshakeHandler;
|
|
||||||
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len)> AwsEventHandler;
|
|
||||||
|
|
||||||
//WebServer Handler implementation that plays the role of a socket server
|
|
||||||
class AsyncWebSocket : public AsyncWebHandler {
|
|
||||||
private:
|
|
||||||
String _url;
|
|
||||||
std::list<AsyncWebSocketClient> _clients;
|
|
||||||
uint32_t _cNextId;
|
|
||||||
AwsEventHandler _eventHandler;
|
|
||||||
AwsHandshakeHandler _handshakeHandler;
|
|
||||||
bool _enabled;
|
|
||||||
AsyncWebLock _lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebSocket(const String & url);
|
|
||||||
~AsyncWebSocket();
|
|
||||||
const char * url() const {
|
|
||||||
return _url.c_str();
|
|
||||||
}
|
|
||||||
void enable(bool e) {
|
|
||||||
_enabled = e;
|
|
||||||
}
|
|
||||||
bool enabled() const {
|
|
||||||
return _enabled;
|
|
||||||
}
|
|
||||||
bool availableForWriteAll();
|
|
||||||
bool availableForWrite(uint32_t id);
|
|
||||||
|
|
||||||
size_t count() const;
|
|
||||||
AsyncWebSocketClient * client(uint32_t id);
|
|
||||||
bool hasClient(uint32_t id) {
|
|
||||||
return client(id) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close(uint32_t id, uint16_t code = 0, const char * message = NULL);
|
|
||||||
void closeAll(uint16_t code = 0, const char * message = NULL);
|
|
||||||
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
|
|
||||||
|
|
||||||
void ping(uint32_t id, const uint8_t * data = NULL, size_t len = 0);
|
|
||||||
void pingAll(const uint8_t * data = NULL, size_t len = 0); // done
|
|
||||||
|
|
||||||
void text(uint32_t id, const uint8_t * message, size_t len);
|
|
||||||
void text(uint32_t id, const char * message, size_t len);
|
|
||||||
void text(uint32_t id, const char * message);
|
|
||||||
void text(uint32_t id, const String & message);
|
|
||||||
void text(uint32_t id, const __FlashStringHelper * message);
|
|
||||||
void text(uint32_t id, AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
void text(uint32_t id, std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
|
|
||||||
void textAll(const uint8_t * message, size_t len);
|
|
||||||
void textAll(const char * message, size_t len);
|
|
||||||
void textAll(const char * message);
|
|
||||||
void textAll(const String & message);
|
|
||||||
void textAll(const __FlashStringHelper * message);
|
|
||||||
void textAll(AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
void textAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
|
|
||||||
void binary(uint32_t id, const uint8_t * message, size_t len);
|
|
||||||
void binary(uint32_t id, const char * message, size_t len);
|
|
||||||
void binary(uint32_t id, const char * message);
|
|
||||||
void binary(uint32_t id, const String & message);
|
|
||||||
void binary(uint32_t id, const __FlashStringHelper * message, size_t len);
|
|
||||||
void binary(uint32_t id, AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
void binary(uint32_t id, std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
|
|
||||||
void binaryAll(const uint8_t * message, size_t len);
|
|
||||||
void binaryAll(const char * message, size_t len);
|
|
||||||
void binaryAll(const char * message);
|
|
||||||
void binaryAll(const String & message);
|
|
||||||
void binaryAll(const __FlashStringHelper * message, size_t len);
|
|
||||||
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
|
|
||||||
void binaryAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
|
|
||||||
size_t printf(uint32_t id, const char * format, ...) __attribute__((format(printf, 3, 4)));
|
|
||||||
size_t printfAll(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
#ifndef ESP32
|
|
||||||
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__((format(printf, 3, 4)));
|
|
||||||
#endif
|
|
||||||
size_t printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
|
|
||||||
//event listener
|
|
||||||
void onEvent(AwsEventHandler handler) {
|
|
||||||
_eventHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handshake Handler
|
|
||||||
void handleHandshake(AwsHandshakeHandler handler) {
|
|
||||||
_handshakeHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
//system callbacks (do not call)
|
|
||||||
uint32_t _getNextId() {
|
|
||||||
return _cNextId++;
|
|
||||||
}
|
|
||||||
AsyncWebSocketClient * _newClient(AsyncWebServerRequest * request);
|
|
||||||
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len);
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest * request) override final;
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest * request) override final;
|
|
||||||
|
|
||||||
|
|
||||||
// messagebuffer functions/objects.
|
|
||||||
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
|
|
||||||
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);
|
|
||||||
|
|
||||||
const std::list<AsyncWebSocketClient> & getClients() const {
|
|
||||||
return _clients;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//WebServer response to authenticate the socket and detach the tcp client from the web server request
|
|
||||||
class AsyncWebSocketResponse : public AsyncWebServerResponse {
|
|
||||||
private:
|
|
||||||
String _content;
|
|
||||||
AsyncWebSocket * _server;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebSocketResponse(const String & key, AsyncWebSocket * server);
|
|
||||||
void _respond(AsyncWebServerRequest * request);
|
|
||||||
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ASYNCWEBSOCKET_H_ */
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
#ifndef ASYNCWEBSYNCHRONIZATION_H_
|
|
||||||
#define ASYNCWEBSYNCHRONIZATION_H_
|
|
||||||
|
|
||||||
// Synchronisation is only available on ESP32, as the ESP8266 isn't using FreeRTOS by default
|
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
|
|
||||||
// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore
|
|
||||||
// Modified 'AsyncWebLock' to just only use mutex since pxCurrentTCB is not
|
|
||||||
// always available. According to example by Arjan Filius, changed name,
|
|
||||||
// added unimplemented version for ESP8266
|
|
||||||
class AsyncPlainLock
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
SemaphoreHandle_t _lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncPlainLock() {
|
|
||||||
_lock = xSemaphoreCreateBinary();
|
|
||||||
// In this fails, the system is likely that much out of memory that
|
|
||||||
// we should abort anyways. If assertions are disabled, nothing is lost..
|
|
||||||
assert(_lock);
|
|
||||||
xSemaphoreGive(_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncPlainLock() {
|
|
||||||
vSemaphoreDelete(_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lock() const {
|
|
||||||
xSemaphoreTake(_lock, portMAX_DELAY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const {
|
|
||||||
xSemaphoreGive(_lock);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore
|
|
||||||
class AsyncWebLock
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
SemaphoreHandle_t _lock;
|
|
||||||
mutable TaskHandle_t _lockedBy{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebLock()
|
|
||||||
{
|
|
||||||
_lock = xSemaphoreCreateBinary();
|
|
||||||
// In this fails, the system is likely that much out of memory that
|
|
||||||
// we should abort anyways. If assertions are disabled, nothing is lost..
|
|
||||||
assert(_lock);
|
|
||||||
_lockedBy = NULL;
|
|
||||||
xSemaphoreGive(_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncWebLock() {
|
|
||||||
vSemaphoreDelete(_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lock() const {
|
|
||||||
const auto currentTask = xTaskGetCurrentTaskHandle();
|
|
||||||
if (_lockedBy != currentTask) {
|
|
||||||
xSemaphoreTake(_lock, portMAX_DELAY);
|
|
||||||
_lockedBy = currentTask;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const {
|
|
||||||
_lockedBy = NULL;
|
|
||||||
xSemaphoreGive(_lock);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// This is the 8266 version of the Sync Lock which is currently unimplemented
|
|
||||||
class AsyncWebLock
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebLock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncWebLock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lock() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Same for AsyncPlainLock, for ESP8266 this is just the unimplemented version above.
|
|
||||||
using AsyncPlainLock = AsyncWebLock;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncWebLockGuard
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const AsyncWebLock *_lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebLockGuard(const AsyncWebLock &l) {
|
|
||||||
if (l.lock()) {
|
|
||||||
_lock = &l;
|
|
||||||
} else {
|
|
||||||
_lock = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncWebLockGuard() {
|
|
||||||
if (_lock) {
|
|
||||||
_lock->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() {
|
|
||||||
if (_lock) {
|
|
||||||
_lock->unlock();
|
|
||||||
_lock = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ASYNCWEBSYNCHRONIZATION_H_
|
|
||||||
@@ -1,616 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef _ESPAsyncWebServer_H_
|
|
||||||
#define _ESPAsyncWebServer_H_
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
|
||||||
#include "FS.h"
|
|
||||||
|
|
||||||
#include <ArduinoJson.h> // added by proddy for EMS-ESP
|
|
||||||
|
|
||||||
#include "StringArray.h"
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#else
|
|
||||||
#error Platform not supported
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ASYNCWEBSERVER_VERSION "2.6.1"
|
|
||||||
#define ASYNCWEBSERVER_VERSION_MAJOR 2
|
|
||||||
#define ASYNCWEBSERVER_VERSION_MINOR 6
|
|
||||||
#define ASYNCWEBSERVER_VERSION_REVISION 1
|
|
||||||
#define ASYNCWEBSERVER_FORK_mathieucarbou
|
|
||||||
|
|
||||||
#ifdef ASYNCWEBSERVER_REGEX
|
|
||||||
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE
|
|
||||||
#else
|
|
||||||
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncWebServer;
|
|
||||||
class AsyncWebServerRequest;
|
|
||||||
class AsyncWebServerResponse;
|
|
||||||
class AsyncWebHeader;
|
|
||||||
class AsyncWebParameter;
|
|
||||||
class AsyncWebRewrite;
|
|
||||||
class AsyncWebHandler;
|
|
||||||
class AsyncStaticWebHandler;
|
|
||||||
class AsyncCallbackWebHandler;
|
|
||||||
class AsyncResponseStream;
|
|
||||||
|
|
||||||
#ifndef WEBSERVER_H
|
|
||||||
typedef enum {
|
|
||||||
HTTP_GET = 0b00000001,
|
|
||||||
HTTP_POST = 0b00000010,
|
|
||||||
HTTP_DELETE = 0b00000100,
|
|
||||||
HTTP_PUT = 0b00001000,
|
|
||||||
HTTP_PATCH = 0b00010000,
|
|
||||||
HTTP_HEAD = 0b00100000,
|
|
||||||
HTTP_OPTIONS = 0b01000000,
|
|
||||||
HTTP_ANY = 0b01111111,
|
|
||||||
} WebRequestMethod;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_FS_FILE_OPEN_MODE
|
|
||||||
namespace fs {
|
|
||||||
class FileOpenMode {
|
|
||||||
public:
|
|
||||||
static const char * read;
|
|
||||||
static const char * write;
|
|
||||||
static const char * append;
|
|
||||||
};
|
|
||||||
}; // namespace fs
|
|
||||||
#else
|
|
||||||
#include "FileOpenMode.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//if this value is returned when asked for data, packet will not be sent and you will be asked for data again
|
|
||||||
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
|
|
||||||
|
|
||||||
typedef uint8_t WebRequestMethodComposite;
|
|
||||||
typedef std::function<void(void)> ArDisconnectHandler;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PARAMETER :: Chainable object to hold GET/POST and FILE parameters
|
|
||||||
* */
|
|
||||||
|
|
||||||
class AsyncWebParameter {
|
|
||||||
private:
|
|
||||||
String _name;
|
|
||||||
String _value;
|
|
||||||
size_t _size;
|
|
||||||
bool _isForm;
|
|
||||||
bool _isFile;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebParameter(const String & name, const String & value, bool form = false, bool file = false, size_t size = 0)
|
|
||||||
: _name(name)
|
|
||||||
, _value(value)
|
|
||||||
, _size(size)
|
|
||||||
, _isForm(form)
|
|
||||||
, _isFile(file) {
|
|
||||||
}
|
|
||||||
const String & name() const {
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
const String & value() const {
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
size_t size() const {
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
bool isPost() const {
|
|
||||||
return _isForm;
|
|
||||||
}
|
|
||||||
bool isFile() const {
|
|
||||||
return _isFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* HEADER :: Chainable object to hold the headers
|
|
||||||
* */
|
|
||||||
|
|
||||||
class AsyncWebHeader {
|
|
||||||
private:
|
|
||||||
String _name;
|
|
||||||
String _value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebHeader() = default;
|
|
||||||
AsyncWebHeader(const AsyncWebHeader &) = default;
|
|
||||||
|
|
||||||
AsyncWebHeader(const String & name, const String & value)
|
|
||||||
: _name(name)
|
|
||||||
, _value(value) {
|
|
||||||
}
|
|
||||||
AsyncWebHeader(const String & data)
|
|
||||||
: _name()
|
|
||||||
, _value() {
|
|
||||||
if (!data)
|
|
||||||
return;
|
|
||||||
int index = data.indexOf(':');
|
|
||||||
if (index < 0)
|
|
||||||
return;
|
|
||||||
_name = data.substring(0, index);
|
|
||||||
_value = data.substring(index + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebHeader & operator=(const AsyncWebHeader &) = default;
|
|
||||||
|
|
||||||
const String & name() const {
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
const String & value() const {
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
String toString() const {
|
|
||||||
return _name + F(": ") + _value + F("\r\n");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
|
|
||||||
* */
|
|
||||||
|
|
||||||
typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType;
|
|
||||||
|
|
||||||
typedef std::function<size_t(uint8_t *, size_t, size_t)> AwsResponseFiller;
|
|
||||||
typedef std::function<String(const String &)> AwsTemplateProcessor;
|
|
||||||
|
|
||||||
class AsyncWebServerRequest {
|
|
||||||
using File = fs::File;
|
|
||||||
using FS = fs::FS;
|
|
||||||
friend class AsyncWebServer;
|
|
||||||
friend class AsyncCallbackWebHandler;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AsyncClient * _client;
|
|
||||||
AsyncWebServer * _server;
|
|
||||||
AsyncWebHandler * _handler;
|
|
||||||
AsyncWebServerResponse * _response;
|
|
||||||
std::vector<String> _interestingHeaders;
|
|
||||||
ArDisconnectHandler _onDisconnectfn;
|
|
||||||
|
|
||||||
String _temp;
|
|
||||||
uint8_t _parseState;
|
|
||||||
|
|
||||||
uint8_t _version;
|
|
||||||
WebRequestMethodComposite _method;
|
|
||||||
String _url;
|
|
||||||
String _host;
|
|
||||||
String _contentType;
|
|
||||||
String _boundary;
|
|
||||||
String _authorization;
|
|
||||||
RequestedConnectionType _reqconntype;
|
|
||||||
void _removeNotInterestingHeaders();
|
|
||||||
bool _isDigest;
|
|
||||||
bool _isMultipart;
|
|
||||||
bool _isPlainPost;
|
|
||||||
bool _expectingContinue;
|
|
||||||
size_t _contentLength;
|
|
||||||
size_t _parsedLength;
|
|
||||||
|
|
||||||
std::list<AsyncWebHeader> _headers;
|
|
||||||
LinkedList<AsyncWebParameter *> _params;
|
|
||||||
std::vector<String> _pathParams;
|
|
||||||
|
|
||||||
uint8_t _multiParseState;
|
|
||||||
uint8_t _boundaryPosition;
|
|
||||||
size_t _itemStartIndex;
|
|
||||||
size_t _itemSize;
|
|
||||||
String _itemName;
|
|
||||||
String _itemFilename;
|
|
||||||
String _itemType;
|
|
||||||
String _itemValue;
|
|
||||||
uint8_t * _itemBuffer;
|
|
||||||
size_t _itemBufferIndex;
|
|
||||||
bool _itemIsFile;
|
|
||||||
|
|
||||||
void _onPoll();
|
|
||||||
void _onAck(size_t len, uint32_t time);
|
|
||||||
void _onError(int8_t error);
|
|
||||||
void _onTimeout(uint32_t time);
|
|
||||||
void _onDisconnect();
|
|
||||||
void _onData(void * buf, size_t len);
|
|
||||||
|
|
||||||
void _addParam(AsyncWebParameter *);
|
|
||||||
void _addPathParam(const char * param);
|
|
||||||
|
|
||||||
bool _parseReqHead();
|
|
||||||
bool _parseReqHeader();
|
|
||||||
void _parseLine();
|
|
||||||
void _parsePlainPostChar(uint8_t data);
|
|
||||||
void _parseMultipartPostByte(uint8_t data, bool last);
|
|
||||||
void _addGetParams(const String & params);
|
|
||||||
|
|
||||||
void _handleUploadStart();
|
|
||||||
void _handleUploadByte(uint8_t data, bool last);
|
|
||||||
void _handleUploadEnd();
|
|
||||||
|
|
||||||
public:
|
|
||||||
File _tempFile;
|
|
||||||
void * _tempObject;
|
|
||||||
|
|
||||||
AsyncWebServerRequest(AsyncWebServer *, AsyncClient *);
|
|
||||||
~AsyncWebServerRequest();
|
|
||||||
|
|
||||||
AsyncClient * client() {
|
|
||||||
return _client;
|
|
||||||
}
|
|
||||||
uint8_t version() const {
|
|
||||||
return _version;
|
|
||||||
}
|
|
||||||
WebRequestMethodComposite method() const {
|
|
||||||
return _method;
|
|
||||||
}
|
|
||||||
const String & url() const {
|
|
||||||
return _url;
|
|
||||||
}
|
|
||||||
const String & host() const {
|
|
||||||
return _host;
|
|
||||||
}
|
|
||||||
const String & contentType() const {
|
|
||||||
return _contentType;
|
|
||||||
}
|
|
||||||
size_t contentLength() const {
|
|
||||||
return _contentLength;
|
|
||||||
}
|
|
||||||
bool multipart() const {
|
|
||||||
return _isMultipart;
|
|
||||||
}
|
|
||||||
const __FlashStringHelper * methodToString() const;
|
|
||||||
const __FlashStringHelper * requestedConnTypeToString() const;
|
|
||||||
RequestedConnectionType requestedConnType() const {
|
|
||||||
return _reqconntype;
|
|
||||||
}
|
|
||||||
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
|
||||||
void onDisconnect(ArDisconnectHandler fn);
|
|
||||||
|
|
||||||
//hash is the string representation of:
|
|
||||||
// base64(user:pass) for basic or
|
|
||||||
// user:realm:md5(user:realm:pass) for digest
|
|
||||||
bool authenticate(const char * hash);
|
|
||||||
bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false);
|
|
||||||
void requestAuthentication(const char * realm = NULL, bool isDigest = true);
|
|
||||||
|
|
||||||
void setHandler(AsyncWebHandler * handler) {
|
|
||||||
_handler = handler;
|
|
||||||
}
|
|
||||||
void addInterestingHeader(const String & name);
|
|
||||||
|
|
||||||
void redirect(const String & url);
|
|
||||||
|
|
||||||
void send(AsyncWebServerResponse * response);
|
|
||||||
void send(int code, const String & contentType = String(), const String & content = String());
|
|
||||||
void send(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
void send(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
void send(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
void send(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
void sendChunked(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
void send_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
void send_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
|
||||||
|
|
||||||
AsyncWebServerResponse * beginResponse(int code, const String & contentType = String(), const String & content = String());
|
|
||||||
AsyncWebServerResponse *
|
|
||||||
beginResponse(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncWebServerResponse *
|
|
||||||
beginResponse(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncWebServerResponse * beginResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncWebServerResponse * beginResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
AsyncWebServerResponse * beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
AsyncResponseStream * beginResponseStream(const String & contentType, size_t bufferSize = 1460);
|
|
||||||
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len); // added by proddy for EMS-ESP
|
|
||||||
|
|
||||||
size_t headers() const; // get header count
|
|
||||||
bool hasHeader(const String & name) const; // check if header exists
|
|
||||||
bool hasHeader(const __FlashStringHelper * data) const; // check if header exists
|
|
||||||
|
|
||||||
AsyncWebHeader * getHeader(const String & name);
|
|
||||||
const AsyncWebHeader * getHeader(const String & name) const;
|
|
||||||
AsyncWebHeader * getHeader(const __FlashStringHelper * data);
|
|
||||||
const AsyncWebHeader * getHeader(const __FlashStringHelper * data) const;
|
|
||||||
AsyncWebHeader * getHeader(size_t num);
|
|
||||||
const AsyncWebHeader * getHeader(size_t num) const;
|
|
||||||
|
|
||||||
size_t params() const; // get arguments count
|
|
||||||
bool hasParam(const String & name, bool post = false, bool file = false) const;
|
|
||||||
bool hasParam(const __FlashStringHelper * data, bool post = false, bool file = false) const;
|
|
||||||
|
|
||||||
AsyncWebParameter * getParam(const String & name, bool post = false, bool file = false) const;
|
|
||||||
AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const;
|
|
||||||
AsyncWebParameter * getParam(size_t num) const;
|
|
||||||
|
|
||||||
size_t args() const {
|
|
||||||
return params();
|
|
||||||
} // get arguments count
|
|
||||||
const String & arg(const String & name) const; // get request argument value by name
|
|
||||||
const String & arg(const __FlashStringHelper * data) const; // get request argument value by F(name)
|
|
||||||
const String & arg(size_t i) const; // get request argument value by number
|
|
||||||
const String & argName(size_t i) const; // get request argument name by number
|
|
||||||
bool hasArg(const char * name) const; // check if argument exists
|
|
||||||
bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists
|
|
||||||
|
|
||||||
const String & ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const;
|
|
||||||
|
|
||||||
const String & header(const char * name) const; // get request header value by name
|
|
||||||
const String & header(const __FlashStringHelper * data) const; // get request header value by F(name)
|
|
||||||
const String & header(size_t i) const; // get request header value by number
|
|
||||||
const String & headerName(size_t i) const; // get request header name by number
|
|
||||||
String urlDecode(const String & text) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
|
|
||||||
* */
|
|
||||||
|
|
||||||
typedef std::function<bool(AsyncWebServerRequest * request)> ArRequestFilterFunction;
|
|
||||||
|
|
||||||
bool ON_STA_FILTER(AsyncWebServerRequest * request);
|
|
||||||
|
|
||||||
bool ON_AP_FILTER(AsyncWebServerRequest * request);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* REWRITE :: One instance can be handle any Request (done by the Server)
|
|
||||||
* */
|
|
||||||
|
|
||||||
class AsyncWebRewrite {
|
|
||||||
protected:
|
|
||||||
String _from;
|
|
||||||
String _toUrl;
|
|
||||||
String _params;
|
|
||||||
ArRequestFilterFunction _filter;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebRewrite(const char * from, const char * to)
|
|
||||||
: _from(from)
|
|
||||||
, _toUrl(to)
|
|
||||||
, _params(String())
|
|
||||||
, _filter(NULL) {
|
|
||||||
int index = _toUrl.indexOf('?');
|
|
||||||
if (index > 0) {
|
|
||||||
_params = _toUrl.substring(index + 1);
|
|
||||||
_toUrl = _toUrl.substring(0, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual ~AsyncWebRewrite() {
|
|
||||||
}
|
|
||||||
AsyncWebRewrite & setFilter(ArRequestFilterFunction fn) {
|
|
||||||
_filter = fn;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
bool filter(AsyncWebServerRequest * request) const {
|
|
||||||
return _filter == NULL || _filter(request);
|
|
||||||
}
|
|
||||||
const String & from(void) const {
|
|
||||||
return _from;
|
|
||||||
}
|
|
||||||
const String & toUrl(void) const {
|
|
||||||
return _toUrl;
|
|
||||||
}
|
|
||||||
const String & params(void) const {
|
|
||||||
return _params;
|
|
||||||
}
|
|
||||||
virtual bool match(AsyncWebServerRequest * request) {
|
|
||||||
return from() == request->url() && filter(request);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* HANDLER :: One instance can be attached to any Request (done by the Server)
|
|
||||||
* */
|
|
||||||
|
|
||||||
class AsyncWebHandler {
|
|
||||||
protected:
|
|
||||||
ArRequestFilterFunction _filter;
|
|
||||||
String _username;
|
|
||||||
String _password;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebHandler()
|
|
||||||
: _username("")
|
|
||||||
, _password("") {
|
|
||||||
}
|
|
||||||
AsyncWebHandler & setFilter(ArRequestFilterFunction fn) {
|
|
||||||
_filter = fn;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
AsyncWebHandler & setAuthentication(const String & username, const String & password) {
|
|
||||||
_username = username;
|
|
||||||
_password = password;
|
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
AsyncWebHandler & setAuthentication(const char * username, const char * password) {
|
|
||||||
_username = String(username);
|
|
||||||
_password = String(password);
|
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
bool filter(AsyncWebServerRequest * request) {
|
|
||||||
return _filter == NULL || _filter(request);
|
|
||||||
}
|
|
||||||
virtual ~AsyncWebHandler() {
|
|
||||||
}
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest * request __attribute__((unused))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest * request __attribute__((unused))) {
|
|
||||||
}
|
|
||||||
virtual void handleUpload(AsyncWebServerRequest * request __attribute__((unused)),
|
|
||||||
const String & filename __attribute__((unused)),
|
|
||||||
size_t index __attribute__((unused)),
|
|
||||||
uint8_t * data __attribute__((unused)),
|
|
||||||
size_t len __attribute__((unused)),
|
|
||||||
bool final __attribute__((unused))) {
|
|
||||||
}
|
|
||||||
virtual void handleBody(AsyncWebServerRequest * request __attribute__((unused)),
|
|
||||||
uint8_t * data __attribute__((unused)),
|
|
||||||
size_t len __attribute__((unused)),
|
|
||||||
size_t index __attribute__((unused)),
|
|
||||||
size_t total __attribute__((unused))) {
|
|
||||||
}
|
|
||||||
virtual bool isRequestHandlerTrivial() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RESPONSE :: One instance is created for each Request (attached by the Handler)
|
|
||||||
* */
|
|
||||||
|
|
||||||
typedef enum { RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED } WebResponseState;
|
|
||||||
|
|
||||||
class AsyncWebServerResponse {
|
|
||||||
protected:
|
|
||||||
int _code;
|
|
||||||
std::list<AsyncWebHeader> _headers;
|
|
||||||
String _contentType;
|
|
||||||
size_t _contentLength;
|
|
||||||
bool _sendContentLength;
|
|
||||||
bool _chunked;
|
|
||||||
size_t _headLength;
|
|
||||||
size_t _sentLength;
|
|
||||||
size_t _ackedLength;
|
|
||||||
size_t _writtenLength;
|
|
||||||
WebResponseState _state;
|
|
||||||
const char * _responseCodeToString(int code);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const __FlashStringHelper * responseCodeToString(int code);
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebServerResponse();
|
|
||||||
virtual ~AsyncWebServerResponse();
|
|
||||||
virtual void setCode(int code);
|
|
||||||
virtual void setContentLength(size_t len);
|
|
||||||
virtual void setContentType(const String & type);
|
|
||||||
virtual void addHeader(const String & name, const String & value);
|
|
||||||
virtual String _assembleHead(uint8_t version);
|
|
||||||
virtual bool _started() const;
|
|
||||||
virtual bool _finished() const;
|
|
||||||
virtual bool _failed() const;
|
|
||||||
virtual bool _sourceValid() const;
|
|
||||||
virtual void _respond(AsyncWebServerRequest * request);
|
|
||||||
virtual size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SERVER :: One instance
|
|
||||||
* */
|
|
||||||
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
|
||||||
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy for EMS-ESP
|
|
||||||
|
|
||||||
class AsyncWebServer {
|
|
||||||
protected:
|
|
||||||
AsyncServer _server;
|
|
||||||
LinkedList<AsyncWebRewrite *> _rewrites;
|
|
||||||
LinkedList<AsyncWebHandler *> _handlers;
|
|
||||||
AsyncCallbackWebHandler * _catchAllHandler;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebServer(uint16_t port);
|
|
||||||
~AsyncWebServer();
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
void end();
|
|
||||||
|
|
||||||
#if ASYNC_TCP_SSL_ENABLED
|
|
||||||
void onSslFileRequest(AcSSlFileHandler cb, void * arg);
|
|
||||||
void beginSecure(const char * cert, const char * private_key_file, const char * password);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AsyncWebRewrite & addRewrite(AsyncWebRewrite * rewrite);
|
|
||||||
bool removeRewrite(AsyncWebRewrite * rewrite);
|
|
||||||
AsyncWebRewrite & rewrite(const char * from, const char * to);
|
|
||||||
|
|
||||||
AsyncWebHandler & addHandler(AsyncWebHandler * handler);
|
|
||||||
bool removeHandler(AsyncWebHandler * handler);
|
|
||||||
|
|
||||||
AsyncCallbackWebHandler & on(const char * uri, ArRequestHandlerFunction onRequest);
|
|
||||||
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest);
|
|
||||||
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
|
|
||||||
AsyncCallbackWebHandler &
|
|
||||||
on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
|
|
||||||
|
|
||||||
void on(const char * uri, ArJsonRequestHandlerFunction onRequest); // added by proddy for EMS-ESP
|
|
||||||
|
|
||||||
AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
|
|
||||||
|
|
||||||
void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned
|
|
||||||
void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads
|
|
||||||
void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request)
|
|
||||||
|
|
||||||
void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody
|
|
||||||
|
|
||||||
void _handleDisconnect(AsyncWebServerRequest * request);
|
|
||||||
void _attachHandler(AsyncWebServerRequest * request);
|
|
||||||
void _rewriteRequest(AsyncWebServerRequest * request);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DefaultHeaders {
|
|
||||||
using headers_t = std::list<AsyncWebHeader>;
|
|
||||||
headers_t _headers;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DefaultHeaders() = default;
|
|
||||||
|
|
||||||
using ConstIterator = headers_t::const_iterator;
|
|
||||||
|
|
||||||
void addHeader(const String & name, const String & value) {
|
|
||||||
_headers.emplace_back(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstIterator begin() const {
|
|
||||||
return _headers.begin();
|
|
||||||
}
|
|
||||||
ConstIterator end() const {
|
|
||||||
return _headers.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultHeaders(DefaultHeaders const &) = delete;
|
|
||||||
DefaultHeaders & operator=(DefaultHeaders const &) = delete;
|
|
||||||
|
|
||||||
static DefaultHeaders & Instance() {
|
|
||||||
static DefaultHeaders instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "WebResponseImpl.h"
|
|
||||||
#include "WebHandlerImpl.h"
|
|
||||||
#include "AsyncWebSocket.h"
|
|
||||||
#include "AsyncEventSource.h"
|
|
||||||
|
|
||||||
#endif /* _AsyncWebServer_H_ */
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// to please Arduino Lint
|
|
||||||
#include "ESPAsyncWebServer.h"
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef STRINGARRAY_H_
|
|
||||||
#define STRINGARRAY_H_
|
|
||||||
|
|
||||||
#include "stddef.h"
|
|
||||||
#include "WString.h"
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class LinkedListNode {
|
|
||||||
T _value;
|
|
||||||
public:
|
|
||||||
LinkedListNode<T>* next;
|
|
||||||
LinkedListNode(const T val): _value(val), next(nullptr) {}
|
|
||||||
~LinkedListNode(){}
|
|
||||||
const T& value() const { return _value; };
|
|
||||||
T& value(){ return _value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, template<typename> class Item = LinkedListNode>
|
|
||||||
class LinkedList {
|
|
||||||
public:
|
|
||||||
typedef Item<T> ItemType;
|
|
||||||
typedef std::function<void(const T&)> OnRemove;
|
|
||||||
typedef std::function<bool(const T&)> Predicate;
|
|
||||||
private:
|
|
||||||
ItemType* _root;
|
|
||||||
OnRemove _onRemove;
|
|
||||||
|
|
||||||
class Iterator {
|
|
||||||
ItemType* _node;
|
|
||||||
public:
|
|
||||||
Iterator(ItemType* current = nullptr) : _node(current) {}
|
|
||||||
Iterator(const Iterator& i) : _node(i._node) {}
|
|
||||||
Iterator& operator ++() { _node = _node->next; return *this; }
|
|
||||||
bool operator != (const Iterator& i) const { return _node != i._node; }
|
|
||||||
const T& operator * () const { return _node->value(); }
|
|
||||||
const T* operator -> () const { return &_node->value(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef const Iterator ConstIterator;
|
|
||||||
ConstIterator begin() const { return ConstIterator(_root); }
|
|
||||||
ConstIterator end() const { return ConstIterator(nullptr); }
|
|
||||||
|
|
||||||
LinkedList(OnRemove onRemove) : _root(nullptr), _onRemove(onRemove) {}
|
|
||||||
~LinkedList(){}
|
|
||||||
void add(const T& t){
|
|
||||||
auto it = new ItemType(t);
|
|
||||||
if(!_root){
|
|
||||||
_root = it;
|
|
||||||
} else {
|
|
||||||
auto i = _root;
|
|
||||||
while(i->next) i = i->next;
|
|
||||||
i->next = it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T& front() const {
|
|
||||||
return _root->value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEmpty() const {
|
|
||||||
return _root == nullptr;
|
|
||||||
}
|
|
||||||
size_t length() const {
|
|
||||||
size_t i = 0;
|
|
||||||
auto it = _root;
|
|
||||||
while(it){
|
|
||||||
i++;
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
size_t count_if(Predicate predicate) const {
|
|
||||||
size_t i = 0;
|
|
||||||
auto it = _root;
|
|
||||||
while(it){
|
|
||||||
if (!predicate){
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else if (predicate(it->value())) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
const T* nth(size_t N) const {
|
|
||||||
size_t i = 0;
|
|
||||||
auto it = _root;
|
|
||||||
while(it){
|
|
||||||
if(i++ == N)
|
|
||||||
return &(it->value());
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool remove(const T& t){
|
|
||||||
auto it = _root;
|
|
||||||
auto pit = _root;
|
|
||||||
while(it){
|
|
||||||
if(it->value() == t){
|
|
||||||
if(it == _root){
|
|
||||||
_root = _root->next;
|
|
||||||
} else {
|
|
||||||
pit->next = it->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_onRemove) {
|
|
||||||
_onRemove(it->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete it;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
pit = it;
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool remove_first(Predicate predicate){
|
|
||||||
auto it = _root;
|
|
||||||
auto pit = _root;
|
|
||||||
while(it){
|
|
||||||
if(predicate(it->value())){
|
|
||||||
if(it == _root){
|
|
||||||
_root = _root->next;
|
|
||||||
} else {
|
|
||||||
pit->next = it->next;
|
|
||||||
}
|
|
||||||
if (_onRemove) {
|
|
||||||
_onRemove(it->value());
|
|
||||||
}
|
|
||||||
delete it;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
pit = it;
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(){
|
|
||||||
while(_root != nullptr){
|
|
||||||
auto it = _root;
|
|
||||||
_root = _root->next;
|
|
||||||
if (_onRemove) {
|
|
||||||
_onRemove(it->value());
|
|
||||||
}
|
|
||||||
delete it;
|
|
||||||
}
|
|
||||||
_root = nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* STRINGARRAY_H_ */
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "WebAuthentication.h"
|
|
||||||
#include <libb64/cencode.h>
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <MD5Builder.h>
|
|
||||||
#else
|
|
||||||
#include "md5.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Basic Auth hash = base64("username:password")
|
|
||||||
|
|
||||||
bool checkBasicAuthentication(const char * hash, const char * username, const char * password) {
|
|
||||||
if (username == NULL || password == NULL || hash == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
size_t toencodeLen = strlen(username) + strlen(password) + 1;
|
|
||||||
size_t encodedLen = base64_encode_expected_len(toencodeLen);
|
|
||||||
if (strlen(hash) != encodedLen)
|
|
||||||
// Fix from https://github.com/me-no-dev/ESPAsyncWebServer/issues/667
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
if (strlen(hash) != encodedLen)
|
|
||||||
#else
|
|
||||||
if (strlen(hash) != encodedLen - 1)
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
|
|
||||||
char * toencode = new char[toencodeLen + 1];
|
|
||||||
if (toencode == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
char * encoded = new char[base64_encode_expected_len(toencodeLen) + 1];
|
|
||||||
if (encoded == NULL) {
|
|
||||||
delete[] toencode;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sprintf_P(toencode, PSTR("%s:%s"), username, password);
|
|
||||||
if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0) {
|
|
||||||
delete[] toencode;
|
|
||||||
delete[] encoded;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
delete[] toencode;
|
|
||||||
delete[] encoded;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool getMD5(uint8_t * data, uint16_t len, char * output) { //33 bytes or more
|
|
||||||
#ifdef ESP32
|
|
||||||
MD5Builder md5;
|
|
||||||
md5.begin();
|
|
||||||
md5.add(data, len);
|
|
||||||
md5.calculate();
|
|
||||||
md5.getChars(output);
|
|
||||||
#else
|
|
||||||
md5_context_t _ctx;
|
|
||||||
|
|
||||||
uint8_t * _buf = (uint8_t *)malloc(16);
|
|
||||||
if (_buf == NULL)
|
|
||||||
return false;
|
|
||||||
memset(_buf, 0x00, 16);
|
|
||||||
|
|
||||||
MD5Init(&_ctx);
|
|
||||||
MD5Update(&_ctx, data, len);
|
|
||||||
MD5Final(_buf, &_ctx);
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
|
||||||
sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(_buf);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String genRandomMD5() {
|
|
||||||
#ifdef ESP8266
|
|
||||||
uint32_t r = RANDOM_REG32;
|
|
||||||
#else
|
|
||||||
uint32_t r = rand();
|
|
||||||
#endif
|
|
||||||
char * out = (char *)malloc(33);
|
|
||||||
if (out == NULL || !getMD5((uint8_t *)(&r), 4, out))
|
|
||||||
return emptyString;
|
|
||||||
String res = String(out);
|
|
||||||
free(out);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String stringMD5(const String & in) {
|
|
||||||
char * out = (char *)malloc(33);
|
|
||||||
if (out == NULL || !getMD5((uint8_t *)(in.c_str()), in.length(), out))
|
|
||||||
return emptyString;
|
|
||||||
String res = String(out);
|
|
||||||
free(out);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
String generateDigestHash(const char * username, const char * password, const char * realm) {
|
|
||||||
if (username == NULL || password == NULL || realm == NULL) {
|
|
||||||
return emptyString;
|
|
||||||
}
|
|
||||||
char * out = (char *)malloc(33);
|
|
||||||
String res = String(username);
|
|
||||||
res += ':';
|
|
||||||
res.concat(realm);
|
|
||||||
res += ':';
|
|
||||||
String in = res;
|
|
||||||
in.concat(password);
|
|
||||||
if (out == NULL || !getMD5((uint8_t *)(in.c_str()), in.length(), out))
|
|
||||||
return emptyString;
|
|
||||||
res.concat(out);
|
|
||||||
free(out);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
String requestDigestAuthentication(const char * realm) {
|
|
||||||
String header = F("realm=\"");
|
|
||||||
if (realm == NULL)
|
|
||||||
header.concat(F("asyncesp"));
|
|
||||||
else
|
|
||||||
header.concat(realm);
|
|
||||||
header.concat(F("\", qop=\"auth\", nonce=\""));
|
|
||||||
header.concat(genRandomMD5());
|
|
||||||
header.concat(F("\", opaque=\""));
|
|
||||||
header.concat(genRandomMD5());
|
|
||||||
header += '"';
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checkDigestAuthentication(const char * header,
|
|
||||||
const __FlashStringHelper * method,
|
|
||||||
const char * username,
|
|
||||||
const char * password,
|
|
||||||
const char * realm,
|
|
||||||
bool passwordIsHash,
|
|
||||||
const char * nonce,
|
|
||||||
const char * opaque,
|
|
||||||
const char * uri) {
|
|
||||||
if (username == NULL || password == NULL || header == NULL || method == NULL) {
|
|
||||||
//os_printf("AUTH FAIL: missing requred fields\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String myHeader = String(header);
|
|
||||||
int nextBreak = myHeader.indexOf(',');
|
|
||||||
if (nextBreak < 0) {
|
|
||||||
//os_printf("AUTH FAIL: no variables\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String myUsername = String();
|
|
||||||
String myRealm = String();
|
|
||||||
String myNonce = String();
|
|
||||||
String myUri = String();
|
|
||||||
String myResponse = String();
|
|
||||||
String myQop = String();
|
|
||||||
String myNc = String();
|
|
||||||
String myCnonce = String();
|
|
||||||
|
|
||||||
myHeader += F(", ");
|
|
||||||
do {
|
|
||||||
String avLine = myHeader.substring(0, nextBreak);
|
|
||||||
avLine.trim();
|
|
||||||
myHeader = myHeader.substring(nextBreak + 1);
|
|
||||||
nextBreak = myHeader.indexOf(',');
|
|
||||||
|
|
||||||
int eqSign = avLine.indexOf('=');
|
|
||||||
if (eqSign < 0) {
|
|
||||||
//os_printf("AUTH FAIL: no = sign\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String varName = avLine.substring(0, eqSign);
|
|
||||||
avLine = avLine.substring(eqSign + 1);
|
|
||||||
if (avLine.startsWith(String('"'))) {
|
|
||||||
avLine = avLine.substring(1, avLine.length() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (varName.equals(F("username"))) {
|
|
||||||
if (!avLine.equals(username)) {
|
|
||||||
//os_printf("AUTH FAIL: username\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
myUsername = avLine;
|
|
||||||
} else if (varName.equals(F("realm"))) {
|
|
||||||
if (realm != NULL && !avLine.equals(realm)) {
|
|
||||||
//os_printf("AUTH FAIL: realm\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
myRealm = avLine;
|
|
||||||
} else if (varName.equals(F("nonce"))) {
|
|
||||||
if (nonce != NULL && !avLine.equals(nonce)) {
|
|
||||||
//os_printf("AUTH FAIL: nonce\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
myNonce = avLine;
|
|
||||||
} else if (varName.equals(F("opaque"))) {
|
|
||||||
if (opaque != NULL && !avLine.equals(opaque)) {
|
|
||||||
//os_printf("AUTH FAIL: opaque\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (varName.equals(F("uri"))) {
|
|
||||||
if (uri != NULL && !avLine.equals(uri)) {
|
|
||||||
//os_printf("AUTH FAIL: uri\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
myUri = avLine;
|
|
||||||
} else if (varName.equals(F("response"))) {
|
|
||||||
myResponse = avLine;
|
|
||||||
} else if (varName.equals(F("qop"))) {
|
|
||||||
myQop = avLine;
|
|
||||||
} else if (varName.equals(F("nc"))) {
|
|
||||||
myNc = avLine;
|
|
||||||
} else if (varName.equals(F("cnonce"))) {
|
|
||||||
myCnonce = avLine;
|
|
||||||
}
|
|
||||||
} while (nextBreak > 0);
|
|
||||||
|
|
||||||
String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + String(password));
|
|
||||||
String ha2 = String(method) + ':' + myUri;
|
|
||||||
String response = ha1 + ':' + myNonce + ':' + myNc + ':' + myCnonce + ':' + myQop + ':' + stringMD5(ha2);
|
|
||||||
|
|
||||||
if (myResponse.equals(stringMD5(response))) {
|
|
||||||
//os_printf("AUTH SUCCESS\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//os_printf("AUTH FAIL: password\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEB_AUTHENTICATION_H_
|
|
||||||
#define WEB_AUTHENTICATION_H_
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
bool checkBasicAuthentication(const char * header, const char * username, const char * password);
|
|
||||||
String requestDigestAuthentication(const char * realm);
|
|
||||||
bool checkDigestAuthentication(const char * header, const __FlashStringHelper *method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri);
|
|
||||||
|
|
||||||
//for storing hashed versions on the device that can be authenticated against
|
|
||||||
String generateDigestHash(const char * username, const char * password, const char * realm);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef ASYNCWEBSERVERHANDLERIMPL_H_
|
|
||||||
#define ASYNCWEBSERVERHANDLERIMPL_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#ifdef ASYNCWEBSERVER_REGEX
|
|
||||||
#include <regex>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "stddef.h"
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
class AsyncStaticWebHandler: public AsyncWebHandler {
|
|
||||||
using File = fs::File;
|
|
||||||
using FS = fs::FS;
|
|
||||||
private:
|
|
||||||
bool _getFile(AsyncWebServerRequest *request);
|
|
||||||
bool _fileExists(AsyncWebServerRequest *request, const String& path);
|
|
||||||
uint8_t _countBits(const uint8_t value) const;
|
|
||||||
protected:
|
|
||||||
FS _fs;
|
|
||||||
String _uri;
|
|
||||||
String _path;
|
|
||||||
String _default_file;
|
|
||||||
String _cache_control;
|
|
||||||
String _last_modified;
|
|
||||||
AwsTemplateProcessor _callback;
|
|
||||||
bool _isDir;
|
|
||||||
bool _gzipFirst;
|
|
||||||
uint8_t _gzipStats;
|
|
||||||
public:
|
|
||||||
AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
|
||||||
AsyncStaticWebHandler& setIsDir(bool isDir);
|
|
||||||
AsyncStaticWebHandler& setDefaultFile(const char* filename);
|
|
||||||
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
|
|
||||||
AsyncStaticWebHandler& setLastModified(const char* last_modified);
|
|
||||||
AsyncStaticWebHandler& setLastModified(struct tm* last_modified);
|
|
||||||
#ifdef ESP8266
|
|
||||||
AsyncStaticWebHandler& setLastModified(time_t last_modified);
|
|
||||||
AsyncStaticWebHandler& setLastModified(); //sets to current time. Make sure sntp is runing and time is updated
|
|
||||||
#endif
|
|
||||||
AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;}
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncCallbackWebHandler: public AsyncWebHandler {
|
|
||||||
private:
|
|
||||||
protected:
|
|
||||||
String _uri;
|
|
||||||
WebRequestMethodComposite _method;
|
|
||||||
ArRequestHandlerFunction _onRequest;
|
|
||||||
ArUploadHandlerFunction _onUpload;
|
|
||||||
ArBodyHandlerFunction _onBody;
|
|
||||||
bool _isRegex;
|
|
||||||
public:
|
|
||||||
AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {}
|
|
||||||
void setUri(const String& uri){
|
|
||||||
_uri = uri;
|
|
||||||
_isRegex = uri.startsWith("^") && uri.endsWith("$");
|
|
||||||
}
|
|
||||||
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
|
||||||
void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; }
|
|
||||||
void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; }
|
|
||||||
void onBody(ArBodyHandlerFunction fn){ _onBody = fn; }
|
|
||||||
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest *request) override final{
|
|
||||||
|
|
||||||
if(!_onRequest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(!(_method & request->method()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#ifdef ASYNCWEBSERVER_REGEX
|
|
||||||
if (_isRegex) {
|
|
||||||
std::regex pattern(_uri.c_str());
|
|
||||||
std::smatch matches;
|
|
||||||
std::string s(request->url().c_str());
|
|
||||||
if(std::regex_search(s, matches, pattern)) {
|
|
||||||
for (size_t i = 1; i < matches.size(); ++i) { // start from 1
|
|
||||||
request->_addPathParam(matches[i].str().c_str());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (_uri.length() && _uri.startsWith("/*.")) {
|
|
||||||
String uriTemplate = String (_uri);
|
|
||||||
uriTemplate = uriTemplate.substring(uriTemplate.lastIndexOf("."));
|
|
||||||
if (!request->url().endsWith(uriTemplate))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (_uri.length() && _uri.endsWith("*")) {
|
|
||||||
String uriTemplate = String(_uri);
|
|
||||||
uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1);
|
|
||||||
if (!request->url().startsWith(uriTemplate))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
request->addInterestingHeader("ANY");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
|
||||||
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if(_onRequest)
|
|
||||||
_onRequest(request);
|
|
||||||
else
|
|
||||||
request->send(500);
|
|
||||||
}
|
|
||||||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
|
|
||||||
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if(_onUpload)
|
|
||||||
_onUpload(request, filename, index, data, len, final);
|
|
||||||
}
|
|
||||||
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
|
||||||
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if(_onBody)
|
|
||||||
_onBody(request, data, len, index, total);
|
|
||||||
}
|
|
||||||
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "ESPAsyncWebServer.h"
|
|
||||||
#include "WebHandlerImpl.h"
|
|
||||||
|
|
||||||
AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control)
|
|
||||||
: _fs(fs), _uri(uri), _path(path), _default_file(F("index.htm")), _cache_control(cache_control), _last_modified(), _callback(nullptr)
|
|
||||||
{
|
|
||||||
// Ensure leading '/'
|
|
||||||
if (_uri.length() == 0 || _uri[0] != '/') _uri = String('/') + _uri;
|
|
||||||
if (_path.length() == 0 || _path[0] != '/') _path = String('/') + _path;
|
|
||||||
|
|
||||||
// If path ends with '/' we assume a hint that this is a directory to improve performance.
|
|
||||||
// However - if it does not end with '/' we, can't assume a file, path can still be a directory.
|
|
||||||
_isDir = _path[_path.length()-1] == '/';
|
|
||||||
|
|
||||||
// Remove the trailing '/' so we can handle default file
|
|
||||||
// Notice that root will be "" not "/"
|
|
||||||
if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1);
|
|
||||||
if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1);
|
|
||||||
|
|
||||||
// Reset stats
|
|
||||||
_gzipFirst = false;
|
|
||||||
_gzipStats = 0xF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir){
|
|
||||||
_isDir = isDir;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename){
|
|
||||||
_default_file = String(filename);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control){
|
|
||||||
_cache_control = String(cache_control);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified){
|
|
||||||
_last_modified = last_modified;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified){
|
|
||||||
auto formatP = PSTR("%a, %d %b %Y %H:%M:%S %Z");
|
|
||||||
char format[strlen_P(formatP) + 1];
|
|
||||||
strcpy_P(format, formatP);
|
|
||||||
|
|
||||||
char result[30];
|
|
||||||
strftime(result, sizeof(result), format, last_modified);
|
|
||||||
return setLastModified((const char *)result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified){
|
|
||||||
return setLastModified((struct tm *)gmtime(&last_modified));
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){
|
|
||||||
time_t last_modified;
|
|
||||||
if(time(&last_modified) == 0) //time is not yet set
|
|
||||||
return *this;
|
|
||||||
return setLastModified(last_modified);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){
|
|
||||||
if(request->method() != HTTP_GET
|
|
||||||
|| !request->url().startsWith(_uri)
|
|
||||||
|| !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)
|
|
||||||
){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (_getFile(request)) {
|
|
||||||
// We interested in "If-Modified-Since" header to check if file was modified
|
|
||||||
if (_last_modified.length())
|
|
||||||
request->addInterestingHeader(F("If-Modified-Since"));
|
|
||||||
|
|
||||||
if(_cache_control.length())
|
|
||||||
request->addInterestingHeader(F("If-None-Match"));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
// Remove the found uri
|
|
||||||
String path = request->url().substring(_uri.length());
|
|
||||||
|
|
||||||
// We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/'
|
|
||||||
bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/');
|
|
||||||
|
|
||||||
path = _path + path;
|
|
||||||
|
|
||||||
// Do we have a file or .gz file
|
|
||||||
if (!canSkipFileCheck && _fileExists(request, path))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Can't handle if not default file
|
|
||||||
if (_default_file.length() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Try to add default file, ensure there is a trailing '/' ot the path.
|
|
||||||
if (path.length() == 0 || path[path.length()-1] != '/')
|
|
||||||
path += String('/');
|
|
||||||
path += _default_file;
|
|
||||||
|
|
||||||
return _fileExists(request, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
#define FILE_IS_REAL(f) (f == true && !f.isDirectory())
|
|
||||||
#else
|
|
||||||
#define FILE_IS_REAL(f) (f == true)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const String& path)
|
|
||||||
{
|
|
||||||
bool fileFound = false;
|
|
||||||
bool gzipFound = false;
|
|
||||||
|
|
||||||
String gzip = path + F(".gz");
|
|
||||||
|
|
||||||
if (_gzipFirst) {
|
|
||||||
if (_fs.exists(gzip)) {
|
|
||||||
request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read);
|
|
||||||
gzipFound = FILE_IS_REAL(request->_tempFile);
|
|
||||||
}
|
|
||||||
if (!gzipFound){
|
|
||||||
if (_fs.exists(path)) {
|
|
||||||
request->_tempFile = _fs.open(path, fs::FileOpenMode::read);
|
|
||||||
fileFound = FILE_IS_REAL(request->_tempFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_fs.exists(path)) {
|
|
||||||
request->_tempFile = _fs.open(path, fs::FileOpenMode::read);
|
|
||||||
fileFound = FILE_IS_REAL(request->_tempFile);
|
|
||||||
}
|
|
||||||
if (!fileFound){
|
|
||||||
if (_fs.exists(gzip)) {
|
|
||||||
request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read);
|
|
||||||
gzipFound = FILE_IS_REAL(request->_tempFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = fileFound || gzipFound;
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
// Extract the file name from the path and keep it in _tempObject
|
|
||||||
size_t pathLen = path.length();
|
|
||||||
char * _tempPath = (char*)malloc(pathLen+1);
|
|
||||||
snprintf_P(_tempPath, pathLen+1, PSTR("%s"), path.c_str());
|
|
||||||
request->_tempObject = (void*)_tempPath;
|
|
||||||
|
|
||||||
// Calculate gzip statistic
|
|
||||||
_gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0);
|
|
||||||
if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip
|
|
||||||
else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip
|
|
||||||
else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const
|
|
||||||
{
|
|
||||||
uint8_t w = value;
|
|
||||||
uint8_t n;
|
|
||||||
for (n=0; w!=0; n++) w&=w-1;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
// Get the filename from request->_tempObject and free it
|
|
||||||
String filename = String((char*)request->_tempObject);
|
|
||||||
free(request->_tempObject);
|
|
||||||
request->_tempObject = NULL;
|
|
||||||
if((_username.length() && _password.length()) && !request->authenticate(_username.c_str(), _password.c_str()))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
|
|
||||||
if (request->_tempFile == true) {
|
|
||||||
time_t lw = request->_tempFile.getLastWrite(); // get last file mod time (if supported by FS)
|
|
||||||
if (lw) setLastModified(gmtime(&lw));
|
|
||||||
String etag(lw ? lw : request->_tempFile.size()); // set etag to lastmod timestamp if available, otherwise to size
|
|
||||||
if (_last_modified.length() && _last_modified == request->header(F("If-Modified-Since"))) {
|
|
||||||
request->_tempFile.close();
|
|
||||||
request->send(304); // Not modified
|
|
||||||
} else if (_cache_control.length() && request->hasHeader(F("If-None-Match")) && request->header(F("If-None-Match")).equals(etag)) {
|
|
||||||
request->_tempFile.close();
|
|
||||||
AsyncWebServerResponse * response = new AsyncBasicResponse(304); // Not modified
|
|
||||||
response->addHeader(F("Cache-Control"), _cache_control);
|
|
||||||
response->addHeader(F("ETag"), etag);
|
|
||||||
request->send(response);
|
|
||||||
} else {
|
|
||||||
AsyncWebServerResponse * response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback);
|
|
||||||
if (_last_modified.length())
|
|
||||||
response->addHeader(F("Last-Modified"), _last_modified);
|
|
||||||
if (_cache_control.length()){
|
|
||||||
response->addHeader(F("Cache-Control"), _cache_control);
|
|
||||||
response->addHeader(F("ETag"), etag);
|
|
||||||
}
|
|
||||||
request->send(response);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
request->send(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef ASYNCWEBSERVERRESPONSEIMPL_H_
|
|
||||||
#define ASYNCWEBSERVERRESPONSEIMPL_H_
|
|
||||||
|
|
||||||
#ifdef Arduino_h
|
|
||||||
// arduino is not compatible with std::vector
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
#endif
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
|
|
||||||
|
|
||||||
class AsyncBasicResponse : public AsyncWebServerResponse {
|
|
||||||
private:
|
|
||||||
String _content;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncBasicResponse(int code, const String & contentType = String(), const String & content = String());
|
|
||||||
void _respond(AsyncWebServerRequest * request);
|
|
||||||
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncAbstractResponse : public AsyncWebServerResponse {
|
|
||||||
private:
|
|
||||||
String _head;
|
|
||||||
// Data is inserted into cache at begin().
|
|
||||||
// This is inefficient with vector, but if we use some other container,
|
|
||||||
// we won't be able to access it as contiguous array of bytes when reading from it,
|
|
||||||
// so by gaining performance in one place, we'll lose it in another.
|
|
||||||
std::vector<uint8_t> _cache;
|
|
||||||
size_t _readDataFromCacheOrContent(uint8_t * data, const size_t len);
|
|
||||||
size_t _fillBufferAndProcessTemplates(uint8_t * buf, size_t maxLen);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AwsTemplateProcessor _callback;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
|
|
||||||
void _respond(AsyncWebServerRequest * request);
|
|
||||||
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf __attribute__((unused)), size_t maxLen __attribute__((unused))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef TEMPLATE_PLACEHOLDER
|
|
||||||
#define TEMPLATE_PLACEHOLDER '%'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TEMPLATE_PARAM_NAME_LENGTH 32
|
|
||||||
class AsyncFileResponse : public AsyncAbstractResponse {
|
|
||||||
using File = fs::File;
|
|
||||||
using FS = fs::FS;
|
|
||||||
|
|
||||||
private:
|
|
||||||
File _content;
|
|
||||||
String _path;
|
|
||||||
void _setContentType(const String & path);
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncFileResponse(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
AsyncFileResponse(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
|
||||||
~AsyncFileResponse();
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return !!(_content);
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncStreamResponse : public AsyncAbstractResponse {
|
|
||||||
private:
|
|
||||||
Stream * _content;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return !!(_content);
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncCallbackResponse : public AsyncAbstractResponse {
|
|
||||||
private:
|
|
||||||
AwsResponseFiller _content;
|
|
||||||
size_t _filledLength;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return !!(_content);
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncChunkedResponse : public AsyncAbstractResponse {
|
|
||||||
private:
|
|
||||||
AwsResponseFiller _content;
|
|
||||||
size_t _filledLength;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return !!(_content);
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncProgmemResponse : public AsyncAbstractResponse {
|
|
||||||
private:
|
|
||||||
const uint8_t * _content;
|
|
||||||
size_t _readLength;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class cbuf;
|
|
||||||
|
|
||||||
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
|
|
||||||
private:
|
|
||||||
std::unique_ptr<cbuf> _content;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncResponseStream(const String & contentType, size_t bufferSize);
|
|
||||||
~AsyncResponseStream();
|
|
||||||
bool _sourceValid() const {
|
|
||||||
return (_state < RESPONSE_END);
|
|
||||||
}
|
|
||||||
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
|
|
||||||
size_t write(const uint8_t * data, size_t len);
|
|
||||||
size_t write(uint8_t data);
|
|
||||||
using Print::write;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* ASYNCWEBSERVERRESPONSEIMPL_H_ */
|
|
||||||
@@ -1,781 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "ESPAsyncWebServer.h"
|
|
||||||
#include "WebResponseImpl.h"
|
|
||||||
#include "cbuf.h"
|
|
||||||
|
|
||||||
// Since ESP8266 does not link memchr by default, here's its implementation.
|
|
||||||
void * memchr(void * ptr, int ch, size_t count) {
|
|
||||||
unsigned char * p = static_cast<unsigned char *>(ptr);
|
|
||||||
while (count--)
|
|
||||||
if (*p++ == static_cast<unsigned char>(ch))
|
|
||||||
return --p;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abstract Response
|
|
||||||
* */
|
|
||||||
const char * AsyncWebServerResponse::_responseCodeToString(int code) {
|
|
||||||
return reinterpret_cast<const char *>(responseCodeToString(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
const __FlashStringHelper * AsyncWebServerResponse::responseCodeToString(int code) {
|
|
||||||
switch (code) {
|
|
||||||
case 100:
|
|
||||||
return F("Continue");
|
|
||||||
case 101:
|
|
||||||
return F("Switching Protocols");
|
|
||||||
case 200:
|
|
||||||
return F("OK");
|
|
||||||
case 201:
|
|
||||||
return F("Created");
|
|
||||||
case 202:
|
|
||||||
return F("Accepted");
|
|
||||||
case 203:
|
|
||||||
return F("Non-Authoritative Information");
|
|
||||||
case 204:
|
|
||||||
return F("No Content");
|
|
||||||
case 205:
|
|
||||||
return F("Reset Content");
|
|
||||||
case 206:
|
|
||||||
return F("Partial Content");
|
|
||||||
case 300:
|
|
||||||
return F("Multiple Choices");
|
|
||||||
case 301:
|
|
||||||
return F("Moved Permanently");
|
|
||||||
case 302:
|
|
||||||
return F("Found");
|
|
||||||
case 303:
|
|
||||||
return F("See Other");
|
|
||||||
case 304:
|
|
||||||
return F("Not Modified");
|
|
||||||
case 305:
|
|
||||||
return F("Use Proxy");
|
|
||||||
case 307:
|
|
||||||
return F("Temporary Redirect");
|
|
||||||
case 400:
|
|
||||||
return F("Bad Request");
|
|
||||||
case 401:
|
|
||||||
return F("Unauthorized");
|
|
||||||
case 402:
|
|
||||||
return F("Payment Required");
|
|
||||||
case 403:
|
|
||||||
return F("Forbidden");
|
|
||||||
case 404:
|
|
||||||
return F("Not Found");
|
|
||||||
case 405:
|
|
||||||
return F("Method Not Allowed");
|
|
||||||
case 406:
|
|
||||||
return F("Not Acceptable");
|
|
||||||
case 407:
|
|
||||||
return F("Proxy Authentication Required");
|
|
||||||
case 408:
|
|
||||||
return F("Request Time-out");
|
|
||||||
case 409:
|
|
||||||
return F("Conflict");
|
|
||||||
case 410:
|
|
||||||
return F("Gone");
|
|
||||||
case 411:
|
|
||||||
return F("Length Required");
|
|
||||||
case 412:
|
|
||||||
return F("Precondition Failed");
|
|
||||||
case 413:
|
|
||||||
return F("Request Entity Too Large");
|
|
||||||
case 414:
|
|
||||||
return F("Request-URI Too Large");
|
|
||||||
case 415:
|
|
||||||
return F("Unsupported Media Type");
|
|
||||||
case 416:
|
|
||||||
return F("Requested range not satisfiable");
|
|
||||||
case 417:
|
|
||||||
return F("Expectation Failed");
|
|
||||||
case 500:
|
|
||||||
return F("Internal Server Error");
|
|
||||||
case 501:
|
|
||||||
return F("Not Implemented");
|
|
||||||
case 502:
|
|
||||||
return F("Bad Gateway");
|
|
||||||
case 503:
|
|
||||||
return F("Service Unavailable");
|
|
||||||
case 504:
|
|
||||||
return F("Gateway Time-out");
|
|
||||||
case 505:
|
|
||||||
return F("HTTP Version not supported");
|
|
||||||
default:
|
|
||||||
return F("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebServerResponse::AsyncWebServerResponse()
|
|
||||||
: _code(0)
|
|
||||||
, _contentType()
|
|
||||||
, _contentLength(0)
|
|
||||||
, _sendContentLength(true)
|
|
||||||
, _chunked(false)
|
|
||||||
, _headLength(0)
|
|
||||||
, _sentLength(0)
|
|
||||||
, _ackedLength(0)
|
|
||||||
, _writtenLength(0)
|
|
||||||
, _state(RESPONSE_SETUP) {
|
|
||||||
for (const auto & header : DefaultHeaders::Instance()) {
|
|
||||||
_headers.emplace_back(header);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebServerResponse::~AsyncWebServerResponse() = default;
|
|
||||||
|
|
||||||
void AsyncWebServerResponse::setCode(int code) {
|
|
||||||
if (_state == RESPONSE_SETUP)
|
|
||||||
_code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServerResponse::setContentLength(size_t len) {
|
|
||||||
if (_state == RESPONSE_SETUP)
|
|
||||||
_contentLength = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServerResponse::setContentType(const String & type) {
|
|
||||||
if (_state == RESPONSE_SETUP)
|
|
||||||
_contentType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServerResponse::addHeader(const String & name, const String & value) {
|
|
||||||
_headers.emplace_back(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
String AsyncWebServerResponse::_assembleHead(uint8_t version) {
|
|
||||||
if (version) {
|
|
||||||
addHeader(F("Accept-Ranges"), F("none"));
|
|
||||||
if (_chunked)
|
|
||||||
addHeader(F("Transfer-Encoding"), F("chunked"));
|
|
||||||
}
|
|
||||||
String out = String();
|
|
||||||
int bufSize = 300;
|
|
||||||
char buf[bufSize];
|
|
||||||
|
|
||||||
snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d %s\r\n"), version, _code, _responseCodeToString(_code));
|
|
||||||
out.concat(buf);
|
|
||||||
|
|
||||||
if (_sendContentLength) {
|
|
||||||
snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength);
|
|
||||||
out.concat(buf);
|
|
||||||
}
|
|
||||||
if (_contentType.length()) {
|
|
||||||
snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str());
|
|
||||||
out.concat(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto & header : _headers) {
|
|
||||||
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str());
|
|
||||||
out.concat(buf);
|
|
||||||
}
|
|
||||||
_headers.clear();
|
|
||||||
|
|
||||||
out.concat(F("\r\n"));
|
|
||||||
_headLength = out.length();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncWebServerResponse::_started() const {
|
|
||||||
return _state > RESPONSE_SETUP;
|
|
||||||
}
|
|
||||||
bool AsyncWebServerResponse::_finished() const {
|
|
||||||
return _state > RESPONSE_WAIT_ACK;
|
|
||||||
}
|
|
||||||
bool AsyncWebServerResponse::_failed() const {
|
|
||||||
return _state == RESPONSE_FAILED;
|
|
||||||
}
|
|
||||||
bool AsyncWebServerResponse::_sourceValid() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void AsyncWebServerResponse::_respond(AsyncWebServerRequest * request) {
|
|
||||||
_state = RESPONSE_END;
|
|
||||||
request->client()->close();
|
|
||||||
}
|
|
||||||
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest * request, size_t len, uint32_t time) {
|
|
||||||
(void)request;
|
|
||||||
(void)len;
|
|
||||||
(void)time;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* String/Code Response
|
|
||||||
* */
|
|
||||||
AsyncBasicResponse::AsyncBasicResponse(int code, const String & contentType, const String & content) {
|
|
||||||
_code = code;
|
|
||||||
_content = content;
|
|
||||||
_contentType = contentType;
|
|
||||||
if (_content.length()) {
|
|
||||||
_contentLength = _content.length();
|
|
||||||
if (!_contentType.length())
|
|
||||||
_contentType = F("text/plain");
|
|
||||||
}
|
|
||||||
addHeader(F("Connection"), F("close"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncBasicResponse::_respond(AsyncWebServerRequest * request) {
|
|
||||||
_state = RESPONSE_HEADERS;
|
|
||||||
String out = _assembleHead(request->version());
|
|
||||||
size_t outLen = out.length();
|
|
||||||
size_t space = request->client()->space();
|
|
||||||
if (!_contentLength && space >= outLen) {
|
|
||||||
_writtenLength += request->client()->write(out.c_str(), outLen);
|
|
||||||
_state = RESPONSE_WAIT_ACK;
|
|
||||||
} else if (_contentLength && space >= outLen + _contentLength) {
|
|
||||||
out += _content;
|
|
||||||
outLen += _contentLength;
|
|
||||||
_writtenLength += request->client()->write(out.c_str(), outLen);
|
|
||||||
_state = RESPONSE_WAIT_ACK;
|
|
||||||
} else if (space && space < outLen) {
|
|
||||||
String partial = out.substring(0, space);
|
|
||||||
_content = out.substring(space) + _content;
|
|
||||||
_contentLength += outLen - space;
|
|
||||||
_writtenLength += request->client()->write(partial.c_str(), partial.length());
|
|
||||||
_state = RESPONSE_CONTENT;
|
|
||||||
} else if (space > outLen && space < (outLen + _contentLength)) {
|
|
||||||
size_t shift = space - outLen;
|
|
||||||
outLen += shift;
|
|
||||||
_sentLength += shift;
|
|
||||||
out += _content.substring(0, shift);
|
|
||||||
_content = _content.substring(shift);
|
|
||||||
_writtenLength += request->client()->write(out.c_str(), outLen);
|
|
||||||
_state = RESPONSE_CONTENT;
|
|
||||||
} else {
|
|
||||||
_content = out + _content;
|
|
||||||
_contentLength += outLen;
|
|
||||||
_state = RESPONSE_CONTENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncBasicResponse::_ack(AsyncWebServerRequest * request, size_t len, uint32_t time) {
|
|
||||||
(void)time;
|
|
||||||
_ackedLength += len;
|
|
||||||
if (_state == RESPONSE_CONTENT) {
|
|
||||||
size_t available = _contentLength - _sentLength;
|
|
||||||
size_t space = request->client()->space();
|
|
||||||
//we can fit in this packet
|
|
||||||
if (space > available) {
|
|
||||||
_writtenLength += request->client()->write(_content.c_str(), available);
|
|
||||||
_content = String();
|
|
||||||
_state = RESPONSE_WAIT_ACK;
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
//send some data, the rest on ack
|
|
||||||
String out = _content.substring(0, space);
|
|
||||||
_content = _content.substring(space);
|
|
||||||
_sentLength += space;
|
|
||||||
_writtenLength += request->client()->write(out.c_str(), space);
|
|
||||||
return space;
|
|
||||||
} else if (_state == RESPONSE_WAIT_ACK) {
|
|
||||||
if (_ackedLength >= _writtenLength) {
|
|
||||||
_state = RESPONSE_END;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abstract Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback)
|
|
||||||
: _callback(callback) {
|
|
||||||
// In case of template processing, we're unable to determine real response size
|
|
||||||
if (callback) {
|
|
||||||
_contentLength = 0;
|
|
||||||
_sendContentLength = false;
|
|
||||||
_chunked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncAbstractResponse::_respond(AsyncWebServerRequest * request) {
|
|
||||||
addHeader(F("Connection"), F("close"));
|
|
||||||
_head = _assembleHead(request->version());
|
|
||||||
_state = RESPONSE_HEADERS;
|
|
||||||
_ack(request, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest * request, size_t len, uint32_t time) {
|
|
||||||
(void)time;
|
|
||||||
if (!_sourceValid()) {
|
|
||||||
_state = RESPONSE_FAILED;
|
|
||||||
request->client()->close();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ackedLength += len;
|
|
||||||
size_t space = request->client()->space();
|
|
||||||
|
|
||||||
size_t headLen = _head.length();
|
|
||||||
if (_state == RESPONSE_HEADERS) {
|
|
||||||
if (space >= headLen) {
|
|
||||||
_state = RESPONSE_CONTENT;
|
|
||||||
space -= headLen;
|
|
||||||
} else {
|
|
||||||
String out = _head.substring(0, space);
|
|
||||||
_head = _head.substring(space);
|
|
||||||
_writtenLength += request->client()->write(out.c_str(), out.length());
|
|
||||||
return out.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_state == RESPONSE_CONTENT) {
|
|
||||||
size_t outLen;
|
|
||||||
if (_chunked) {
|
|
||||||
if (space <= 8) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
outLen = space;
|
|
||||||
} else if (!_sendContentLength) {
|
|
||||||
outLen = space;
|
|
||||||
} else {
|
|
||||||
outLen = ((_contentLength - _sentLength) > space) ? space : (_contentLength - _sentLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t * buf = (uint8_t *)malloc(outLen + headLen);
|
|
||||||
if (!buf) {
|
|
||||||
// os_printf("_ack malloc %d failed\n", outLen+headLen);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headLen) {
|
|
||||||
memcpy(buf, _head.c_str(), _head.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t readLen = 0;
|
|
||||||
|
|
||||||
if (_chunked) {
|
|
||||||
// HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added.
|
|
||||||
// See RFC2616 sections 2, 3.6.1.
|
|
||||||
readLen = _fillBufferAndProcessTemplates(buf + headLen + 6, outLen - 8);
|
|
||||||
if (readLen == RESPONSE_TRY_AGAIN) {
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
outLen = sprintf_P((char *)buf + headLen, PSTR("%x"), readLen) + headLen;
|
|
||||||
while (outLen < headLen + 4)
|
|
||||||
buf[outLen++] = ' ';
|
|
||||||
buf[outLen++] = '\r';
|
|
||||||
buf[outLen++] = '\n';
|
|
||||||
outLen += readLen;
|
|
||||||
buf[outLen++] = '\r';
|
|
||||||
buf[outLen++] = '\n';
|
|
||||||
} else {
|
|
||||||
readLen = _fillBufferAndProcessTemplates(buf + headLen, outLen);
|
|
||||||
if (readLen == RESPONSE_TRY_AGAIN) {
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
outLen = readLen + headLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headLen) {
|
|
||||||
_head = String();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outLen) {
|
|
||||||
_writtenLength += request->client()->write((const char *)buf, outLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_chunked) {
|
|
||||||
_sentLength += readLen;
|
|
||||||
} else {
|
|
||||||
_sentLength += outLen - headLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
if ((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || (!_chunked && _sentLength == _contentLength)) {
|
|
||||||
_state = RESPONSE_WAIT_ACK;
|
|
||||||
}
|
|
||||||
return outLen;
|
|
||||||
|
|
||||||
} else if (_state == RESPONSE_WAIT_ACK) {
|
|
||||||
if (!_sendContentLength || _ackedLength >= _writtenLength) {
|
|
||||||
_state = RESPONSE_END;
|
|
||||||
if (!_chunked && !_sendContentLength)
|
|
||||||
request->client()->close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t * data, const size_t len) {
|
|
||||||
// If we have something in cache, copy it to buffer
|
|
||||||
const size_t readFromCache = std::min(len, _cache.size());
|
|
||||||
if (readFromCache) {
|
|
||||||
memcpy(data, _cache.data(), readFromCache);
|
|
||||||
_cache.erase(_cache.begin(), _cache.begin() + readFromCache);
|
|
||||||
}
|
|
||||||
// If we need to read more...
|
|
||||||
const size_t needFromFile = len - readFromCache;
|
|
||||||
const size_t readFromContent = _fillBuffer(data + readFromCache, needFromFile);
|
|
||||||
return readFromCache + readFromContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t * data, size_t len) {
|
|
||||||
if (!_callback)
|
|
||||||
return _fillBuffer(data, len);
|
|
||||||
|
|
||||||
const size_t originalLen = len;
|
|
||||||
len = _readDataFromCacheOrContent(data, len);
|
|
||||||
// Now we've read 'len' bytes, either from cache or from file
|
|
||||||
// Search for template placeholders
|
|
||||||
uint8_t * pTemplateStart = data;
|
|
||||||
while ((pTemplateStart < &data[len])
|
|
||||||
&& (pTemplateStart = (uint8_t *)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1]
|
|
||||||
uint8_t * pTemplateEnd =
|
|
||||||
(pTemplateStart < &data[len - 1]) ? (uint8_t *)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr;
|
|
||||||
// temporary buffer to hold parameter name
|
|
||||||
uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1];
|
|
||||||
String paramName;
|
|
||||||
// If closing placeholder is found:
|
|
||||||
if (pTemplateEnd) {
|
|
||||||
// prepare argument to callback
|
|
||||||
const size_t paramNameLength = std::min((size_t)sizeof(buf) - 1, (size_t)(pTemplateEnd - pTemplateStart - 1));
|
|
||||||
if (paramNameLength) {
|
|
||||||
memcpy(buf, pTemplateStart + 1, paramNameLength);
|
|
||||||
buf[paramNameLength] = 0;
|
|
||||||
paramName = String(reinterpret_cast<char *>(buf));
|
|
||||||
} else { // double percent sign encountered, this is single percent sign escaped.
|
|
||||||
// remove the 2nd percent sign
|
|
||||||
memmove(pTemplateEnd, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1);
|
|
||||||
len += _readDataFromCacheOrContent(&data[len - 1], 1) - 1;
|
|
||||||
++pTemplateStart;
|
|
||||||
}
|
|
||||||
} else if (&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data
|
|
||||||
memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart);
|
|
||||||
const size_t readFromCacheOrContent =
|
|
||||||
_readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1));
|
|
||||||
if (readFromCacheOrContent) {
|
|
||||||
pTemplateEnd = (uint8_t *)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent);
|
|
||||||
if (pTemplateEnd) {
|
|
||||||
// prepare argument to callback
|
|
||||||
*pTemplateEnd = 0;
|
|
||||||
paramName = String(reinterpret_cast<char *>(buf));
|
|
||||||
// Copy remaining read-ahead data into cache
|
|
||||||
_cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
|
||||||
pTemplateEnd = &data[len - 1];
|
|
||||||
} else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
|
|
||||||
{
|
|
||||||
// but first, store read file data in cache
|
|
||||||
_cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
|
||||||
++pTemplateStart;
|
|
||||||
}
|
|
||||||
} else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
|
|
||||||
++pTemplateStart;
|
|
||||||
} else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
|
|
||||||
++pTemplateStart;
|
|
||||||
if (paramName.length()) {
|
|
||||||
// call callback and replace with result.
|
|
||||||
// Everything in range [pTemplateStart, pTemplateEnd] can be safely replaced with parameter value.
|
|
||||||
// Data after pTemplateEnd may need to be moved.
|
|
||||||
// The first byte of data after placeholder is located at pTemplateEnd + 1.
|
|
||||||
// It should be located at pTemplateStart + numBytesCopied (to begin right after inserted parameter value).
|
|
||||||
const String paramValue(_callback(paramName));
|
|
||||||
const char * pvstr = paramValue.c_str();
|
|
||||||
const unsigned int pvlen = paramValue.length();
|
|
||||||
const size_t numBytesCopied = std::min(pvlen, static_cast<unsigned int>(&data[originalLen - 1] - pTemplateStart + 1));
|
|
||||||
// make room for param value
|
|
||||||
// 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store
|
|
||||||
if ((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) {
|
|
||||||
_cache.insert(_cache.begin(), &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]);
|
|
||||||
//2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end
|
|
||||||
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied);
|
|
||||||
len = originalLen; // fix issue with truncated data, not sure if it has any side effects
|
|
||||||
} else if (pTemplateEnd + 1 != pTemplateStart + numBytesCopied)
|
|
||||||
//2. Either parameter value is shorter than placeholder text OR there is enough free space in buffer to fit.
|
|
||||||
// Move the entire data after the placeholder
|
|
||||||
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1);
|
|
||||||
// 3. replace placeholder with actual value
|
|
||||||
memcpy(pTemplateStart, pvstr, numBytesCopied);
|
|
||||||
// If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer)
|
|
||||||
if (numBytesCopied < pvlen) {
|
|
||||||
_cache.insert(_cache.begin(), pvstr + numBytesCopied, pvstr + pvlen);
|
|
||||||
} else if (pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text...
|
|
||||||
// there is some free room, fill it from cache
|
|
||||||
const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied;
|
|
||||||
const size_t totalFreeRoom = originalLen - len + roomFreed;
|
|
||||||
len += _readDataFromCacheOrContent(&data[len - roomFreed], totalFreeRoom) - roomFreed;
|
|
||||||
} else { // result is copied fully; it is longer than placeholder text
|
|
||||||
const size_t roomTaken = pTemplateStart + numBytesCopied - pTemplateEnd - 1;
|
|
||||||
len = std::min(len + roomTaken, originalLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // while(pTemplateStart)
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* File Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncFileResponse::~AsyncFileResponse() {
|
|
||||||
if (_content)
|
|
||||||
_content.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncFileResponse::_setContentType(const String & path) {
|
|
||||||
#if HAVE_EXTERN_GET_CONTENT_TYPE_FUNCTION
|
|
||||||
extern const __FlashStringHelper * getContentType(const String & path);
|
|
||||||
_contentType = getContentType(path);
|
|
||||||
#else
|
|
||||||
if (path.endsWith(F(".html")))
|
|
||||||
_contentType = F("text/html");
|
|
||||||
else if (path.endsWith(F(".htm")))
|
|
||||||
_contentType = F("text/html");
|
|
||||||
else if (path.endsWith(F(".css")))
|
|
||||||
_contentType = F("text/css");
|
|
||||||
else if (path.endsWith(F(".json")))
|
|
||||||
_contentType = F("application/json");
|
|
||||||
else if (path.endsWith(F(".js")))
|
|
||||||
_contentType = F("application/javascript");
|
|
||||||
else if (path.endsWith(F(".png")))
|
|
||||||
_contentType = F("image/png");
|
|
||||||
else if (path.endsWith(F(".gif")))
|
|
||||||
_contentType = F("image/gif");
|
|
||||||
else if (path.endsWith(F(".jpg")))
|
|
||||||
_contentType = F("image/jpeg");
|
|
||||||
else if (path.endsWith(F(".ico")))
|
|
||||||
_contentType = F("image/x-icon");
|
|
||||||
else if (path.endsWith(F(".svg")))
|
|
||||||
_contentType = F("image/svg+xml");
|
|
||||||
else if (path.endsWith(F(".eot")))
|
|
||||||
_contentType = F("font/eot");
|
|
||||||
else if (path.endsWith(F(".woff")))
|
|
||||||
_contentType = F("font/woff");
|
|
||||||
else if (path.endsWith(F(".woff2")))
|
|
||||||
_contentType = F("font/woff2");
|
|
||||||
else if (path.endsWith(F(".ttf")))
|
|
||||||
_contentType = F("font/ttf");
|
|
||||||
else if (path.endsWith(F(".xml")))
|
|
||||||
_contentType = F("text/xml");
|
|
||||||
else if (path.endsWith(F(".pdf")))
|
|
||||||
_contentType = F("application/pdf");
|
|
||||||
else if (path.endsWith(F(".zip")))
|
|
||||||
_contentType = F("application/zip");
|
|
||||||
else if (path.endsWith(F(".gz")))
|
|
||||||
_contentType = F("application/x-gzip");
|
|
||||||
else
|
|
||||||
_contentType = F("text/plain");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncFileResponse::AsyncFileResponse(FS & fs, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback)
|
|
||||||
: AsyncAbstractResponse(callback) {
|
|
||||||
_code = 200;
|
|
||||||
_path = path;
|
|
||||||
|
|
||||||
if (!download && !fs.exists(_path) && fs.exists(_path + F(".gz"))) {
|
|
||||||
_path = _path + F(".gz");
|
|
||||||
addHeader(F("Content-Encoding"), F("gzip"));
|
|
||||||
_callback = nullptr; // Unable to process zipped templates
|
|
||||||
_sendContentLength = true;
|
|
||||||
_chunked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_content = fs.open(_path, fs::FileOpenMode::read);
|
|
||||||
_contentLength = _content.size();
|
|
||||||
|
|
||||||
if (contentType.length() == 0)
|
|
||||||
_setContentType(path);
|
|
||||||
else
|
|
||||||
_contentType = contentType;
|
|
||||||
|
|
||||||
int filenameStart = path.lastIndexOf('/') + 1;
|
|
||||||
char buf[26 + path.length() - filenameStart];
|
|
||||||
char * filename = (char *)path.c_str() + filenameStart;
|
|
||||||
|
|
||||||
if (download) {
|
|
||||||
// set filename and force download
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("attachment; filename=\"%s\""), filename);
|
|
||||||
} else {
|
|
||||||
// set filename and force rendering
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("inline; filename=\"%s\""), filename);
|
|
||||||
}
|
|
||||||
addHeader(F("Content-Disposition"), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncFileResponse::AsyncFileResponse(File content, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback)
|
|
||||||
: AsyncAbstractResponse(callback) {
|
|
||||||
_code = 200;
|
|
||||||
_path = path;
|
|
||||||
|
|
||||||
if (!download && String(content.name()).endsWith(F(".gz")) && !path.endsWith(F(".gz"))) {
|
|
||||||
addHeader(F("Content-Encoding"), F("gzip"));
|
|
||||||
_callback = nullptr; // Unable to process gzipped templates
|
|
||||||
_sendContentLength = true;
|
|
||||||
_chunked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_content = content;
|
|
||||||
_contentLength = _content.size();
|
|
||||||
|
|
||||||
if (contentType.length() == 0)
|
|
||||||
_setContentType(path);
|
|
||||||
else
|
|
||||||
_contentType = contentType;
|
|
||||||
|
|
||||||
int filenameStart = path.lastIndexOf('/') + 1;
|
|
||||||
char buf[26 + path.length() - filenameStart];
|
|
||||||
char * filename = (char *)path.c_str() + filenameStart;
|
|
||||||
|
|
||||||
if (download) {
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("attachment; filename=\"%s\""), filename);
|
|
||||||
} else {
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("inline; filename=\"%s\""), filename);
|
|
||||||
}
|
|
||||||
addHeader(F("Content-Disposition"), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncFileResponse::_fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
return _content.read(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stream Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncStreamResponse::AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback)
|
|
||||||
: AsyncAbstractResponse(callback) {
|
|
||||||
_code = 200;
|
|
||||||
_content = &stream;
|
|
||||||
_contentLength = len;
|
|
||||||
_contentType = contentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncStreamResponse::_fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
size_t available = _content->available();
|
|
||||||
size_t outLen = (available > len) ? len : available;
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < outLen; i++)
|
|
||||||
data[i] = _content->read();
|
|
||||||
return outLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Callback Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncCallbackResponse::AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback)
|
|
||||||
: AsyncAbstractResponse(templateCallback) {
|
|
||||||
_code = 200;
|
|
||||||
_content = callback;
|
|
||||||
_contentLength = len;
|
|
||||||
if (!len)
|
|
||||||
_sendContentLength = false;
|
|
||||||
_contentType = contentType;
|
|
||||||
_filledLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncCallbackResponse::_fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
size_t ret = _content(data, len, _filledLength);
|
|
||||||
if (ret != RESPONSE_TRY_AGAIN) {
|
|
||||||
_filledLength += ret;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Chunked Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncChunkedResponse::AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback)
|
|
||||||
: AsyncAbstractResponse(processorCallback) {
|
|
||||||
_code = 200;
|
|
||||||
_content = callback;
|
|
||||||
_contentLength = 0;
|
|
||||||
_contentType = contentType;
|
|
||||||
_sendContentLength = false;
|
|
||||||
_chunked = true;
|
|
||||||
_filledLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncChunkedResponse::_fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
size_t ret = _content(data, len, _filledLength);
|
|
||||||
if (ret != RESPONSE_TRY_AGAIN) {
|
|
||||||
_filledLength += ret;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Progmem Response
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncProgmemResponse::AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback)
|
|
||||||
: AsyncAbstractResponse(callback) {
|
|
||||||
_code = code;
|
|
||||||
_content = content;
|
|
||||||
_contentType = contentType;
|
|
||||||
_contentLength = len;
|
|
||||||
_readLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncProgmemResponse::_fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
size_t left = _contentLength - _readLength;
|
|
||||||
if (left > len) {
|
|
||||||
memcpy_P(data, _content + _readLength, len);
|
|
||||||
_readLength += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
memcpy_P(data, _content + _readLength, left);
|
|
||||||
_readLength += left;
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Response Stream (You can print/write/printf to it, up to the contentLen bytes)
|
|
||||||
* */
|
|
||||||
|
|
||||||
AsyncResponseStream::AsyncResponseStream(const String & contentType, size_t bufferSize) {
|
|
||||||
_code = 200;
|
|
||||||
_contentLength = 0;
|
|
||||||
_contentType = contentType;
|
|
||||||
_content = std::unique_ptr<cbuf>(new cbuf(bufferSize)); //std::make_unique<cbuf>(bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncResponseStream::~AsyncResponseStream() = default;
|
|
||||||
|
|
||||||
size_t AsyncResponseStream::_fillBuffer(uint8_t * buf, size_t maxLen) {
|
|
||||||
return _content->read((char *)buf, maxLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncResponseStream::write(const uint8_t * data, size_t len) {
|
|
||||||
if (_started())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (len > _content->room()) {
|
|
||||||
size_t needed = len - _content->room();
|
|
||||||
_content->resizeAdd(needed);
|
|
||||||
}
|
|
||||||
size_t written = _content->write((const char *)data, len);
|
|
||||||
_contentLength += written;
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AsyncResponseStream::write(uint8_t data) {
|
|
||||||
return write(&data, 1);
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
Asynchronous WebServer library for Espressif MCUs
|
|
||||||
|
|
||||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include "ESPAsyncWebServer.h"
|
|
||||||
#include "WebHandlerImpl.h"
|
|
||||||
#include "AsyncJson.h"
|
|
||||||
|
|
||||||
bool ON_STA_FILTER(AsyncWebServerRequest * request) {
|
|
||||||
return WiFi.localIP() == request->client()->localIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ON_AP_FILTER(AsyncWebServerRequest * request) {
|
|
||||||
return WiFi.localIP() != request->client()->localIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef HAVE_FS_FILE_OPEN_MODE
|
|
||||||
const char * fs::FileOpenMode::read = "r";
|
|
||||||
const char * fs::FileOpenMode::write = "w";
|
|
||||||
const char * fs::FileOpenMode::append = "a";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AsyncWebServer::AsyncWebServer(uint16_t port)
|
|
||||||
: _server(port)
|
|
||||||
, _rewrites(LinkedList<AsyncWebRewrite *>([](AsyncWebRewrite * r) { delete r; }))
|
|
||||||
, _handlers(LinkedList<AsyncWebHandler *>([](AsyncWebHandler * h) { delete h; })) {
|
|
||||||
_catchAllHandler = new AsyncCallbackWebHandler();
|
|
||||||
if (_catchAllHandler == NULL)
|
|
||||||
return;
|
|
||||||
_server.onClient(
|
|
||||||
[](void * s, AsyncClient * c) {
|
|
||||||
if (c == NULL)
|
|
||||||
return;
|
|
||||||
c->setRxTimeout(3);
|
|
||||||
AsyncWebServerRequest * r = new AsyncWebServerRequest((AsyncWebServer *)s, c);
|
|
||||||
if (r == NULL) {
|
|
||||||
c->close(true);
|
|
||||||
c->free();
|
|
||||||
delete c;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebServer::~AsyncWebServer() {
|
|
||||||
reset();
|
|
||||||
end();
|
|
||||||
if (_catchAllHandler)
|
|
||||||
delete _catchAllHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebRewrite & AsyncWebServer::addRewrite(AsyncWebRewrite * rewrite) {
|
|
||||||
_rewrites.add(rewrite);
|
|
||||||
return *rewrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncWebServer::removeRewrite(AsyncWebRewrite * rewrite) {
|
|
||||||
return _rewrites.remove(rewrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebRewrite & AsyncWebServer::rewrite(const char * from, const char * to) {
|
|
||||||
return addRewrite(new AsyncWebRewrite(from, to));
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncWebHandler & AsyncWebServer::addHandler(AsyncWebHandler * handler) {
|
|
||||||
_handlers.add(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncWebServer::removeHandler(AsyncWebHandler * handler) {
|
|
||||||
return _handlers.remove(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::begin() {
|
|
||||||
_server.setNoDelay(true);
|
|
||||||
_server.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::end() {
|
|
||||||
_server.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ASYNC_TCP_SSL_ENABLED
|
|
||||||
void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void * arg) {
|
|
||||||
_server.onSslFileRequest(cb, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::beginSecure(const char * cert, const char * key, const char * password) {
|
|
||||||
_server.beginSecure(cert, key, password);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest * request) {
|
|
||||||
delete request;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest * request) {
|
|
||||||
for (const auto & r : _rewrites) {
|
|
||||||
if (r->match(request)) {
|
|
||||||
request->_url = r->toUrl();
|
|
||||||
request->_addGetParams(r->params());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::_attachHandler(AsyncWebServerRequest * request) {
|
|
||||||
for (const auto & h : _handlers) {
|
|
||||||
if (h->filter(request) && h->canHandle(request)) {
|
|
||||||
request->setHandler(h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request->addInterestingHeader(F("ANY"));
|
|
||||||
request->setHandler(_catchAllHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri,
|
|
||||||
WebRequestMethodComposite method,
|
|
||||||
ArRequestHandlerFunction onRequest,
|
|
||||||
ArUploadHandlerFunction onUpload,
|
|
||||||
ArBodyHandlerFunction onBody) {
|
|
||||||
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
|
|
||||||
handler->setUri(uri);
|
|
||||||
handler->setMethod(method);
|
|
||||||
handler->onRequest(onRequest);
|
|
||||||
handler->onUpload(onUpload);
|
|
||||||
handler->onBody(onBody);
|
|
||||||
addHandler(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncCallbackWebHandler &
|
|
||||||
AsyncWebServer::on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload) {
|
|
||||||
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
|
|
||||||
handler->setUri(uri);
|
|
||||||
handler->setMethod(method);
|
|
||||||
handler->onRequest(onRequest);
|
|
||||||
handler->onUpload(onUpload);
|
|
||||||
addHandler(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {
|
|
||||||
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
|
|
||||||
handler->setUri(uri);
|
|
||||||
handler->setMethod(method);
|
|
||||||
handler->onRequest(onRequest);
|
|
||||||
addHandler(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri, ArRequestHandlerFunction onRequest) {
|
|
||||||
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
|
|
||||||
handler->setUri(uri);
|
|
||||||
handler->onRequest(onRequest);
|
|
||||||
addHandler(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// added by proddy for EMS-ESP
|
|
||||||
void AsyncWebServer::on(const char * uri, ArJsonRequestHandlerFunction onRequest) {
|
|
||||||
auto * handler = new AsyncCallbackJsonWebHandler(uri, onRequest);
|
|
||||||
addHandler(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncStaticWebHandler & AsyncWebServer::serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control) {
|
|
||||||
AsyncStaticWebHandler * handler = new AsyncStaticWebHandler(uri, fs, path, cache_control);
|
|
||||||
addHandler(handler);
|
|
||||||
return *handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn) {
|
|
||||||
_catchAllHandler->onRequest(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn) {
|
|
||||||
_catchAllHandler->onUpload(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn) {
|
|
||||||
_catchAllHandler->onBody(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncWebServer::reset() {
|
|
||||||
_rewrites.free();
|
|
||||||
_handlers.free();
|
|
||||||
|
|
||||||
if (_catchAllHandler != NULL) {
|
|
||||||
_catchAllHandler->onRequest(NULL);
|
|
||||||
_catchAllHandler->onUpload(NULL);
|
|
||||||
_catchAllHandler->onBody(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* FIPS-180-1 compliant SHA-1 implementation
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
||||||
* Modified for esp32 by Lucas Saavedra Vaz on 11 Jan 2024
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
|
|
||||||
#include "SHA1Builder.h"
|
|
||||||
|
|
||||||
// 32-bit integer manipulation macros (big endian)
|
|
||||||
|
|
||||||
#ifndef GET_UINT32_BE
|
|
||||||
#define GET_UINT32_BE(n, b, i) \
|
|
||||||
{ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PUT_UINT32_BE
|
|
||||||
#define PUT_UINT32_BE(n, b, i) \
|
|
||||||
{ \
|
|
||||||
(b)[(i)] = (uint8_t)((n) >> 24); \
|
|
||||||
(b)[(i) + 1] = (uint8_t)((n) >> 16); \
|
|
||||||
(b)[(i) + 2] = (uint8_t)((n) >> 8); \
|
|
||||||
(b)[(i) + 3] = (uint8_t)((n)); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
|
|
||||||
static const uint8_t sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
// Private methods
|
|
||||||
|
|
||||||
void SHA1Builder::process(const uint8_t * data) {
|
|
||||||
uint32_t temp, W[16], A, B, C, D, E;
|
|
||||||
|
|
||||||
GET_UINT32_BE(W[0], data, 0);
|
|
||||||
GET_UINT32_BE(W[1], data, 4);
|
|
||||||
GET_UINT32_BE(W[2], data, 8);
|
|
||||||
GET_UINT32_BE(W[3], data, 12);
|
|
||||||
GET_UINT32_BE(W[4], data, 16);
|
|
||||||
GET_UINT32_BE(W[5], data, 20);
|
|
||||||
GET_UINT32_BE(W[6], data, 24);
|
|
||||||
GET_UINT32_BE(W[7], data, 28);
|
|
||||||
GET_UINT32_BE(W[8], data, 32);
|
|
||||||
GET_UINT32_BE(W[9], data, 36);
|
|
||||||
GET_UINT32_BE(W[10], data, 40);
|
|
||||||
GET_UINT32_BE(W[11], data, 44);
|
|
||||||
GET_UINT32_BE(W[12], data, 48);
|
|
||||||
GET_UINT32_BE(W[13], data, 52);
|
|
||||||
GET_UINT32_BE(W[14], data, 56);
|
|
||||||
GET_UINT32_BE(W[15], data, 60);
|
|
||||||
|
|
||||||
#define sha1_S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
|
||||||
|
|
||||||
#define sha1_R(t) (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = sha1_S(temp, 1)))
|
|
||||||
|
|
||||||
#define sha1_P(a, b, c, d, e, x) \
|
|
||||||
{ \
|
|
||||||
e += sha1_S(a, 5) + sha1_F(b, c, d) + sha1_K + x; \
|
|
||||||
b = sha1_S(b, 30); \
|
|
||||||
}
|
|
||||||
|
|
||||||
A = state[0];
|
|
||||||
B = state[1];
|
|
||||||
C = state[2];
|
|
||||||
D = state[3];
|
|
||||||
E = state[4];
|
|
||||||
|
|
||||||
#define sha1_F(x, y, z) (z ^ (x & (y ^ z)))
|
|
||||||
#define sha1_K 0x5A827999
|
|
||||||
|
|
||||||
sha1_P(A, B, C, D, E, W[0]);
|
|
||||||
sha1_P(E, A, B, C, D, W[1]);
|
|
||||||
sha1_P(D, E, A, B, C, W[2]);
|
|
||||||
sha1_P(C, D, E, A, B, W[3]);
|
|
||||||
sha1_P(B, C, D, E, A, W[4]);
|
|
||||||
sha1_P(A, B, C, D, E, W[5]);
|
|
||||||
sha1_P(E, A, B, C, D, W[6]);
|
|
||||||
sha1_P(D, E, A, B, C, W[7]);
|
|
||||||
sha1_P(C, D, E, A, B, W[8]);
|
|
||||||
sha1_P(B, C, D, E, A, W[9]);
|
|
||||||
sha1_P(A, B, C, D, E, W[10]);
|
|
||||||
sha1_P(E, A, B, C, D, W[11]);
|
|
||||||
sha1_P(D, E, A, B, C, W[12]);
|
|
||||||
sha1_P(C, D, E, A, B, W[13]);
|
|
||||||
sha1_P(B, C, D, E, A, W[14]);
|
|
||||||
sha1_P(A, B, C, D, E, W[15]);
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(16));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(17));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(18));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(19));
|
|
||||||
|
|
||||||
#undef sha1_K
|
|
||||||
#undef sha1_F
|
|
||||||
|
|
||||||
#define sha1_F(x, y, z) (x ^ y ^ z)
|
|
||||||
#define sha1_K 0x6ED9EBA1
|
|
||||||
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(20));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(21));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(22));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(23));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(24));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(25));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(26));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(27));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(28));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(29));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(30));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(31));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(32));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(33));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(34));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(35));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(36));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(37));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(38));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(39));
|
|
||||||
|
|
||||||
#undef sha1_K
|
|
||||||
#undef sha1_F
|
|
||||||
|
|
||||||
#define sha1_F(x, y, z) ((x & y) | (z & (x | y)))
|
|
||||||
#define sha1_K 0x8F1BBCDC
|
|
||||||
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(40));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(41));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(42));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(43));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(44));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(45));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(46));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(47));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(48));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(49));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(50));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(51));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(52));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(53));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(54));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(55));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(56));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(57));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(58));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(59));
|
|
||||||
|
|
||||||
#undef sha1_K
|
|
||||||
#undef sha1_F
|
|
||||||
|
|
||||||
#define sha1_F(x, y, z) (x ^ y ^ z)
|
|
||||||
#define sha1_K 0xCA62C1D6
|
|
||||||
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(60));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(61));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(62));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(63));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(64));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(65));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(66));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(67));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(68));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(69));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(70));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(71));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(72));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(73));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(74));
|
|
||||||
sha1_P(A, B, C, D, E, sha1_R(75));
|
|
||||||
sha1_P(E, A, B, C, D, sha1_R(76));
|
|
||||||
sha1_P(D, E, A, B, C, sha1_R(77));
|
|
||||||
sha1_P(C, D, E, A, B, sha1_R(78));
|
|
||||||
sha1_P(B, C, D, E, A, sha1_R(79));
|
|
||||||
|
|
||||||
#undef sha1_K
|
|
||||||
#undef sha1_F
|
|
||||||
|
|
||||||
state[0] += A;
|
|
||||||
state[1] += B;
|
|
||||||
state[2] += C;
|
|
||||||
state[3] += D;
|
|
||||||
state[4] += E;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public methods
|
|
||||||
|
|
||||||
void SHA1Builder::begin(void) {
|
|
||||||
total[0] = 0;
|
|
||||||
total[1] = 0;
|
|
||||||
|
|
||||||
state[0] = 0x67452301;
|
|
||||||
state[1] = 0xEFCDAB89;
|
|
||||||
state[2] = 0x98BADCFE;
|
|
||||||
state[3] = 0x10325476;
|
|
||||||
state[4] = 0xC3D2E1F0;
|
|
||||||
|
|
||||||
memset(buffer, 0x00, sizeof(buffer));
|
|
||||||
memset(hash, 0x00, sizeof(hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHA1Builder::add(const uint8_t * data, size_t len) {
|
|
||||||
size_t fill;
|
|
||||||
uint32_t left;
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
left = total[0] & 0x3F;
|
|
||||||
fill = 64 - left;
|
|
||||||
|
|
||||||
total[0] += (uint32_t)len;
|
|
||||||
total[0] &= 0xFFFFFFFF;
|
|
||||||
|
|
||||||
if (total[0] < (uint32_t)len) {
|
|
||||||
total[1]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left && len >= fill) {
|
|
||||||
memcpy((void *)(buffer + left), data, fill);
|
|
||||||
process(buffer);
|
|
||||||
data += fill;
|
|
||||||
len -= fill;
|
|
||||||
left = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (len >= 64) {
|
|
||||||
process(data);
|
|
||||||
data += 64;
|
|
||||||
len -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
memcpy((void *)(buffer + left), data, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHA1Builder::calculate(void) {
|
|
||||||
uint32_t last, padn;
|
|
||||||
uint32_t high, low;
|
|
||||||
uint8_t msglen[8];
|
|
||||||
|
|
||||||
high = (total[0] >> 29) | (total[1] << 3);
|
|
||||||
low = (total[0] << 3);
|
|
||||||
|
|
||||||
PUT_UINT32_BE(high, msglen, 0);
|
|
||||||
PUT_UINT32_BE(low, msglen, 4);
|
|
||||||
|
|
||||||
last = total[0] & 0x3F;
|
|
||||||
padn = (last < 56) ? (56 - last) : (120 - last);
|
|
||||||
|
|
||||||
add((uint8_t *)sha1_padding, padn);
|
|
||||||
add(msglen, 8);
|
|
||||||
|
|
||||||
PUT_UINT32_BE(state[0], hash, 0);
|
|
||||||
PUT_UINT32_BE(state[1], hash, 4);
|
|
||||||
PUT_UINT32_BE(state[2], hash, 8);
|
|
||||||
PUT_UINT32_BE(state[3], hash, 12);
|
|
||||||
PUT_UINT32_BE(state[4], hash, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHA1Builder::getBytes(uint8_t * output) {
|
|
||||||
memcpy(output, hash, SHA1_HASH_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#ifndef SHA1Builder_h
|
|
||||||
#define SHA1Builder_h
|
|
||||||
|
|
||||||
#include <Stream.h>
|
|
||||||
#include <WString.h>
|
|
||||||
|
|
||||||
#define SHA1_HASH_SIZE 20
|
|
||||||
|
|
||||||
class SHA1Builder {
|
|
||||||
private:
|
|
||||||
uint32_t total[2]; /* number of bytes processed */
|
|
||||||
uint32_t state[5]; /* intermediate digest state */
|
|
||||||
unsigned char buffer[64]; /* data block being processed */
|
|
||||||
uint8_t hash[SHA1_HASH_SIZE]; /* SHA-1 result */
|
|
||||||
|
|
||||||
void process(const uint8_t * data);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void begin();
|
|
||||||
void add(const uint8_t * data, size_t len);
|
|
||||||
void calculate();
|
|
||||||
void getBytes(uint8_t * output);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SHA1Builder_h
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
name=OneWire
|
|
||||||
version=2.3.3
|
|
||||||
author=Jim Studt, Tom Pollard, Robin James, Glenn Trewitt, Jason Dangel, Guillermo Lovato, Paul Stoffregen, Scott Roberts, Bertrik Sikken, Mark Tillotson, Ken Butcher, Roger Clark, Love Nystrom
|
|
||||||
maintainer=Paul Stoffregen
|
|
||||||
sentence=Access 1-wire temperature sensors, memory and other chips.
|
|
||||||
paragraph= Mod of Paul Stoffregen code to support ESP32
|
|
||||||
category=Communication
|
|
||||||
url=http://www.pjrc.com/teensy/td_libs_OneWire.html
|
|
||||||
architectures=esp8266,esp32
|
|
||||||
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
#######################################
|
|
||||||
# Syntax Coloring Map For the current project.
|
|
||||||
# This file was generated by doxygen2keywords.xsl.
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Classes and structs (KEYWORD1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
ModbusServerTCP::ClientData KEYWORD1
|
|
||||||
CoilData KEYWORD1
|
|
||||||
Modbus::FCT KEYWORD1
|
|
||||||
ModbusBridge KEYWORD1
|
|
||||||
ModbusClient KEYWORD1
|
|
||||||
ModbusClientTCP KEYWORD1
|
|
||||||
ModbusClientRTU KEYWORD1
|
|
||||||
ModbusClientTCPasync KEYWORD1
|
|
||||||
ModbusError KEYWORD1
|
|
||||||
ModbusMessage KEYWORD1
|
|
||||||
ModbusServer KEYWORD1
|
|
||||||
ModbusServerTCP KEYWORD1
|
|
||||||
ModbusServerRTU KEYWORD1
|
|
||||||
ModbusServerTCPasync KEYWORD1
|
|
||||||
RTUutils KEYWORD1
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Methods (KEYWORD2)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
ClientData KEYWORD2
|
|
||||||
~ClientData KEYWORD2
|
|
||||||
CoilData KEYWORD2
|
|
||||||
~CoilData KEYWORD2
|
|
||||||
coils KEYWORD2
|
|
||||||
coilsSetON KEYWORD2
|
|
||||||
coilsSetOFF KEYWORD2
|
|
||||||
FCT KEYWORD2
|
|
||||||
getType KEYWORD2
|
|
||||||
redefineType KEYWORD2
|
|
||||||
ModbusBridge KEYWORD2
|
|
||||||
attachServer KEYWORD2
|
|
||||||
addFunctionCode KEYWORD2
|
|
||||||
denyFunctionCode KEYWORD2
|
|
||||||
bridgeWorker KEYWORD2
|
|
||||||
bridgeDenyWorker KEYWORD2
|
|
||||||
onDataHandler KEYWORD2
|
|
||||||
onErrorHandler KEYWORD2
|
|
||||||
onResponseHandler KEYWORD2
|
|
||||||
getMessageCount KEYWORD2
|
|
||||||
getErrorCount KEYWORD2
|
|
||||||
resetCounts KEYWORD2
|
|
||||||
addRequest KEYWORD2
|
|
||||||
syncRequest KEYWORD2
|
|
||||||
buildErrorMsg KEYWORD2
|
|
||||||
addRequest KEYWORD2
|
|
||||||
ModbusClient KEYWORD2
|
|
||||||
waitSync KEYWORD2
|
|
||||||
ModbusClientTCPasync KEYWORD2
|
|
||||||
setTimeout KEYWORD2
|
|
||||||
setIdleTimeout KEYWORD2
|
|
||||||
setMaxInflightRequests KEYWORD2
|
|
||||||
addToQueue KEYWORD2
|
|
||||||
ModbusError KEYWORD2
|
|
||||||
getText KEYWORD2
|
|
||||||
ModbusMessage KEYWORD2
|
|
||||||
data KEYWORD2
|
|
||||||
size KEYWORD2
|
|
||||||
push_back KEYWORD2
|
|
||||||
clear KEYWORD2
|
|
||||||
resize KEYWORD2
|
|
||||||
begin KEYWORD2
|
|
||||||
end KEYWORD2
|
|
||||||
append KEYWORD2
|
|
||||||
getServerID KEYWORD2
|
|
||||||
getFunctionCode KEYWORD2
|
|
||||||
getError KEYWORD2
|
|
||||||
setFunctionCode KEYWORD2
|
|
||||||
add KEYWORD2
|
|
||||||
get KEYWORD2
|
|
||||||
setMessage KEYWORD2
|
|
||||||
setError KEYWORD2
|
|
||||||
determineFloatOrder KEYWORD2
|
|
||||||
determineDoubleOrder KEYWORD2
|
|
||||||
swapFloat KEYWORD2
|
|
||||||
swapDouble KEYWORD2
|
|
||||||
getOne KEYWORD2
|
|
||||||
registerWorker KEYWORD2
|
|
||||||
getWorker KEYWORD2
|
|
||||||
unregisterWorker KEYWORD2
|
|
||||||
isServerFor KEYWORD2
|
|
||||||
getMessageCount KEYWORD2
|
|
||||||
getErrorCount KEYWORD2
|
|
||||||
resetCounts KEYWORD2
|
|
||||||
localRequest KEYWORD2
|
|
||||||
listServer KEYWORD2
|
|
||||||
ModbusServer KEYWORD2
|
|
||||||
ModbusServerTCP KEYWORD2
|
|
||||||
activeClients KEYWORD2
|
|
||||||
start KEYWORD2
|
|
||||||
stop KEYWORD2
|
|
||||||
clientAvailable KEYWORD2
|
|
||||||
ModbusServerTCPasync KEYWORD2
|
|
||||||
isRunning KEYWORD2
|
|
||||||
calcCRC KEYWORD2
|
|
||||||
validCRC KEYWORD2
|
|
||||||
addCRC KEYWORD2
|
|
||||||
calculateInterval KEYWORD2
|
|
||||||
prepareHardwareSerial KEYWORD2
|
|
||||||
RTUutils KEYWORD2
|
|
||||||
ServerData KEYWORD2
|
|
||||||
NIL_RESPONSE KEYWORD2
|
|
||||||
ECHO_RESPONSE KEYWORD2
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Constants (LITERAL1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
DISCONNECTED LITERAL1
|
|
||||||
CONNECTING LITERAL1
|
|
||||||
CONNECTED LITERAL1
|
|
||||||
ANY_FUNCTION_CODE LITERAL1
|
|
||||||
READ_COIL LITERAL1
|
|
||||||
READ_DISCR_INPUT LITERAL1
|
|
||||||
READ_HOLD_REGISTER LITERAL1
|
|
||||||
READ_INPUT_REGISTER LITERAL1
|
|
||||||
WRITE_COIL LITERAL1
|
|
||||||
WRITE_HOLD_REGISTER LITERAL1
|
|
||||||
READ_EXCEPTION_SERIAL LITERAL1
|
|
||||||
DIAGNOSTICS_SERIAL LITERAL1
|
|
||||||
READ_COMM_CNT_SERIAL LITERAL1
|
|
||||||
READ_COMM_LOG_SERIAL LITERAL1
|
|
||||||
WRITE_MULT_COILS LITERAL1
|
|
||||||
WRITE_MULT_REGISTERS LITERAL1
|
|
||||||
REPORT_SERVER_ID_SERIAL LITERAL1
|
|
||||||
READ_FILE_RECORD LITERAL1
|
|
||||||
WRITE_FILE_RECORD LITERAL1
|
|
||||||
MASK_WRITE_REGISTER LITERAL1
|
|
||||||
R_W_MULT_REGISTERS LITERAL1
|
|
||||||
READ_FIFO_QUEUE LITERAL1
|
|
||||||
ENCAPSULATED_INTERFACE LITERAL1
|
|
||||||
USER_DEFINED_41 LITERAL1
|
|
||||||
USER_DEFINED_42 LITERAL1
|
|
||||||
USER_DEFINED_43 LITERAL1
|
|
||||||
USER_DEFINED_44 LITERAL1
|
|
||||||
USER_DEFINED_45 LITERAL1
|
|
||||||
USER_DEFINED_46 LITERAL1
|
|
||||||
USER_DEFINED_47 LITERAL1
|
|
||||||
USER_DEFINED_48 LITERAL1
|
|
||||||
USER_DEFINED_64 LITERAL1
|
|
||||||
USER_DEFINED_65 LITERAL1
|
|
||||||
USER_DEFINED_66 LITERAL1
|
|
||||||
USER_DEFINED_67 LITERAL1
|
|
||||||
USER_DEFINED_68 LITERAL1
|
|
||||||
USER_DEFINED_69 LITERAL1
|
|
||||||
USER_DEFINED_6A LITERAL1
|
|
||||||
USER_DEFINED_6B LITERAL1
|
|
||||||
USER_DEFINED_6C LITERAL1
|
|
||||||
USER_DEFINED_6D LITERAL1
|
|
||||||
USER_DEFINED_6E LITERAL1
|
|
||||||
SUCCESS LITERAL1
|
|
||||||
ILLEGAL_FUNCTION LITERAL1
|
|
||||||
ILLEGAL_DATA_ADDRESS LITERAL1
|
|
||||||
ILLEGAL_DATA_VALUE LITERAL1
|
|
||||||
SERVER_DEVICE_FAILURE LITERAL1
|
|
||||||
ACKNOWLEDGE LITERAL1
|
|
||||||
SERVER_DEVICE_BUSY LITERAL1
|
|
||||||
NEGATIVE_ACKNOWLEDGE LITERAL1
|
|
||||||
MEMORY_PARITY_ERROR LITERAL1
|
|
||||||
GATEWAY_PATH_UNAVAIL LITERAL1
|
|
||||||
GATEWAY_TARGET_NO_RESP LITERAL1
|
|
||||||
TIMEOUT LITERAL1
|
|
||||||
INVALID_SERVER LITERAL1
|
|
||||||
CRC_ERROR LITERAL1
|
|
||||||
FC_MISMATCH LITERAL1
|
|
||||||
SERVER_ID_MISMATCH LITERAL1
|
|
||||||
PACKET_LENGTH_ERROR LITERAL1
|
|
||||||
PARAMETER_COUNT_ERROR LITERAL1
|
|
||||||
PARAMETER_LIMIT_ERROR LITERAL1
|
|
||||||
REQUEST_QUEUE_FULL LITERAL1
|
|
||||||
ILLEGAL_IP_OR_PORT LITERAL1
|
|
||||||
IP_CONNECTION_FAILED LITERAL1
|
|
||||||
TCP_HEAD_MISMATCH LITERAL1
|
|
||||||
EMPTY_MESSAGE LITERAL1
|
|
||||||
ASCII_FRAME_ERR LITERAL1
|
|
||||||
ASCII_CRC_ERR LITERAL1
|
|
||||||
ASCII_INVALID_CHAR LITERAL1
|
|
||||||
BROADCAST_ERROR LITERAL1
|
|
||||||
UNDEFINED_ERROR LITERAL1
|
|
||||||
FC01_TYPE LITERAL1
|
|
||||||
FC07_TYPE LITERAL1
|
|
||||||
FC0F_TYPE LITERAL1
|
|
||||||
FC10_TYPE LITERAL1
|
|
||||||
FC16_TYPE LITERAL1
|
|
||||||
FC18_TYPE LITERAL1
|
|
||||||
FCGENERIC LITERAL1
|
|
||||||
FCUSER LITERAL1
|
|
||||||
FCILLEGAL LITERAL1
|
|
||||||
PrintOut LITERAL1
|
|
||||||
LOG_LEVEL LITERAL1
|
|
||||||
LOCAL_LOG_LEVEL LITERAL1
|
|
||||||
LOG_LEVEL_NONE LITERAL1
|
|
||||||
LOG_LEVEL_CRITICAL LITERAL1
|
|
||||||
LOG_LEVEL_ERROR LITERAL1
|
|
||||||
LOG_LEVEL_WARNING LITERAL1
|
|
||||||
LOG_LEVEL_INFO LITERAL1
|
|
||||||
LOG_LEVEL_DEBUG LITERAL1
|
|
||||||
LOG_LEVEL_VERBOSE LITERAL1
|
|
||||||
LL_RED LITERAL1
|
|
||||||
LL_GREEN LITERAL1
|
|
||||||
LL_YELLOW LITERAL1
|
|
||||||
LL_BLUE LITERAL1
|
|
||||||
LL_MAGENTA LITERAL1
|
|
||||||
LL_CYAN LITERAL1
|
|
||||||
LL_NORM LITERAL1
|
|
||||||
LOG_HEADER LITERAL1
|
|
||||||
LOG_LINE_C LITERAL1
|
|
||||||
LOG_LINE_E LITERAL1
|
|
||||||
LOG_LINE_T LITERAL1
|
|
||||||
LOG_RAW_C LITERAL1
|
|
||||||
LOG_RAW_E LITERAL1
|
|
||||||
LOG_RAW_T LITERAL1
|
|
||||||
HEX_DUMP_T LITERAL1
|
|
||||||
LOG_N LITERAL1
|
|
||||||
LOGRAW_N LITERAL1
|
|
||||||
HEXDUMP_N LITERAL1
|
|
||||||
LOG_C LITERAL1
|
|
||||||
LOGRAW_C LITERAL1
|
|
||||||
HEXDUMP_C LITERAL1
|
|
||||||
LOG_E LITERAL1
|
|
||||||
LOGRAW_E LITERAL1
|
|
||||||
HEXDUMP_E LITERAL1
|
|
||||||
LOG_W LITERAL1
|
|
||||||
LOGRAW_W LITERAL1
|
|
||||||
HEXDUMP_W LITERAL1
|
|
||||||
LOG_I LITERAL1
|
|
||||||
LOGRAW_I LITERAL1
|
|
||||||
HEXDUMP_I LITERAL1
|
|
||||||
LOG_D LITERAL1
|
|
||||||
LOGRAW_D LITERAL1
|
|
||||||
HEXDUMP_D LITERAL1
|
|
||||||
LOG_V LITERAL1
|
|
||||||
LOGRAW_V LITERAL1
|
|
||||||
HEXDUMP_V LITERAL1
|
|
||||||
LOCAL_LOG_LEVEL LITERAL1
|
|
||||||
TCP_SERVER LITERAL1
|
|
||||||
RTU_SERVER LITERAL1
|
|
||||||
SERVER_END LITERAL1
|
|
||||||
LOCAL_LOG_LEVEL LITERAL1
|
|
||||||
DEFAULTTIMEOUT LITERAL1
|
|
||||||
DEFAULTIDLETIME LITERAL1
|
|
||||||
LOCAL_LOG_LEVEL LITERAL1
|
|
||||||
SERVER_END LITERAL1
|
|
||||||
SWAP_BYTES LITERAL1
|
|
||||||
SWAP_REGISTERS LITERAL1
|
|
||||||
SWAP_WORDS LITERAL1
|
|
||||||
SWAP_NIBBLES LITERAL1
|
|
||||||
LOCK_GUARD LITERAL1
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
name=eModbus
|
|
||||||
version=1.7.2
|
|
||||||
author=bertmelis,Miq1 <miq1@gmx.de>
|
|
||||||
maintainer=Miq1 <miq1@gmx.de>
|
|
||||||
sentence=eModbus provides Modbus RTU, ASCII and TCP functions for ESP32.
|
|
||||||
paragraph=This library is non-blocking for the program using it. Modbus requests and responses will be returned to user-supplied callback functions. All Modbus function codes are supported implicitly, the codes specified by the Modbus specs are parameter-checked.
|
|
||||||
category=Communication
|
|
||||||
url=https://github.com/eModbus/eModbus
|
|
||||||
architectures=esp32,FreeRTOS
|
|
||||||
@@ -12,6 +12,7 @@ with additional changes to support EMS-ESP such as compiling with Tasmota and no
|
|||||||
```
|
```
|
||||||
src/espMqttClient.cpp
|
src/espMqttClient.cpp
|
||||||
src/Transport/ClientSecureSync.h
|
src/Transport/ClientSecureSync.h
|
||||||
|
src/Config.h
|
||||||
```
|
```
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef Features_h
|
|
||||||
#define Features_h
|
|
||||||
|
|
||||||
// project feature on by default
|
|
||||||
#ifndef FT_PROJECT
|
|
||||||
#define FT_PROJECT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// security feature on by default
|
|
||||||
#ifndef FT_SECURITY
|
|
||||||
#define FT_SECURITY 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// mqtt feature on by default
|
|
||||||
#ifndef FT_MQTT
|
|
||||||
#define FT_MQTT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ntp feature on by default
|
|
||||||
#ifndef FT_NTP
|
|
||||||
#define FT_NTP 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// upload firmware/file feature on by default
|
|
||||||
#ifndef FT_UPLOAD_FIRMWARE
|
|
||||||
#define FT_UPLOAD_FIRMWARE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -26,13 +26,6 @@ SOFTWARE.
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include "semver200.h"
|
#include "semver200.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // for logging
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// disable symbol name too long warning
|
|
||||||
#pragma warning(disable : 4503)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace version {
|
namespace version {
|
||||||
@@ -57,7 +50,7 @@ inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void Parse_error(const std::string & s) {
|
inline void Parse_error(const std::string & s) {
|
||||||
emsesp::EMSESP::logger().err("parse error: %s", s.c_str());
|
// emsesp::EMSESP::logger().err("parse error: %s", s.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advance parser state machine by a single step.
|
/// Advance parser state machine by a single step.
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "uuid/syslog.h"
|
#include "uuid/syslog.h"
|
||||||
|
|
||||||
#include "../../../src/emsesp.h"
|
|
||||||
|
|
||||||
#ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
#ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||||
// time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637
|
// time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637
|
||||||
@@ -233,8 +231,8 @@ SyslogService::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_
|
|||||||
: id_(id)
|
: id_(id)
|
||||||
, content_(std::move(content)) {
|
, content_(std::move(content)) {
|
||||||
// Added for EMS-ESP
|
// Added for EMS-ESP
|
||||||
// check for Ethernet too. This assumes the network has already started.
|
// if (time_good_ || emsesp::EMSESP::system_.network_connected()) {
|
||||||
if (time_good_ || emsesp::EMSESP::system_.network_connected()) {
|
if (time_good_) {
|
||||||
#if UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
#if UUID_SYSLOG_HAVE_GETTIMEOFDAY
|
||||||
if (gettimeofday(&time_, nullptr) != 0) {
|
if (gettimeofday(&time_, nullptr) != 0) {
|
||||||
time_.tv_sec = (time_t)-1;
|
time_.tv_sec = (time_t)-1;
|
||||||
@@ -364,9 +362,9 @@ bool SyslogService::can_transmit() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!emsesp::EMSESP::system_.network_connected()) {
|
// if (!emsesp::EMSESP::system_.network_connected()) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const uint64_t now = uuid::get_uptime_ms();
|
const uint64_t now = uuid::get_uptime_ms();
|
||||||
uint64_t message_delay = UUID_SYSLOG_UDP_BASE_MESSAGE_DELAY;
|
uint64_t message_delay = UUID_SYSLOG_UDP_BASE_MESSAGE_DELAY;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#ifndef ASYNC_JSON_H_
|
#ifndef ASYNC_JSON_H_
|
||||||
#define ASYNC_JSON_H_
|
#define ASYNC_JSON_H_
|
||||||
|
|
||||||
@@ -6,7 +5,8 @@
|
|||||||
|
|
||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
|
|
||||||
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024
|
// treat MessagePack as normal JSON responses
|
||||||
|
#define AsyncMessagePackResponse AsyncJsonResponse
|
||||||
|
|
||||||
constexpr const char * JSON_MIMETYPE = "application/json";
|
constexpr const char * JSON_MIMETYPE = "application/json";
|
||||||
|
|
||||||
@@ -42,65 +42,17 @@ class ChunkPrint : public Print {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// class PrettyAsyncJsonResponse {
|
|
||||||
// protected:
|
|
||||||
// JsonDocument _jsonBuffer;
|
|
||||||
|
|
||||||
// JsonVariant _root;
|
|
||||||
// bool _isValid;
|
|
||||||
|
|
||||||
// public:
|
|
||||||
// PrettyAsyncJsonResponse(bool isArray = false)
|
|
||||||
// : _isValid{false} {
|
|
||||||
// if (isArray)
|
|
||||||
// _root = _jsonBuffer.to<JsonArray>();
|
|
||||||
// else
|
|
||||||
// _root = _jsonBuffer.add<JsonObject>();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ~PrettyAsyncJsonResponse() {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// JsonVariant getRoot() {
|
|
||||||
// return _root;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bool _sourceValid() const {
|
|
||||||
// return _isValid;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// size_t setLength() {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void setContentType(const char * s) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// size_t getSize() {
|
|
||||||
// return _jsonBuffer.size();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// size_t _fillBuffer(uint8_t * data, size_t len) {
|
|
||||||
// return len;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void setCode(uint16_t) {
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
class AsyncJsonResponse {
|
class AsyncJsonResponse {
|
||||||
protected:
|
protected:
|
||||||
JsonDocument _jsonBuffer;
|
JsonDocument _jsonBuffer;
|
||||||
JsonVariant _root;
|
JsonVariant _root;
|
||||||
bool _isValid;
|
bool _isValid;
|
||||||
bool _isMsgPack;
|
|
||||||
int _code;
|
int _code;
|
||||||
size_t _contentLength;
|
size_t _contentLength;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncJsonResponse(bool isArray = false, bool isMsgPack = false)
|
AsyncJsonResponse(bool isArray = false)
|
||||||
: _isValid{false}
|
: _isValid{false} {
|
||||||
, _isMsgPack{isMsgPack} {
|
|
||||||
_code = 200;
|
_code = 200;
|
||||||
if (isArray)
|
if (isArray)
|
||||||
_root = _jsonBuffer.to<JsonArray>();
|
_root = _jsonBuffer.to<JsonArray>();
|
||||||
@@ -120,7 +72,7 @@ class AsyncJsonResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t setLength() {
|
size_t setLength() {
|
||||||
_contentLength = _isMsgPack ? measureMsgPack(_root) : measureJson(_root);
|
_contentLength = measureJson(_root);
|
||||||
|
|
||||||
if (_contentLength) {
|
if (_contentLength) {
|
||||||
_isValid = true;
|
_isValid = true;
|
||||||
@@ -133,7 +85,7 @@ class AsyncJsonResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t _fillBuffer(uint8_t * data, size_t len) {
|
size_t _fillBuffer(uint8_t * data, size_t len) {
|
||||||
// _isMsgPack ? serializeMsgPack(_root, data) : serializeJson(_root, data);
|
// serializeJson(_root, data);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,10 +107,9 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
|
|||||||
ArJsonRequestHandlerFunction _onRequest;
|
ArJsonRequestHandlerFunction _onRequest;
|
||||||
size_t _contentLength;
|
size_t _contentLength;
|
||||||
size_t _maxContentLength;
|
size_t _maxContentLength;
|
||||||
size_t _maxJsonBufferSize;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
|
AsyncCallbackJsonWebHandler(const String & uri, ArJsonRequestHandlerFunction onRequest = nullptr)
|
||||||
: _uri(uri)
|
: _uri(uri)
|
||||||
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
|
, _method(HTTP_POST | HTTP_PUT | HTTP_PATCH)
|
||||||
, _onRequest(onRequest)
|
, _onRequest(onRequest)
|
||||||
@@ -171,9 +122,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
|
|||||||
void setMaxContentLength(int maxContentLength) {
|
void setMaxContentLength(int maxContentLength) {
|
||||||
_maxContentLength = maxContentLength;
|
_maxContentLength = maxContentLength;
|
||||||
}
|
}
|
||||||
void setMaxJsonBufferSize(int maxJsonBufferSize) {
|
|
||||||
_maxJsonBufferSize = maxJsonBufferSize;
|
|
||||||
}
|
|
||||||
void onRequest(ArJsonRequestHandlerFunction fn) {
|
void onRequest(ArJsonRequestHandlerFunction fn) {
|
||||||
_onRequest = fn;
|
_onRequest = fn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef ESP8266React_h
|
#ifndef ESP32React_h
|
||||||
#define ESP8266React_h
|
#define ESP32React_h
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
@@ -97,9 +97,9 @@ class DummySettingsService : public StatefulService<DummySettings> {
|
|||||||
#define NTPSettings DummySettings
|
#define NTPSettings DummySettings
|
||||||
#define APSettings DummySettings
|
#define APSettings DummySettings
|
||||||
|
|
||||||
class ESP8266React {
|
class ESP32React {
|
||||||
public:
|
public:
|
||||||
ESP8266React(AsyncWebServer * server, FS * fs)
|
ESP32React(AsyncWebServer * server, FS * fs)
|
||||||
: _settings(server, fs, nullptr)
|
: _settings(server, fs, nullptr)
|
||||||
, _securitySettingsService(server, fs){};
|
, _securitySettingsService(server, fs){};
|
||||||
|
|
||||||
@@ -11,8 +11,6 @@ class AsyncWebServer;
|
|||||||
class AsyncWebServerRequest;
|
class AsyncWebServerRequest;
|
||||||
class AsyncWebServerResponse;
|
class AsyncWebServerResponse;
|
||||||
class AsyncJsonResponse;
|
class AsyncJsonResponse;
|
||||||
// class PrettyAsyncJsonResponse;
|
|
||||||
// class MsgpackAsyncJsonResponse;
|
|
||||||
class AsyncEventSource;
|
class AsyncEventSource;
|
||||||
|
|
||||||
class AsyncWebParameter {
|
class AsyncWebParameter {
|
||||||
@@ -102,8 +100,6 @@ class AsyncWebServerRequest {
|
|||||||
|
|
||||||
void send(AsyncJsonResponse * response) {};
|
void send(AsyncJsonResponse * response) {};
|
||||||
|
|
||||||
// void send(PrettyAsyncJsonResponse * response) {};
|
|
||||||
// void send(MsgpackAsyncJsonResponse * response) {};
|
|
||||||
void send(int code, const String & contentType = String(), const String & content = String()) {};
|
void send(int code, const String & contentType = String(), const String & content = String()) {};
|
||||||
void send(int code, const String & contentType, const __FlashStringHelper *) {};
|
void send(int code, const String & contentType, const __FlashStringHelper *) {};
|
||||||
|
|
||||||
@@ -226,7 +222,6 @@ class AsyncWebServerResponse {
|
|||||||
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy for EMS-ESP
|
|
||||||
|
|
||||||
class AsyncWebServer {
|
class AsyncWebServer {
|
||||||
protected:
|
protected:
|
||||||
@@ -246,7 +241,6 @@ class AsyncWebServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {};
|
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {};
|
||||||
void on(const char * uri, ArJsonRequestHandlerFunction onRequest) {}; // added by proddy for EMS-ESP
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef Features_h
|
|
||||||
#define Features_h
|
|
||||||
|
|
||||||
// project feature off by default
|
|
||||||
#ifndef FT_PROJECT
|
|
||||||
#define FT_PROJECT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// security feature on by default
|
|
||||||
#ifndef FT_SECURITY
|
|
||||||
#define FT_SECURITY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// mqtt feature on by default
|
|
||||||
#ifndef FT_MQTT
|
|
||||||
#define FT_MQTT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ntp feature on by default
|
|
||||||
#ifndef FT_NTP
|
|
||||||
#define FT_NTP 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// upload firmware/file feature off by default
|
|
||||||
#ifndef FT_UPLOAD_FIRMWARE
|
|
||||||
#define FT_UPLOAD_FIRMWARE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
class HTTPClient {
|
class HTTPClient {
|
||||||
public:
|
public:
|
||||||
// HTTPClient();
|
|
||||||
// ~HTTPClient();
|
|
||||||
|
|
||||||
bool begin(String url) {
|
bool begin(String url) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define SecurityManager_h
|
#define SecurityManager_h
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "Features.h"
|
|
||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
|
|
||||||
@@ -70,6 +69,21 @@ class SecurityManager {
|
|||||||
virtual ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) = 0;
|
virtual ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) = 0;
|
||||||
virtual ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) = 0;
|
virtual ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) = 0;
|
||||||
virtual ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate) = 0;
|
virtual ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate) = 0;
|
||||||
|
|
||||||
|
void addEndpoint(AsyncWebServer * server,
|
||||||
|
const String & path,
|
||||||
|
AuthenticationPredicate predicate,
|
||||||
|
ArJsonRequestHandlerFunction function,
|
||||||
|
WebRequestMethodComposite method = HTTP_POST) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-Json endpoints - default GET
|
||||||
|
void addEndpoint(AsyncWebServer * server,
|
||||||
|
const String & path,
|
||||||
|
AuthenticationPredicate predicate,
|
||||||
|
ArRequestHandlerFunction function,
|
||||||
|
WebRequestMethodComposite method = HTTP_GET) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef SecuritySettingsService_h
|
#ifndef SecuritySettingsService_h
|
||||||
#define SecuritySettingsService_h
|
#define SecuritySettingsService_h
|
||||||
|
|
||||||
#include "Features.h"
|
|
||||||
#include "SecurityManager.h"
|
#include "SecurityManager.h"
|
||||||
#include "HttpEndpoint.h"
|
#include "HttpEndpoint.h"
|
||||||
#include "FSPersistence.h"
|
#include "FSPersistence.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mock-api",
|
"name": "mock-api",
|
||||||
"version": "3.7.1",
|
"version": "3.7.2",
|
||||||
"description": "mock api for EMS-ESP",
|
"description": "mock api for EMS-ESP",
|
||||||
"author": "proddy, emsesp.org",
|
"author": "proddy, emsesp.org",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@msgpack/msgpack": "^2.8.0",
|
"@msgpack/msgpack": "^2.8.0",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.0",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.1",
|
||||||
"formidable": "^3.5.2",
|
"formidable": "^3.5.2",
|
||||||
"itty-router": "^5.0.18",
|
"itty-router": "^5.0.18",
|
||||||
"prettier": "^3.4.2"
|
"prettier": "^3.4.2"
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ let VERSION_IS_UPGRADEABLE: boolean;
|
|||||||
|
|
||||||
// Versions
|
// Versions
|
||||||
// default - on latest stable, no upgrades
|
// default - on latest stable, no upgrades
|
||||||
let THIS_VERSION = '3.7.1';
|
let THIS_VERSION = '3.7.2';
|
||||||
let LATEST_STABLE_VERSION = '3.7.1';
|
let LATEST_STABLE_VERSION = '3.7.2';
|
||||||
let LATEST_DEV_VERSION = '3.7.2-dev.1';
|
let LATEST_DEV_VERSION = '3.7.3-dev.1';
|
||||||
|
|
||||||
// scenarios for testing, overriding the default
|
// scenarios for testing, overriding the default
|
||||||
const version_test = 0;
|
const version_test = 0;
|
||||||
|
|||||||
@@ -139,9 +139,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@trivago/prettier-plugin-sort-imports@npm:^5.2.0":
|
"@trivago/prettier-plugin-sort-imports@npm:^5.2.1":
|
||||||
version: 5.2.0
|
version: 5.2.1
|
||||||
resolution: "@trivago/prettier-plugin-sort-imports@npm:5.2.0"
|
resolution: "@trivago/prettier-plugin-sort-imports@npm:5.2.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/generator": "npm:^7.26.2"
|
"@babel/generator": "npm:^7.26.2"
|
||||||
"@babel/parser": "npm:^7.26.2"
|
"@babel/parser": "npm:^7.26.2"
|
||||||
@@ -153,7 +153,7 @@ __metadata:
|
|||||||
"@vue/compiler-sfc": 3.x
|
"@vue/compiler-sfc": 3.x
|
||||||
prettier: 2.x - 3.x
|
prettier: 2.x - 3.x
|
||||||
prettier-plugin-svelte: 3.x
|
prettier-plugin-svelte: 3.x
|
||||||
svelte: 4.x
|
svelte: 4.x || 5.x
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@vue/compiler-sfc":
|
"@vue/compiler-sfc":
|
||||||
optional: true
|
optional: true
|
||||||
@@ -161,7 +161,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
svelte:
|
svelte:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/73ebdea1f5cef609e1bf7ed7a276916770de210d29e512dfcdac68fafd05cc155f5aec5962bcce65952d24e43aeee81bc58caf37c8d298e7d7f23d4851534405
|
checksum: 10c0/fd782f84d44c61159dce099775a86ebb5082b5e5eea205ec71d6fede3cf079aafb8f9a9979d5742ff0126598a37098cf679d5bad268320907513f2984df3d501
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ __metadata:
|
|||||||
resolution: "mock-api@workspace:."
|
resolution: "mock-api@workspace:."
|
||||||
dependencies:
|
dependencies:
|
||||||
"@msgpack/msgpack": "npm:^2.8.0"
|
"@msgpack/msgpack": "npm:^2.8.0"
|
||||||
"@trivago/prettier-plugin-sort-imports": "npm:^5.2.0"
|
"@trivago/prettier-plugin-sort-imports": "npm:^5.2.1"
|
||||||
formidable: "npm:^3.5.2"
|
formidable: "npm:^3.5.2"
|
||||||
itty-router: "npm:^5.0.18"
|
itty-router: "npm:^5.0.18"
|
||||||
prettier: "npm:^3.4.2"
|
prettier: "npm:^3.4.2"
|
||||||
|
|||||||
14
partitions/esp32_partition_16M.md
Normal file
14
partitions/esp32_partition_16M.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
| Name | Type | SubType | Offset | Size | Notes | File |
|
||||||
|
|------------|------------|----------|---------------|--------------------|---------------------------------|---------------------------------|
|
||||||
|
| bootloader | | | 0x0000/0x1000 | 0x8000 (32 KB) | ESP32-S3=0x1000, ESP32=0x1000 | bootloader*.bin |
|
||||||
|
| partitions | | | 0x8000 | 0x1000 (4 KB) | same for each board | partitions*.bin |
|
||||||
|
| - | | | | | | |
|
||||||
|
| nvs | data | nvs | 0x9000 | 0x5000 (20 KB) | reserved for ESP32 | |
|
||||||
|
| otadata | data | ota | 0xE000 | 0x2000 (8 KB) | same for each board | boot_app0*.bin |
|
||||||
|
| boot | app | factory | 0x10000 | 0x480000 (4.5 MB) | default boot partition | EMS-ESP firmware *.bin/loader |
|
||||||
|
| app0 | app | ota_0 | 0x290000 | 0x490000 (4.56 MB) | OTA cycle 1 | EMS-ESP firmware *.bin |
|
||||||
|
| app1 | app | ota_1 | 0x510000 | 0x490000 (4.56 MB) | OTA cycle 2 | EMS-ESP firmware *.bin |
|
||||||
|
| nvs1 | data | nvs | 0xAA0000 | 0x040000 (256 KB) | custom for EMS-ESP | (generated by script) |
|
||||||
|
| spiffs | data | spiffs | 0xAA0000 | 0x200000 (2 MB) | for LittleFS/EMS-ESP filesystem | (not used) |
|
||||||
|
| coredump | data | coredump | 0xCE0000 | 0x010000 (64 KB) | | |
|
||||||
@@ -11,81 +11,53 @@
|
|||||||
; -DEMSESP_DE_ONLY ; only DE translated entity names
|
; -DEMSESP_DE_ONLY ; only DE translated entity names
|
||||||
; -DEMSESP_EN_ONLY ; only EN translated entity names
|
; -DEMSESP_EN_ONLY ; only EN translated entity names
|
||||||
; -DEMSESP_PINGTEST ; send log message every 1/2 second
|
; -DEMSESP_PINGTEST ; send log message every 1/2 second
|
||||||
|
|
||||||
; my_build_flags = -DEMSESP_TEST -DEMSESP_DEBUG
|
; my_build_flags = -DEMSESP_TEST -DEMSESP_DEBUG
|
||||||
; my_build_flags = -DEMSESP_DEBUG
|
|
||||||
; my_build_flags = -DEMSESP_DEBUG -DEMSESP_TEST -DEMSESP_PINGTEST
|
; my_build_flags = -DEMSESP_DEBUG -DEMSESP_TEST -DEMSESP_PINGTEST
|
||||||
|
; my_build_flags = -DEMSESP_DEBUG -DCORE_DEBUG_LEVEL=5
|
||||||
|
my_build_flags =
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
default_envs = s_16M_P ; BBQKees E32V2
|
; default_envs = s_16M_P ; BBQKees E32V2
|
||||||
; default_envs = s3_16M_P ; BBQKees S3
|
default_envs = s3_16M_P ; BBQKees S3
|
||||||
; default_envs = s_4M ; BBQKees S32
|
|
||||||
; default_envs = native
|
|
||||||
; default_envs = debug
|
|
||||||
; default_envs = s2_4M
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
; set the username and password for the admin account (default both admin)
|
|
||||||
|
; uncomment this section to enable extra debug
|
||||||
|
; build_type = debug
|
||||||
|
; monitor_filters = colorize, esp32_exception_decoder
|
||||||
|
|
||||||
|
; customize the scripts
|
||||||
|
; extra_scripts =
|
||||||
|
; pre:scripts/build_interface.py ; builds the WebUI (unless NO_BUILD_WEBUI is set) - comment out if you don't want to build each time
|
||||||
|
; scripts/rename_fw.py ; renames the firmware .bin file - comment out if not needed
|
||||||
|
; scripts/upload.py ; optionally upload the firmware via OTA (must have upload_protocol = custom)
|
||||||
|
|
||||||
|
; set the username and password for the admin account (default password is admin)
|
||||||
custom_username = admin
|
custom_username = admin
|
||||||
custom_password = admin
|
custom_password = admin
|
||||||
|
|
||||||
; ** upload settings **
|
; ** upload settings **
|
||||||
; for direct USB set:
|
; for direct USB, which is the default you can set an optional port for example:
|
||||||
; upload_protocol = esptool
|
; upload_port = /dev/ttyUSB0 or COM3
|
||||||
; upload_port = /dev/ttyUSB*
|
|
||||||
;
|
;
|
||||||
; for direct via URL (OTA) set:
|
; for direct via HTTP (OTA) set:
|
||||||
; upload_protocol = custom
|
; upload_protocol = custom
|
||||||
; custom_emsesp_ip = <ip address> or ems-esp.local
|
; custom_emsesp_ip = <ip address> or ems-esp.local
|
||||||
; custom_password = admin
|
|
||||||
|
|
||||||
; upload_protocol = esptool
|
|
||||||
; upload_port = /dev/ttyUSB*
|
|
||||||
|
|
||||||
upload_protocol = custom
|
upload_protocol = custom
|
||||||
; custom_emsesp_ip = 10.10.10.175 ; S3
|
custom_emsesp_ip = 10.10.10.93 ; S3
|
||||||
custom_emsesp_ip = 192.168.1.225 ; E32V2
|
; custom_emsesp_ip = 192.168.1.225 ; E32V2
|
||||||
|
|
||||||
; build_type = debug
|
; ** debug settings **
|
||||||
; monitor_filters = esp32_exception_decoder
|
; to be used with esp-prog/JTAG hardware device like https://docs.espressif.com/projects/esp-dev-kits/en/latest/other/esp-prog/user_guide.html
|
||||||
|
|
||||||
; ** modules **
|
|
||||||
; example below is using a locally built version of EMS-ESP-Modules. You can also test with:
|
|
||||||
; rm -rf .pio/libdeps/native/EMS-ESP-Modules; pio run -e native -t clean; pio run -e native -t exec
|
|
||||||
; lib_deps =
|
|
||||||
; file://../modules/EMS-ESP-Modules
|
|
||||||
|
|
||||||
[env:native]
|
|
||||||
extra_scripts =
|
|
||||||
; pre:scripts/refresh_module_library_native.py
|
|
||||||
; post:scripts/run_native.py
|
|
||||||
|
|
||||||
[env:s_16M_P]
|
|
||||||
extra_scripts =
|
|
||||||
pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
|
|
||||||
scripts/rename_fw.py
|
|
||||||
scripts/upload.py
|
|
||||||
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc2/platform-espressif32.zip
|
|
||||||
|
|
||||||
[env:s3_16M_P]
|
|
||||||
extra_scripts =
|
|
||||||
; pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
|
|
||||||
scripts/rename_fw.py
|
|
||||||
scripts/upload.py
|
|
||||||
|
|
||||||
[env:s_4M]
|
|
||||||
extra_scripts =
|
|
||||||
; pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
|
|
||||||
scripts/rename_fw.py
|
|
||||||
; scripts/upload.py
|
|
||||||
|
|
||||||
; pio run -e debug
|
; pio run -e debug
|
||||||
; or from Visual Studio Code do PIO -> Project Tasks -> debug -> General -> Upload and Monitor
|
; add to build_flags these additional options: EMSESP_DEBUG EMSESP_UART_DEBUG EMSESP_DEBUG_SENSOR
|
||||||
; options for debugging are: EMSESP_DEBUG EMSESP_UART_DEBUG EMSESP_DEBUG_SENSOR
|
|
||||||
[env:debug]
|
[env:debug]
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
framework = arduino
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
board_build.partitions = esp32_partition_debug.csv
|
board_build.partitions = partitions/esp32_partition_debug.csv
|
||||||
board_upload.flash_size = 4MB
|
board_upload.flash_size = 4MB
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
|
|||||||
312
platformio.ini
312
platformio.ini
@@ -4,188 +4,181 @@
|
|||||||
; The firmware is renamed following this convention, and placed in the build/firmware folder:
|
; The firmware is renamed following this convention, and placed in the build/firmware folder:
|
||||||
; EMS-ESP32-<version>-<chip_type>-<flash_mem>[+ if PSRAM onboard].bin
|
; EMS-ESP32-<version>-<chip_type>-<flash_mem>[+ if PSRAM onboard].bin
|
||||||
; For example: EMS-ESP-3_7_0-dev_31-esp32-16MB+.bin
|
; For example: EMS-ESP-3_7_0-dev_31-esp32-16MB+.bin
|
||||||
|
;
|
||||||
|
; boards can be found in https://github.com/pioarduino/platform-espressif32/tree/main/boards
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
; build all the CI targets as default. Use pio_local.ini to override.
|
; build all supported targets. Use pio_local.ini to override and build specific targets.
|
||||||
default_envs = ci_s_4M, ci_s_16M, ci_s_16M_P, ci_s3_16M_P
|
default_envs = s_4M, s_16M, s_16M_P, s3_16M_P
|
||||||
|
|
||||||
|
description = EMS-ESP Firmware for the ESP32
|
||||||
|
src_dir = src
|
||||||
|
lib_dir = lib
|
||||||
|
boards_dir = boards
|
||||||
|
; build_cache_dir = .pio/build_cache
|
||||||
|
|
||||||
extra_configs =
|
extra_configs =
|
||||||
factory_settings.ini
|
factory_settings.ini
|
||||||
pio_local.ini
|
pio_local.ini
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
core_build_flags = -std=gnu++2a -Isrc -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
|
core_build_flags = -std=gnu++17 -O3 -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
|
||||||
core_unbuild_flags = -std=gnu++11
|
core_unbuild_flags = -std=gnu++11 -std=gnu++14
|
||||||
|
|
||||||
my_build_flags =
|
my_build_flags =
|
||||||
|
|
||||||
; explanation on these custom settings:
|
|
||||||
; CONFIG_ASYNC_TCP_QUEUE - see https://github.com/emsesp/EMS-ESP32/issues/177
|
|
||||||
; CONFIG_ASYNC_TCP_STACK_SIZE - stack usage measured: ESP32: ~2.3K, ESP32S3: ~3.5k
|
|
||||||
; CONFIG_ASYNC_TCP_TASK_PRIORITY - default is 10, was 5 for EMS-ESP
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.core_build_flags}
|
${common.core_build_flags}
|
||||||
${factory_settings.build_flags}
|
${factory_settings.build_flags}
|
||||||
${common.my_build_flags}
|
${common.my_build_flags}
|
||||||
|
-I./src/core
|
||||||
|
-D ARDUINO_ARCH_ESP32
|
||||||
-D ONEWIRE_CRC16=0
|
-D ONEWIRE_CRC16=0
|
||||||
-D CONFIG_ETH_ENABLED
|
|
||||||
-D CONFIG_UART_ISR_IN_IRAM
|
-D CONFIG_UART_ISR_IN_IRAM
|
||||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=6144
|
; AsyncTCP
|
||||||
-D CONFIG_ASYNC_TCP_QUEUE=32
|
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 ; default
|
||||||
-D CONFIG_ASYNC_TCP_TASK_PRIORITY=10
|
-D CONFIG_ASYNC_TCP_PRIORITY=10 ; default
|
||||||
|
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 ; default
|
||||||
|
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 ; force async_tcp task to be on same core as Arduino app (default is any core)
|
||||||
|
-D CONFIG_ASYNC_TCP_STACK_SIZE=6144 ; stack usage measured: ESP32: ~2.3K, ESP32S3: ~3.5k - (default is 16K)
|
||||||
|
; ESPAsyncWebServer
|
||||||
|
-D WS_MAX_QUEUED_MESSAGES=64
|
||||||
-D CORE_DEBUG_LEVEL=0
|
-D CORE_DEBUG_LEVEL=0
|
||||||
|
|
||||||
unbuild_flags =
|
unbuild_flags =
|
||||||
${common.core_unbuild_flags}
|
${common.core_unbuild_flags}
|
||||||
|
|
||||||
[espressif32_base]
|
; 16MB Flash variants
|
||||||
platform = espressif32@6.9.0
|
[espressif32_base_16M]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board_build.filesystem = littlefs
|
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||||
build_flags =
|
board_upload.flash_size = 16MB
|
||||||
${common.build_flags}
|
platform = espressif32@6.9.0 ; Arduino Core 2.0.18 / IDF 4.4.8
|
||||||
build_unflags =
|
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip ; Arduino Core 3.1.0 / IDF 5.3.2
|
||||||
${common.unbuild_flags}
|
; platform = https://github.com/pioarduino/platform-espressif32.git#develop
|
||||||
extra_scripts =
|
;
|
||||||
pre:scripts/build_interface.py
|
; Experimental for building using espidf and the Hybrid mode to remove core libraries.
|
||||||
scripts/rename_fw.py
|
;
|
||||||
|
; custom_sdkconfig = https://raw.githubusercontent.com/pioarduino/sdkconfig/refs/heads/main/sdkconfig_tasmota_esp32
|
||||||
|
; '# CONFIG_ETH_USE_ESP32_EMAC is not set'
|
||||||
|
; '# CONFIG_ETH_PHY_INTERFACE_RMII is not set'
|
||||||
|
; '# CONFIG_ETH_RMII_CLK_INPUT is not set'
|
||||||
|
; '# CONFIG_ETH_RMII_CLK_IN_GPIO is not set'
|
||||||
|
; custom_component_remove = espressif/esp_hosted
|
||||||
|
; espressif/esp_wifi_remote
|
||||||
|
; espressif/esp-dsp
|
||||||
|
; espressif/network_provisioning
|
||||||
|
; espressif/esp-zboss-lib
|
||||||
|
; espressif/esp-zigbee-lib
|
||||||
|
; espressif/esp_rainmaker
|
||||||
|
; espressif/rmaker_common
|
||||||
|
; espressif/esp_insights
|
||||||
|
; espressif/esp_diag_data_store
|
||||||
|
; espressif/esp_diagnostics
|
||||||
|
; espressif/cbor
|
||||||
|
; espressif/qrcode
|
||||||
|
; espressif/esp-sr
|
||||||
|
; espressif/libsodium
|
||||||
|
; espressif/esp-modbus
|
||||||
|
; chmorgan/esp-libhelix-mp3
|
||||||
|
; espressif/esp32-camera
|
||||||
|
|
||||||
[espressif32_base_tasmota]
|
; 32MB Flash variants
|
||||||
; use Tasmota's library for 4MB variants
|
[espressif32_base_32M]
|
||||||
; it removes some unused libs (like mbedtsl, so no WiFi_secure.h) and increases available heap
|
|
||||||
; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
|
||||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip
|
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board_build.filesystem = littlefs
|
board_build.partitions = partitions/esp32_partition_32M.csv
|
||||||
build_flags =
|
board_upload.flash_size = 32MB
|
||||||
${common.build_flags}
|
platform = espressif32@6.9.0 ; Arduino Core 2.0.18 / IDF 4.4.8
|
||||||
-DTASMOTA_SDK
|
|
||||||
build_unflags =
|
; use Tasmota's library for 4MB Flash variants.
|
||||||
${common.unbuild_flags}
|
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
||||||
extra_scripts =
|
[espressif32_base_T_4M]
|
||||||
pre:scripts/build_interface.py
|
framework = arduino
|
||||||
scripts/rename_fw.py
|
board_build.partitions = partitions/esp32_partition_4M.csv
|
||||||
|
board_upload.flash_size = 4MB
|
||||||
|
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
||||||
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.12.30/platform-espressif32.zip ; Arduino Core 3.1.0.241206 based on IDF 5.3.2
|
||||||
|
|
||||||
|
; use Tasmota's library for 16MB Flash variants.
|
||||||
|
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
||||||
|
[espressif32_base_T_16M]
|
||||||
|
framework = arduino
|
||||||
|
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
||||||
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.12.30/platform-espressif32.zip ; Arduino Core 3.1.0.241206 based on IDF 5.3.2
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
|
build_flags =
|
||||||
|
${common.build_flags}
|
||||||
|
build_unflags =
|
||||||
|
${common.unbuild_flags}
|
||||||
|
extra_scripts =
|
||||||
|
pre:scripts/build_interface.py ; builds the WebUI (unless NO_BUILD_WEBUI is set)
|
||||||
|
scripts/rename_fw.py ; renames the firmware .bin file
|
||||||
|
scripts/upload.py ; optionally upload the firmware via OTA (if upload_protocol = custom)
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
; on MacBook default upload speed is 921600, which is too fast for USB. Lower for Mac.
|
|
||||||
; see https://docs.platformio.org/en/latest/projectconf/sections/env/options/upload/upload_speed.html
|
|
||||||
; upload_speed = 460800
|
|
||||||
upload_speed = 921600
|
|
||||||
build_type = release
|
build_type = release
|
||||||
check_tool = cppcheck, clangtidy
|
board_build.filesystem = littlefs
|
||||||
check_severity = high, medium
|
lib_deps =
|
||||||
check_flags =
|
bblanchon/ArduinoJson @ 7.3.0
|
||||||
cppcheck: --std=c++11 -v
|
mathieucarbou/AsyncTCP @ 3.3.1
|
||||||
clangtidy: --checks=-*,clang-analyzer-*,performance-*
|
mathieucarbou/ESPAsyncWebServer @ 3.4.5
|
||||||
lib_ldf_mode = chain+
|
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.4
|
||||||
lib_deps =
|
|
||||||
https://github.com/emsesp/EMS-ESP-Modules.git@1.0.3
|
|
||||||
|
|
||||||
;
|
;
|
||||||
; builds for GitHub Actions CI
|
; Builds for different board types
|
||||||
; the Web interface is built separately during the GH Action script, so skipped on these targets
|
; If the environment variable (windows or linux) "NO_BUILD_WEBUI" is set, the WebUI will not be built.
|
||||||
;
|
; If you're building for a single target, create a pio_local.ini file (look at example)
|
||||||
[env:ci_s_4M]
|
|
||||||
; 4MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees older S32 and E32 models
|
|
||||||
extends = espressif32_base_tasmota
|
|
||||||
extra_scripts = scripts/rename_fw.py
|
|
||||||
board = esp32dev
|
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
board_build.partitions = esp32_partition_4M.csv
|
|
||||||
|
|
||||||
[env:ci_s_16M]
|
|
||||||
; 16MB ESP32 - using Tasmota - no SSL, no PSRAM - like the BBQKees some later S32 models
|
|
||||||
extends = espressif32_base_tasmota
|
|
||||||
extra_scripts = scripts/rename_fw.py
|
|
||||||
board = esp32dev
|
|
||||||
board_upload.flash_size = 16MB
|
|
||||||
board_build.partitions = esp32_partition_16M.csv
|
|
||||||
|
|
||||||
[env:ci_s_16M_P]
|
|
||||||
; 16MB ESP32 - with PSRAM - like BBQKees E32V2
|
|
||||||
extends = espressif32_base
|
|
||||||
extra_scripts = scripts/rename_fw.py
|
|
||||||
board = esp32dev
|
|
||||||
board_upload.flash_size = 16MB
|
|
||||||
board_build.partitions = esp32_partition_16M.csv
|
|
||||||
board_build.extra_flags = -DBOARD_HAS_PSRAM
|
|
||||||
|
|
||||||
[env:ci_s3_16M_P]
|
|
||||||
; 16MB ESP32-S3 - with PSRAM - like BBQKees S3
|
|
||||||
extends = espressif32_base
|
|
||||||
extra_scripts = scripts/rename_fw.py
|
|
||||||
board = lolin_s3
|
|
||||||
board_build.f_cpu = 240000000L
|
|
||||||
board_upload.flash_size = 16MB
|
|
||||||
board_build.partitions = esp32_partition_16M.csv
|
|
||||||
|
|
||||||
;
|
|
||||||
; Direct builds
|
|
||||||
;
|
|
||||||
; For board params see json files in https://github.com/platformio/platform-espressif32/tree/master/boards
|
|
||||||
;
|
;
|
||||||
|
|
||||||
[env:s_4M]
|
[env:s_4M]
|
||||||
extends = espressif32_base_tasmota
|
; 4MB ESP32 - using Tasmota - no SSL, no PSRAM - like a BBQKees older S32 and E32 models
|
||||||
board = esp32dev
|
extends = espressif32_base_T_4M
|
||||||
board_upload.flash_size = 4MB
|
board = s_4M
|
||||||
board_build.partitions = esp32_partition_4M.csv
|
|
||||||
|
|
||||||
[env:s_asym_4M]
|
[env:s_16M]
|
||||||
extends = espressif32_base_tasmota
|
; 16MB ESP32 - using Tasmota - no SSL, no PSRAM - like a BBQKees later S32 models
|
||||||
board = esp32dev
|
extends = espressif32_base_T_16M
|
||||||
board_upload.flash_size = 4MB
|
board = s_16M
|
||||||
board_build.partitions = esp32_asym_partition_4M.csv
|
|
||||||
|
|
||||||
[env:s_16M_P]
|
[env:s_16M_P]
|
||||||
extends = espressif32_base
|
; 16MB ESP32 - with PSRAM - like a BBQKees E32V2
|
||||||
board = esp32dev
|
extends = espressif32_base_16M
|
||||||
board_upload.flash_size = 16MB
|
board = s_16M_P
|
||||||
board_build.partitions = esp32_partition_16M.csv
|
|
||||||
board_build.extra_flags = -DBOARD_HAS_PSRAM
|
[env:s3_16M_P]
|
||||||
|
; 16MB ESP32-S3 - with PSRAM - like a BBQKees S3
|
||||||
|
extends = espressif32_base_16M
|
||||||
|
board = s3_16M_P
|
||||||
|
|
||||||
|
[env:s3_32M_P]
|
||||||
|
; 16MB ESP32-S3 - with PSRAM and 32MB flash
|
||||||
|
extends = espressif32_base_32M
|
||||||
|
board = s3_32M_P
|
||||||
|
|
||||||
|
[env:s2_4M_P]
|
||||||
|
; based on lolin_s2_mini with 2MB PSRAM
|
||||||
|
extends = espressif32_base_T_4M
|
||||||
|
board = s2_4M_P
|
||||||
|
|
||||||
[env:c3_mini_4M]
|
[env:c3_mini_4M]
|
||||||
extends = espressif32_base_tasmota
|
; based on lolin_c3_mini, no PSRAM
|
||||||
board = lolin_c3_mini
|
extends = espressif32_base_T_4M
|
||||||
board_upload.flash_size = 4MB
|
board = c3_mini_4M
|
||||||
board_build.partitions = esp32_partition_4M.csv
|
|
||||||
|
|
||||||
; lolin C3 mini v1 needs special wifi init.
|
; lolin C3 mini v1 needs special wifi initialization
|
||||||
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||||
[env:c3_miniv1_4M]
|
[env:c3_miniv1_4M]
|
||||||
extends = espressif32_base_tasmota
|
extends = espressif32_base_T_4M
|
||||||
board = lolin_c3_mini
|
board = c3_mini_4M
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
board_build.partitions = esp32_partition_4M.csv
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.build_flags}
|
${common.build_flags}
|
||||||
-DTASMOTA_SDK
|
-DTASMOTA_SDK
|
||||||
-DBOARD_C3_MINI_V1
|
-DBOARD_C3_MINI_V1
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
[env:s2_4M]
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
extends = espressif32_base_tasmota
|
|
||||||
board = lolin_s2_mini
|
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
board_build.partitions = esp32_partition_4M.csv
|
|
||||||
|
|
||||||
; https://github.com/platformio/platform-espressif32/blob/master/boards/lolin_s3.json
|
|
||||||
[env:s3_16M_P]
|
|
||||||
extends = espressif32_base
|
|
||||||
board = lolin_s3
|
|
||||||
board_upload.use_1200bps_touch = false
|
|
||||||
board_upload.wait_for_upload_port = false
|
|
||||||
board_upload.flash_size = 16MB
|
|
||||||
board_build.partitions = esp32_partition_16M.csv
|
|
||||||
|
|
||||||
[env:s3_32M_P]
|
|
||||||
extends = espressif32_base
|
|
||||||
board = lolin_s3
|
|
||||||
board_build.arduino.memory_type: opi_opi
|
|
||||||
board_build.flash_mode = opi
|
|
||||||
board_upload.flash_size = 32MB
|
|
||||||
board_build.partitions = esp32_partition_32M.csv
|
|
||||||
|
|
||||||
;
|
;
|
||||||
; Building and testing natively, standalone without an ESP32.
|
; Building and testing natively, standalone without an ESP32.
|
||||||
@@ -208,34 +201,33 @@ platform = native
|
|||||||
build_flags =
|
build_flags =
|
||||||
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
|
||||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||||
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.1-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.2-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||||
-std=gnu++14 -Og -ggdb
|
-std=gnu++17 -Og -ggdb
|
||||||
|
build_unflags = -std=gnu++11 -std=gnu++14
|
||||||
build_type = debug
|
build_type = debug
|
||||||
build_src_flags =
|
build_src_flags =
|
||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||||
|
-I./src/core
|
||||||
-I./lib_standalone
|
-I./lib_standalone
|
||||||
-I./lib/uuid-common/src
|
-I./lib/uuid-common/src
|
||||||
-I./lib/uuid-console/src
|
-I./lib/uuid-console/src
|
||||||
-I./lib/uuid-log/src
|
-I./lib/uuid-log/src
|
||||||
-I./lib/semver
|
-I./lib/semver
|
||||||
-I./lib/PButton
|
-I./lib/PButton
|
||||||
-I./lib/ArduinoJson
|
|
||||||
-I./lib/espMqttClient/src
|
-I./lib/espMqttClient/src
|
||||||
-I./lib/espMqttClient/src/Transport
|
-I./lib/espMqttClient/src/Transport
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>
|
+<../src>
|
||||||
|
+<../lib>
|
||||||
+<../lib_standalone>
|
+<../lib_standalone>
|
||||||
+<../lib/uuid-common>
|
-<../src/ESP32React>
|
||||||
+<../lib/uuid-console>
|
-<../lib/uuid-telnet>
|
||||||
+<../lib/uuid-log>
|
-<../lib/uuid-syslog>
|
||||||
+<../lib/semver>
|
-<../lib/eModbus>
|
||||||
+<../lib/PButton>
|
-<../lib/OneWire>
|
||||||
+<../lib/espMqttClient/src>
|
|
||||||
+<../lib/espMqttClient/src/Transport>
|
|
||||||
lib_compat_mode = off
|
|
||||||
lib_ldf_mode = off
|
lib_ldf_mode = off
|
||||||
lib_ignore = Module EMS-ESP-Modules
|
lib_deps =
|
||||||
|
|
||||||
; unit tests
|
; unit tests
|
||||||
; The code is in ./test/test_api.*
|
; The code is in ./test/test_api.*
|
||||||
@@ -250,37 +242,35 @@ build_flags =
|
|||||||
-DEMSESP_STANDALONE -DEMSESP_TEST
|
-DEMSESP_STANDALONE -DEMSESP_TEST
|
||||||
-DEMSESP_UNITY
|
-DEMSESP_UNITY
|
||||||
; -DEMSESP_UNITY_CREATE
|
; -DEMSESP_UNITY_CREATE
|
||||||
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.1-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.2-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||||
-std=gnu++14 -Os -ggdb -Wall -Wextra
|
-std=gnu++17 -Og -ggdb
|
||||||
-lgcov --coverage -fprofile-arcs -ftest-coverage
|
-lgcov --coverage -fprofile-arcs -ftest-coverage
|
||||||
build_type = debug
|
build_type = debug
|
||||||
build_src_flags =
|
build_src_flags =
|
||||||
|
-Wall -Wextra
|
||||||
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
|
||||||
|
-I./src/core
|
||||||
-I./lib_standalone
|
-I./lib_standalone
|
||||||
-I./lib/uuid-common/src
|
-I./lib/uuid-common/src
|
||||||
-I./lib/uuid-console/src
|
-I./lib/uuid-console/src
|
||||||
-I./lib/uuid-log/src
|
-I./lib/uuid-log/src
|
||||||
-I./lib/semver
|
-I./lib/semver
|
||||||
-I./lib/PButton
|
-I./lib/PButton
|
||||||
-I./lib/ArduinoJson
|
|
||||||
-I./lib/espMqttClient/src
|
-I./lib/espMqttClient/src
|
||||||
-I./lib/espMqttClient/src/Transport
|
-I./lib/espMqttClient/src/Transport
|
||||||
-I./test/api
|
-I./test/api
|
||||||
-I./test
|
-I./test
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>
|
+<../src>
|
||||||
-<src/main.cpp>
|
|
||||||
+<../test>
|
+<../test>
|
||||||
|
+<../lib>
|
||||||
+<../lib_standalone>
|
+<../lib_standalone>
|
||||||
+<../lib/uuid-common>
|
-<../src/ESP32React>
|
||||||
+<../lib/uuid-console>
|
-<../lib/uuid-telnet>
|
||||||
+<../lib/uuid-log>
|
-<../lib/uuid-syslog>
|
||||||
+<../lib/semver>
|
-<../lib/eModbus>
|
||||||
+<../lib/PButton>
|
-<../lib/OneWire>
|
||||||
+<../lib/espMqttClient/src>
|
|
||||||
+<../lib/espMqttClient/src/Transport>
|
|
||||||
lib_ldf_mode = off
|
lib_ldf_mode = off
|
||||||
lib_deps = Unity
|
lib_deps = Unity
|
||||||
lib_ignore = Module EMS-ESP-Modules
|
|
||||||
test_testing_command =
|
test_testing_command =
|
||||||
${platformio.build_dir}/${this.__env__}/program
|
${platformio.build_dir}/${this.__env__}/program
|
||||||
|
|||||||
@@ -1400,4 +1400,11 @@ roomload
|
|||||||
intvl
|
intvl
|
||||||
Français
|
Français
|
||||||
lltoa
|
lltoa
|
||||||
redthreshold
|
redthreshold
|
||||||
|
JTAG
|
||||||
|
fuelheat
|
||||||
|
elheat
|
||||||
|
elgenheat
|
||||||
|
fueldhw
|
||||||
|
eldhw
|
||||||
|
elgendhw
|
||||||
@@ -3,7 +3,6 @@ import os
|
|||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
|
|
||||||
def buildWeb():
|
def buildWeb():
|
||||||
os.chdir("interface")
|
os.chdir("interface")
|
||||||
print("Building web interface...")
|
print("Building web interface...")
|
||||||
@@ -20,6 +19,9 @@ def buildWeb():
|
|||||||
finally:
|
finally:
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
# Don't buuld webUI if called from GitHub Actions
|
||||||
if not (env.IsCleanTarget()):
|
if "NO_BUILD_WEBUI" in os.environ:
|
||||||
buildWeb()
|
print("!! Skipping the build of the web interface !!")
|
||||||
|
else:
|
||||||
|
if not (env.IsCleanTarget()):
|
||||||
|
buildWeb()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Builds the dump CSV files, modbus headers and documentation.
|
# Builds the dump_*.csv files, modbus headers and modbus documentation.
|
||||||
# Called by /scripts/generate_csv_and_headers.sh
|
# Run as `sh scripts/generate_csv_and_headers.sh` from the root of the repository.
|
||||||
|
|
||||||
# build dummy modbus_entity_parameters.hpp so it compiles
|
# create a dummy modbus_entity_parameters.hpp so the first pass compiles
|
||||||
cat >./src/modbus_entity_parameters.hpp <<EOL
|
cat >./src/modbus_entity_parameters.hpp <<EOL
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
#include "emsdevice.h"
|
#include "emsdevice.h"
|
||||||
|
|||||||
@@ -100,17 +100,17 @@ def bin_copy(source, target, env):
|
|||||||
file1.close()
|
file1.close()
|
||||||
|
|
||||||
# make a copy using the old 3.6.x filename format for backwards compatibility with the WebUI version check, e.g.
|
# make a copy using the old 3.6.x filename format for backwards compatibility with the WebUI version check, e.g.
|
||||||
# create a EMS-ESP-<version>-ESP32_S3.bin if target is ci_s3_16M_P (16MB, PSRAM)
|
# create a EMS-ESP-<version>-ESP32_S3.bin if target is s3_16M_P (16MB, PSRAM)
|
||||||
# create a EMS-ESP-<version>-ESP32.bin if target is ci_s_4M (4MB, no PSRAM), compatible only with S32 V1 and E32 V1.0,1.4,1.5
|
# create a EMS-ESP-<version>-ESP32.bin if target is s_4M (4MB, no PSRAM), compatible only with S32 V1 and E32 V1.0,1.4,1.5
|
||||||
#
|
#
|
||||||
# Note: there is a chance newer E32V2s (which use the 16MB partition table and PSRAM) are running a custom build
|
# Note: there is a chance newer E32V2s (which use the 16MB partition table and PSRAM) are running a custom build
|
||||||
# of the 3.6.5 firmware as 3.6.5 was released before production of the gateway board. Updating via the WebUI will break the system and require a manual update.
|
# of the 3.6.5 firmware as 3.6.5 was released before production of the gateway board. Updating via the WebUI will break the system and require a manual update.
|
||||||
#
|
#
|
||||||
extra_variant = ""
|
extra_variant = ""
|
||||||
if env.get('PIOENV') == "ci_s3_16M_P":
|
if env.get('PIOENV') == "s3_16M_P":
|
||||||
extra_variant = "EMS-ESP-" + \
|
extra_variant = "EMS-ESP-" + \
|
||||||
app_version.replace(".", "_") + "-ESP32_S3"
|
app_version.replace(".", "_") + "-ESP32_S3"
|
||||||
elif env.get('PIOENV') == "ci_s_4M":
|
elif env.get('PIOENV') == "s_4M":
|
||||||
extra_variant = "EMS-ESP-" + app_version.replace(".", "_") + "-ESP32"
|
extra_variant = "EMS-ESP-" + app_version.replace(".", "_") + "-ESP32"
|
||||||
|
|
||||||
if extra_variant:
|
if extra_variant:
|
||||||
|
|||||||
13
scripts/show_mem.sh
Normal file
13
scripts/show_mem.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo -n "Arduino: "
|
||||||
|
curl -s http://10.10.10.93/api/system/system/arduino | jq -r '.value'
|
||||||
|
|
||||||
|
echo -n "SDK: "
|
||||||
|
curl -s http://10.10.10.93/api/system/system/sdk | jq -r '.value'
|
||||||
|
|
||||||
|
echo -n "Free heap: "
|
||||||
|
curl -s http://10.10.10.93/api/system/system/freeMem | jq -r '.value'
|
||||||
|
|
||||||
|
echo -n "Max Alloc: "
|
||||||
|
curl -s http://10.10.10.93/api/system/system/maxAlloc | jq -r '.value'
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# run from root folder
|
# run from root folder, like `sh ./scripts/update_all.sh`
|
||||||
# make sure ncu is installed globally (https://github.com/raineorshine/npm-check-updates)
|
# make sure ncu is installed globally (https://github.com/raineorshine/npm-check-updates)
|
||||||
# as well as GNUMake (make) and python3
|
# as well as GNUMake (make) and python3
|
||||||
|
|
||||||
cd interface
|
cd interface
|
||||||
rm -rf yarn.lock node_modules
|
rm -rf yarn.lock node_modules
|
||||||
|
touch yarn.lock
|
||||||
ncu -u
|
ncu -u
|
||||||
yarn set version stable
|
yarn set version stable
|
||||||
yarn
|
yarn
|
||||||
@@ -14,6 +15,7 @@ yarn lint
|
|||||||
|
|
||||||
cd ../mock-api
|
cd ../mock-api
|
||||||
rm -rf yarn.lock node_modules
|
rm -rf yarn.lock node_modules
|
||||||
|
touch yarn.lock
|
||||||
ncu -u
|
ncu -u
|
||||||
yarn set version stable
|
yarn set version stable
|
||||||
yarn
|
yarn
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ cpp_entry_template = Template(
|
|||||||
# read translations
|
# read translations
|
||||||
listNames = {}
|
listNames = {}
|
||||||
transre = re.compile(r'^MAKE_TRANSLATION\(([^,\s]+)\s*,\s*\"([^\"]+)\"')
|
transre = re.compile(r'^MAKE_TRANSLATION\(([^,\s]+)\s*,\s*\"([^\"]+)\"')
|
||||||
transf = open('./src/locale_translations.h', 'r')
|
transf = open('./src/core/locale_translations.h', 'r')
|
||||||
while True:
|
while True:
|
||||||
line = transf.readline()
|
line = transf.readline()
|
||||||
if not line:
|
if not line:
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import requests
|
|||||||
import hashlib
|
import hashlib
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -159,5 +161,6 @@ def on_upload(source, target, env):
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
if env.get('UPLOAD_PROTOCOL') == 'custom':
|
||||||
env.Replace(UPLOADCMD=on_upload)
|
env.Replace(UPLOADCMD=on_upload)
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
sonar.organization=emsesp
|
sonar.organization=emsesp
|
||||||
sonar.projectKey=emsesp_EMS-ESP32
|
sonar.projectKey=emsesp_EMS-ESP32
|
||||||
sonar.projectName=EMS-ESP32
|
sonar.projectName=EMS-ESP32
|
||||||
sonar.projectVersion=3.7.1
|
sonar.projectVersion=3.7.2
|
||||||
sonar.sources=./src
|
sonar.sources=./src
|
||||||
sonar.cfamily.compile-commands=compile_commands.json
|
sonar.cfamily.compile-commands=compile_commands.json
|
||||||
sonar.sourceEncoding=UTF-8
|
sonar.sourceEncoding=UTF-8
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "APSettingsService.h"
|
#include "APSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include <emsesp_stub.hpp>
|
||||||
|
|
||||||
APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(APSettings::read, APSettings::update, this, server, AP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(APSettings::read, APSettings::update, this, server, AP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
||||||
: _apSettingsService(apSettingsService) {
|
: _apSettingsService(apSettingsService) {
|
||||||
server->on(AP_STATUS_SERVICE_PATH,
|
securityManager->addEndpoint(server, AP_STATUS_SERVICE_PATH, AuthenticationPredicates::IS_AUTHENTICATED, [this](AsyncWebServerRequest * request) {
|
||||||
HTTP_GET,
|
apStatus(request);
|
||||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { apStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
||||||
@@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager) {
|
: _securityManager(securityManager) {
|
||||||
|
// none of these need authentication
|
||||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { verifyAuthorization(request); });
|
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { verifyAuthorization(request); });
|
||||||
server->on(SIGN_IN_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); });
|
auto * handler = new AsyncCallbackJsonWebHandler(SIGN_IN_PATH);
|
||||||
|
handler->onRequest([this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); });
|
||||||
|
server->addHandler(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies that the request supplied a valid JWT.
|
// Verifies that the request supplied a valid JWT.
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef AuthenticationService_H_
|
#ifndef AuthenticationService_H_
|
||||||
#define AuthenticationService_H_
|
#define AuthenticationService_H_
|
||||||
|
|
||||||
#include "Features.h"
|
|
||||||
#include "SecurityManager.h"
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "ESP8266React.h"
|
#include "ESP32React.h"
|
||||||
|
|
||||||
#include "WWWData.h" // include auto-generated static web resources
|
#include "WWWData.h" // include auto-generated static web resources
|
||||||
|
|
||||||
ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
ESP32React::ESP32React(AsyncWebServer * server, FS * fs)
|
||||||
: _securitySettingsService(server, fs)
|
: _securitySettingsService(server, fs)
|
||||||
, _networkSettingsService(server, fs, &_securitySettingsService)
|
, _networkSettingsService(server, fs, &_securitySettingsService)
|
||||||
, _wifiScanner(server, &_securitySettingsService)
|
, _wifiScanner(server, &_securitySettingsService)
|
||||||
@@ -32,7 +32,7 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
|||||||
return request->send(304);
|
return request->send(304);
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse * response = request->beginResponse_P(200, contentType, content, len);
|
AsyncWebServerResponse * response = request->beginResponse(200, contentType, content, len);
|
||||||
|
|
||||||
response->addHeader("Content-Encoding", "gzip");
|
response->addHeader("Content-Encoding", "gzip");
|
||||||
// response->addHeader("Content-Encoding", "br"); // only works over HTTPS
|
// response->addHeader("Content-Encoding", "br"); // only works over HTTPS
|
||||||
@@ -62,7 +62,7 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266React::begin() {
|
void ESP32React::begin() {
|
||||||
_networkSettingsService.begin();
|
_networkSettingsService.begin();
|
||||||
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
||||||
DefaultHeaders & defaultHeaders = DefaultHeaders::Instance();
|
DefaultHeaders & defaultHeaders = DefaultHeaders::Instance();
|
||||||
@@ -79,7 +79,7 @@ void ESP8266React::begin() {
|
|||||||
_securitySettingsService.begin();
|
_securitySettingsService.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266React::loop() {
|
void ESP32React::loop() {
|
||||||
_networkSettingsService.loop();
|
_networkSettingsService.loop();
|
||||||
_apSettingsService.loop();
|
_apSettingsService.loop();
|
||||||
_mqttSettingsService.loop();
|
_mqttSettingsService.loop();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef ESP8266React_h
|
#ifndef ESP32React_h
|
||||||
#define ESP8266React_h
|
#define ESP32React_h
|
||||||
|
|
||||||
#include "APSettingsService.h"
|
#include "APSettingsService.h"
|
||||||
#include "APStatus.h"
|
#include "APStatus.h"
|
||||||
@@ -15,12 +15,14 @@
|
|||||||
#include "NetworkStatus.h"
|
#include "NetworkStatus.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <AsyncJson.h>
|
||||||
|
#include <AsyncMessagePack.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
class ESP8266React {
|
class ESP32React {
|
||||||
public:
|
public:
|
||||||
ESP8266React(AsyncWebServer * server, FS * fs);
|
ESP32React(AsyncWebServer * server, FS * fs);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
void loop();
|
void loop();
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "StatefulService.h"
|
#include "StatefulService.h"
|
||||||
|
|
||||||
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
||||||
#define HTTPS_ENDPOINT_ORIGIN_ID "https"
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class HttpEndpoint {
|
class HttpEndpoint {
|
||||||
@@ -29,9 +28,8 @@ class HttpEndpoint {
|
|||||||
, _stateUpdater(stateUpdater)
|
, _stateUpdater(stateUpdater)
|
||||||
, _statefulService(statefulService) {
|
, _statefulService(statefulService) {
|
||||||
// Create handler for both GET and POST endpoints
|
// Create handler for both GET and POST endpoints
|
||||||
server->on(servicePath.c_str(),
|
securityManager->addEndpoint(
|
||||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { handleRequest(request, json); },
|
server, servicePath, authenticationPredicate, [this](AsyncWebServerRequest * request, JsonVariant json) { handleRequest(request, json); }, HTTP_ANY); // ALL methods
|
||||||
authenticationPredicate));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "MqttSettingsService.h"
|
#include "MqttSettingsService.h"
|
||||||
#include "../../src/emsesp_stub.hpp"
|
|
||||||
|
#include <emsesp_stub.hpp>
|
||||||
|
|
||||||
MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(MqttSettings::read, MqttSettings::update, this, server, MQTT_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(MqttSettings::read, MqttSettings::update, this, server, MQTT_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#include "MqttStatus.h"
|
#include "MqttStatus.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include <emsesp_stub.hpp>
|
||||||
|
|
||||||
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
||||||
: _mqttSettingsService(mqttSettingsService) {
|
: _mqttSettingsService(mqttSettingsService) {
|
||||||
server->on(MQTT_STATUS_SERVICE_PATH,
|
securityManager->addEndpoint(server, MQTT_STATUS_SERVICE_PATH, AuthenticationPredicates::IS_AUTHENTICATED, [this](AsyncWebServerRequest * request) {
|
||||||
HTTP_GET,
|
mqttStatus(request);
|
||||||
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { mqttStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
#include "NTPSettingsService.h"
|
#include "NTPSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include <emsesp_stub.hpp>
|
||||||
|
|
||||||
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
||||||
, _connected(false) {
|
, _connected(false) {
|
||||||
server->on(TIME_PATH,
|
// POST
|
||||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { configureTime(request, json); },
|
securityManager->addEndpoint(server, TIME_PATH, AuthenticationPredicates::IS_ADMIN, [this](AsyncWebServerRequest * request, JsonVariant json) {
|
||||||
AuthenticationPredicates::IS_ADMIN));
|
configureTime(request, json);
|
||||||
|
});
|
||||||
|
|
||||||
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||||
addUpdateHandler([this] { configureNTP(); }, false);
|
addUpdateHandler([this] { configureNTP(); }, false);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user