forked from Links2004/arduinoWebSockets
Compare commits
132 Commits
esp8266_ba
...
master
Author | SHA1 | Date | |
---|---|---|---|
1789a18ddb | |||
ca8026e550 | |||
daf04b0560 | |||
8cdcf47fc5 | |||
1bea689694 | |||
7a4c416082 | |||
87b23a48e9 | |||
bd011d8fd8 | |||
af17970256 | |||
66f69c3b20 | |||
d41d65ccdc | |||
2e54e8b9c6 | |||
2059fc5c3b | |||
b60be0e3c5 | |||
e8006439a2 | |||
0980b209ba | |||
899cfbdbe7 | |||
dcfb0df665 | |||
dc6fd04a98 | |||
7da1dc5c6e | |||
d6d4c516b3 | |||
e364e66884 | |||
d5f0d3c4b5 | |||
0e127c9a76 | |||
11cf06897c | |||
af1b0256b9 | |||
c5e7a5eb08 | |||
93707d455f | |||
8d193b176d | |||
503105a9fe | |||
6a26f74f95 | |||
be9fd8e267 | |||
313f2e0170 | |||
3b143bc6f3 | |||
aed167bee0 | |||
4acc33589a | |||
3352c833b8 | |||
241c73a806 | |||
437c0252f1 | |||
92480b8987 | |||
da7efc789e | |||
30d5e13666 | |||
751cf87b6c | |||
a215cca4fe | |||
bb900a77b6 | |||
7eda34f345 | |||
22dff6598f | |||
a4f13a1410 | |||
4115a87c16 | |||
82c357c036 | |||
d9a5c629f0 | |||
323592f622 | |||
f1ffaede0b | |||
94a531c464 | |||
ccdba4ed8a | |||
2b0e8f6fe9 | |||
dd8675c6a9 | |||
2110ad0a10 | |||
04249a9b62 | |||
1fb67c8868 | |||
3073c156b1 | |||
5881a99a30 | |||
52b3aa8ea4 | |||
28c0cf3094 | |||
ab9af162b2 | |||
8d76469e90 | |||
61ea44942e | |||
28ed615145 | |||
108090e8cf | |||
46b2ae1c97 | |||
27f86a10ad | |||
860ac9da69 | |||
c897f60567 | |||
b242882ac5 | |||
f8da05aa87 | |||
72aae52655 | |||
a14b6b73b4 | |||
ed685e551f | |||
7c3b1b7408 | |||
738e43fda4 | |||
f55bf8d4ed | |||
a484da47ed | |||
4355199120 | |||
0a4fcd44c2 | |||
3a2b757155 | |||
900d81e534 | |||
0ecef8c552 | |||
410489f7c5 | |||
ec22d67c12 | |||
39e6a8e709 | |||
784b7f9cb8 | |||
fd83d6ad45 | |||
0e729cd896 | |||
2f21590e55 | |||
c98baafda7 | |||
983b9801fb | |||
e70262dab9 | |||
4a05eab627 | |||
822618f606 | |||
1b4f186fa6 | |||
c68e015322 | |||
dc30a2b7bf | |||
6bee53a8bd | |||
ebb87cdc8a | |||
e7ab913693 | |||
52547ec47c | |||
74411bf729 | |||
f0cc36dede | |||
074a674833 | |||
8239e1625e | |||
c5900db636 | |||
9470961d85 | |||
04919f848f | |||
25318111a1 | |||
08caf3bfc6 | |||
fb26433e75 | |||
4f52a0f38e | |||
f20fbbfcd9 | |||
28cd929e7e | |||
826c6b423a | |||
7fea0b8bdf | |||
4db14451fb | |||
80bf087cd0 | |||
5caff59f7f | |||
b90fe4c1d7 | |||
a086303c87 | |||
217c7ce4ea | |||
13a304a8c9 | |||
9b873978ba | |||
508e0fb691 | |||
083683425f | |||
370f217a30 |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
10
.github/workflows/arduino-lint.yaml
vendored
Normal file
10
.github/workflows/arduino-lint.yaml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name: Arduino library compliance (Lint)
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: arduino/arduino-lint-action@v2
|
||||||
|
with:
|
||||||
|
library-manager: update
|
69
.github/workflows/compile-arduino_wifinina-examples.yaml
vendored
Normal file
69
.github/workflows/compile-arduino_wifinina-examples.yaml
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
name: Compile Arduino WiFiNINA Examples
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-arduino_wifinina-examples.yaml"
|
||||||
|
- "examples/arduino_wifinina/**"
|
||||||
|
- "src/**"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-arduino_wifinina-examples.yaml"
|
||||||
|
- "examples/arduino_wifinina/**"
|
||||||
|
- "src/**"
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.board.fqbn }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
SKETCHES_REPORTS_PATH: sketches-reports
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
board:
|
||||||
|
- fqbn: arduino:samd:mkrwifi1010
|
||||||
|
platforms: |
|
||||||
|
- name: arduino:samd
|
||||||
|
artifact-name-suffix: arduino-samd-mkrwifi1010
|
||||||
|
libraries: |
|
||||||
|
- name: WiFiNINA
|
||||||
|
- fqbn: arduino:samd:nano_33_iot
|
||||||
|
platforms: |
|
||||||
|
- name: arduino:samd
|
||||||
|
artifact-name-suffix: arduino-samd-nano_33_iot
|
||||||
|
libraries: |
|
||||||
|
- name: WiFiNINA
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Compile examples
|
||||||
|
uses: arduino/compile-sketches@v1
|
||||||
|
with:
|
||||||
|
fqbn: ${{ matrix.board.fqbn }}
|
||||||
|
platforms: ${{ matrix.board.platforms }}
|
||||||
|
libraries: |
|
||||||
|
# Install the library from the local path.
|
||||||
|
- source-path: ./
|
||||||
|
${{ matrix.board.libraries }}
|
||||||
|
sketch-paths: |
|
||||||
|
- examples/arduino_wifinina/arduino_wifinina.ino
|
||||||
|
enable-deltas-report: true
|
||||||
|
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
|
||||||
|
- name: Save sketches report as workflow artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
if-no-files-found: error
|
||||||
|
path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
name: sketches-report-${{ matrix.board.artifact-name-suffix }}
|
81
.github/workflows/compile-seeed-studio-examples.yaml
vendored
Normal file
81
.github/workflows/compile-seeed-studio-examples.yaml
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
name: Compile SeedStudio Examples
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-seeed-studio-examples.yaml"
|
||||||
|
- "examples/seeed-studio/**"
|
||||||
|
- "src/**"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-seeed-studio-examples.yaml"
|
||||||
|
- "examples/seeed-studio/**"
|
||||||
|
- "src/**"
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.board.fqbn }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
SKETCHES_REPORTS_PATH: sketches-reports
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
board:
|
||||||
|
- fqbn: Seeeduino:samd:seeed_XIAO_m0:usbstack=arduino,debug=off
|
||||||
|
platforms: |
|
||||||
|
- name: Seeeduino:samd
|
||||||
|
source-url: https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
|
||||||
|
libraries: |
|
||||||
|
- name: Seeed Arduino rpcWiFi
|
||||||
|
- name: Seeed Arduino rpcUnified
|
||||||
|
- name: Seeed_Arduino_mbedtls
|
||||||
|
- name: Seeed Arduino FS
|
||||||
|
- name: Seeed Arduino SFUD
|
||||||
|
artifact-name-suffix: seeeduino-xia0
|
||||||
|
- fqbn: Seeeduino:samd:seeed_wio_terminal
|
||||||
|
platforms: |
|
||||||
|
- name: Seeeduino:samd
|
||||||
|
source-url: https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
|
||||||
|
libraries: |
|
||||||
|
- name: Seeed Arduino rpcWiFi
|
||||||
|
- name: Seeed Arduino rpcUnified
|
||||||
|
- name: Seeed_Arduino_mbedtls
|
||||||
|
- name: Seeed Arduino FS
|
||||||
|
- name: Seeed Arduino SFUD
|
||||||
|
artifact-name-suffix: seeeduino-wio_terminal
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Compile examples
|
||||||
|
uses: arduino/compile-sketches@v1
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
fqbn: ${{ matrix.board.fqbn }}
|
||||||
|
platforms: ${{ matrix.board.platforms }}
|
||||||
|
libraries: |
|
||||||
|
# Install the library from the local path.
|
||||||
|
- source-path: ./
|
||||||
|
${{ matrix.board.libraries }}
|
||||||
|
sketch-paths: |
|
||||||
|
- examples/seeed-studio/xio-wio-terminal/WebSocketClient
|
||||||
|
enable-deltas-report: true
|
||||||
|
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
|
||||||
|
- name: Save sketches report as workflow artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
if-no-files-found: error
|
||||||
|
path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
name: sketches-report-${{ matrix.board.artifact-name-suffix }}
|
60
.github/workflows/compile-unor4wifi-examples.yaml
vendored
Normal file
60
.github/workflows/compile-unor4wifi-examples.yaml
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
name: Compile Arduino UNO R4 WiFi Examples
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-unor4wifi-examples.yaml"
|
||||||
|
- "examples/arduino_renesas/**"
|
||||||
|
- "src/**"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-unor4wifi-examples.yaml"
|
||||||
|
- "examples/arduino_renesas/**"
|
||||||
|
- "src/**"
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.board.fqbn }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
SKETCHES_REPORTS_PATH: sketches-reports
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
board:
|
||||||
|
- fqbn: arduino:renesas_uno:unor4wifi
|
||||||
|
platforms: |
|
||||||
|
- name: arduino:renesas_uno
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Compile examples
|
||||||
|
uses: arduino/compile-sketches@v1
|
||||||
|
with:
|
||||||
|
fqbn: ${{ matrix.board.fqbn }}
|
||||||
|
platforms: ${{ matrix.board.platforms }}
|
||||||
|
libraries: |
|
||||||
|
# Install the library from the local path.
|
||||||
|
- source-path: ./
|
||||||
|
sketch-paths: |
|
||||||
|
- examples/arduino_renesas/arduino_uno_r4_wifi
|
||||||
|
enable-deltas-report: true
|
||||||
|
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
|
||||||
|
- name: Save sketches report as workflow artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
if-no-files-found: error
|
||||||
|
path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
name: sketches-report-${{ matrix.board.artifact-name-suffix }}
|
171
.github/workflows/main.yml
vendored
Normal file
171
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 5'
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
release:
|
||||||
|
types: [ published, created, edited ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
check_version_files:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: check version
|
||||||
|
run: |
|
||||||
|
$GITHUB_WORKSPACE/travis/version.py --check
|
||||||
|
|
||||||
|
prepare_example_json:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: generate examples
|
||||||
|
id: set-matrix
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
|
||||||
|
echo -en "matrix=" >> $GITHUB_OUTPUT
|
||||||
|
echo -en "[" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266_pico esp8266 0.35.3 esp8266:esp8266:generic:xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,ResetMethod=nodemcu,CrystalFreq=26,FlashFreq=80,FlashMode=qio,eesz=4M2M,led=2,sdk=nonosdk_190703,ip=lm2f,dbg=Serial1,lvl=SSL,wipe=none,baud=115200 >> $GITHUB_OUTPUT
|
||||||
|
echo -en "," >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266_pico esp8266 0.35.3 esp8266:esp8266:generic:xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,ResetMethod=nodemcu,CrystalFreq=26,FlashFreq=80,FlashMode=qio,eesz=4M2M,led=2,sdk=nonosdk_190703,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200 >> $GITHUB_OUTPUT
|
||||||
|
echo -en "," >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 0.35.3 esp32:esp32:esp32:FlashFreq=80 >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo -en "]" >> $GITHUB_OUTPUT
|
||||||
|
echo >> $GITHUB_OUTPUT
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
|
||||||
|
prepare_ide:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
CLI_VERSION: [0.35.3]
|
||||||
|
env:
|
||||||
|
CLI_VERSION: ${{ matrix.CLI_VERSION }}
|
||||||
|
ARDUINO_DIRECTORIES_DATA: /home/runner/arduino_ide
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get hash
|
||||||
|
id: get-hash
|
||||||
|
run: |
|
||||||
|
echo "hash=$(/bin/date -u "+%Y%m%d")-$(md5sum ".github/workflows/main.yml" | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-hash.outputs.hash }}-${{ matrix.CLI_VERSION }}-cli
|
||||||
|
|
||||||
|
- name: download IDE
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
wget https://github.com/arduino/arduino-cli/releases/download/v${CLI_VERSION}/arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz -q
|
||||||
|
tar xf arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz
|
||||||
|
mkdir -p $ARDUINO_DIRECTORIES_DATA
|
||||||
|
mv arduino-cli $ARDUINO_DIRECTORIES_DATA/
|
||||||
|
|
||||||
|
- name: download ArduinoJson
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip -q
|
||||||
|
unzip 6.x.zip
|
||||||
|
mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||||
|
|
||||||
|
- name: download cores
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
export PATH="$ARDUINO_DIRECTORIES_DATA:$PATH"
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
get_core_cli
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: [prepare_ide, prepare_example_json]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include: ${{ fromJson(needs.prepare_example_json.outputs.matrix) }}
|
||||||
|
env:
|
||||||
|
CPU: ${{ matrix.cpu }}
|
||||||
|
BOARD: ${{ matrix.board }}
|
||||||
|
CLI_VERSION: ${{ matrix.cliversion }}
|
||||||
|
SKETCH: ${{ matrix.sketch }}
|
||||||
|
ARDUINO_DIRECTORIES_DATA: /home/runner/arduino_ide
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: install libgtk2.0-0
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y libgtk2.0-0
|
||||||
|
|
||||||
|
- name: Get hash
|
||||||
|
id: get-hash
|
||||||
|
run: |
|
||||||
|
echo "hash=$(/bin/date -u "+%Y%m%d")-$(md5sum ".github/workflows/main.yml" | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-hash.outputs.hash }}-${{ matrix.cliversion }}-cli
|
||||||
|
|
||||||
|
- name: install python serial
|
||||||
|
if: matrix.cpu == 'esp32'
|
||||||
|
run: |
|
||||||
|
sudo pip3 install pyserial
|
||||||
|
sudo pip install pyserial
|
||||||
|
# sudo apt install python-is-python3
|
||||||
|
|
||||||
|
- name: test IDE
|
||||||
|
run: |
|
||||||
|
export PATH="$ARDUINO_DIRECTORIES_DATA:$PATH"
|
||||||
|
which arduino-cli
|
||||||
|
|
||||||
|
- name: copy code
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries/
|
||||||
|
cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
|
|
||||||
|
- name: build example
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: |
|
||||||
|
set -ex
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
build_sketch_cli "$SKETCH" "$BOARD"
|
||||||
|
|
||||||
|
done:
|
||||||
|
needs: [prepare_ide, prepare_example_json, build, check_version_files]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Done
|
||||||
|
run: |
|
||||||
|
echo DONE
|
10
.travis.yml
10
.travis.yml
@ -10,8 +10,8 @@ os:
|
|||||||
- linux
|
- linux
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.5
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.13
|
||||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.5
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.13
|
||||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13
|
||||||
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5
|
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5
|
||||||
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9
|
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9
|
||||||
@ -43,9 +43,3 @@ notifications:
|
|||||||
email:
|
email:
|
||||||
on_success: change
|
on_success: change
|
||||||
on_failure: change
|
on_failure: change
|
||||||
webhooks:
|
|
||||||
urls:
|
|
||||||
- https://webhooks.gitter.im/e/1aa78fbe15080b0c2e37
|
|
||||||
on_success: change # options: [always|never|change] default: always
|
|
||||||
on_failure: always # options: [always|never|change] default: always
|
|
||||||
on_start: false # default: false
|
|
||||||
|
33
README.md
33
README.md
@ -1,4 +1,4 @@
|
|||||||
WebSocket Server and Client for Arduino [](https://travis-ci.com/Links2004/arduinoWebSockets)
|
WebSocket Server and Client for Arduino [](https://github.com/Links2004/arduinoWebSockets/actions?query=branch%3Amaster)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
a WebSocket Server and Client for Arduino based on RFC6455.
|
a WebSocket Server and Client for Arduino based on RFC6455.
|
||||||
@ -26,11 +26,15 @@ a WebSocket Server and Client for Arduino based on RFC6455.
|
|||||||
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
|
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
|
||||||
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
|
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
|
||||||
- ESP31B
|
- ESP31B
|
||||||
|
- Raspberry Pi Pico W [Arduino for Pico](https://github.com/earlephilhower/arduino-pico)
|
||||||
- Particle with STM32 ARM Cortex M3
|
- Particle with STM32 ARM Cortex M3
|
||||||
- ATmega328 with Ethernet Shield (ATmega branch)
|
- ATmega328 with Ethernet Shield (ATmega branch)
|
||||||
- ATmega328 with enc28j60 (ATmega branch)
|
- ATmega328 with enc28j60 (ATmega branch)
|
||||||
- ATmega2560 with Ethernet Shield (ATmega branch)
|
- ATmega2560 with Ethernet Shield (ATmega branch)
|
||||||
- ATmega2560 with enc28j60 (ATmega branch)
|
- ATmega2560 with enc28j60 (ATmega branch)
|
||||||
|
- Arduino UNO [R4 WiFi](https://github.com/arduino/ArduinoCore-renesas)
|
||||||
|
- Arduino Nano 33 IoT, MKR WIFI 1010 (requires [WiFiNINA](https://github.com/arduino-libraries/WiFiNINA/) library)
|
||||||
|
- Seeeduino XIAO, Seeeduino Wio Terminal (requires [rpcWiFi](https://github.com/Seeed-Studio/Seeed_Arduino_rpcWiFi) library)
|
||||||
|
|
||||||
###### Note: ######
|
###### Note: ######
|
||||||
|
|
||||||
@ -43,10 +47,21 @@ a WebSocket Server and Client for Arduino based on RFC6455.
|
|||||||
### wss / SSL ###
|
### wss / SSL ###
|
||||||
supported for:
|
supported for:
|
||||||
- wss client on the ESP8266
|
- wss client on the ESP8266
|
||||||
|
- wss / SSL for ESP32 in client mode
|
||||||
- wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets
|
- wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets
|
||||||
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
|
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
|
||||||
sample Nginx server configuration file to enable this.
|
sample Nginx server configuration file to enable this.
|
||||||
|
|
||||||
|
### Root CA Cert Bundles for SSL/TLS connections ###
|
||||||
|
|
||||||
|
Secure connections require the certificate of the server to be verified. One option is to provide a single certificate in the chain of trust. However, for flexibility and robustness, a certificate bundle is recommended. If a server changes the root CA from which it derives its certificates, this will not be a problem. With a single CA cert it will not connect.
|
||||||
|
|
||||||
|
- For [technical details](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html)
|
||||||
|
- For a [PlatformIO setup](https://github.com/Duckle29/esp32-certBundle/)
|
||||||
|
- For an [example](examples/esp32/WebSocketClientSSLBundle/)
|
||||||
|
|
||||||
|
Including a bundle with all CA certs will use 77.2 kB but this list can be reduced to 16.5 kB for the 41 most common. This results in 90% absolute usage coverage and 99% market share coverage according to [W3Techs](https://w3techs.com/technologies/overview/ssl_certificate). The bundle is inserted into the compiled firmware. The bundle is not loaded into RAM, only its index.
|
||||||
|
|
||||||
### ESP Async TCP ###
|
### ESP Async TCP ###
|
||||||
|
|
||||||
This libary can run in Async TCP mode on the ESP.
|
This libary can run in Async TCP mode on the ESP.
|
||||||
@ -62,19 +77,19 @@ The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE
|
|||||||
```c++
|
```c++
|
||||||
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||||
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
||||||
```
|
```
|
||||||
- `onEvent`: Callback to handle for websocket events
|
- `onEvent`: Callback to handle for websocket events
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
void onEvent(WebSocketClientEvent cbEvent);
|
void onEvent(WebSocketClientEvent cbEvent);
|
||||||
```
|
```
|
||||||
|
|
||||||
- `WebSocketClientEvent`: Handler for websocket events
|
- `WebSocketClientEvent`: Handler for websocket events
|
||||||
```c++
|
```c++
|
||||||
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
|
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
|
||||||
```
|
```
|
||||||
Where `WStype_t type` is defined as:
|
Where `WStype_t type` is defined as:
|
||||||
```c++
|
```c++
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WStype_ERROR,
|
WStype_ERROR,
|
||||||
WStype_DISCONNECTED,
|
WStype_DISCONNECTED,
|
||||||
@ -88,13 +103,11 @@ Where `WStype_t type` is defined as:
|
|||||||
WStype_PING,
|
WStype_PING,
|
||||||
WStype_PONG,
|
WStype_PONG,
|
||||||
} WStype_t;
|
} WStype_t;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Issues ###
|
### Issues ###
|
||||||
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
||||||
|
|
||||||
[](https://gitter.im/Links2004/arduinoWebSockets?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
||||||
|
|
||||||
### License and credits ###
|
### License and credits ###
|
||||||
|
|
||||||
The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE)
|
The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE)
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "WiFiS3.h"
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
#define WIFI_SSID ""
|
||||||
|
#define WIFI_PASS ""
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t *payload, size_t length) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
Serial.println("[WSc] Disconnected!");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
Serial.println("[WSc] Connected!");
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
Serial.print("[WSc] get text:");
|
||||||
|
Serial.println((char *)payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
for (uint8_t t = 4; t > 0; t--) {
|
||||||
|
Serial.println("[SETUP] BOOT WAIT ...");
|
||||||
|
Serial.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for the WiFi module:
|
||||||
|
if (WiFi.status() == WL_NO_MODULE) {
|
||||||
|
Serial.println("Communication with WiFi module failed!");
|
||||||
|
// don't continue
|
||||||
|
while (true)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fv = WiFi.firmwareVersion();
|
||||||
|
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
|
||||||
|
Serial.println("Please upgrade the firmware");
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("[Wifi]: Connecting");
|
||||||
|
|
||||||
|
int status = WL_IDLE_STATUS;
|
||||||
|
|
||||||
|
// attempt to connect to WiFi network:
|
||||||
|
while (status != WL_CONNECTED) {
|
||||||
|
Serial.print("[Wifi]: Attempting to connect to SSID: ");
|
||||||
|
Serial.println(WIFI_SSID);
|
||||||
|
|
||||||
|
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
|
||||||
|
status = WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Connected!");
|
||||||
|
|
||||||
|
// print your board's IP address:
|
||||||
|
IPAddress ip = WiFi.localIP();
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(ip);
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("192.168.0.123", 8011);
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
100
examples/arduino_wifinina/arduino_wifinina.ino
Normal file
100
examples/arduino_wifinina/arduino_wifinina.ino
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <WiFiNINA.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
#define WIFI_SSID ""
|
||||||
|
#define WIFI_PASS ""
|
||||||
|
|
||||||
|
int status = WL_IDLE_STATUS;
|
||||||
|
WiFiClient client;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t *payload, size_t length) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
Serial.println("[WSc] Disconnected!");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
Serial.println("[WSc] Connected!");
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
Serial.print("[WSc] get text:");
|
||||||
|
Serial.println((char *)payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_PING:
|
||||||
|
case WStype_PONG:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// check for the WiFi module:
|
||||||
|
if (WiFi.status() == WL_NO_MODULE) {
|
||||||
|
Serial.println("Communication with WiFi module failed!");
|
||||||
|
// don't continue
|
||||||
|
while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
String fv = WiFi.firmwareVersion();
|
||||||
|
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
|
||||||
|
Serial.println("Please upgrade the firmware");
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to connect to WiFi network:
|
||||||
|
while (status != WL_CONNECTED) {
|
||||||
|
Serial.print("Attempting to connect to SSID: ");
|
||||||
|
Serial.println(WIFI_SSID);
|
||||||
|
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
|
||||||
|
status = WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
|
|
||||||
|
// wait 10 seconds for connection:
|
||||||
|
delay(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Connected to WiFi");
|
||||||
|
|
||||||
|
// print your board's IP address:
|
||||||
|
IPAddress ip = WiFi.localIP();
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(ip);
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("192.168.0.123", 8011);
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* main.cpp
|
||||||
|
*
|
||||||
|
* Created on: 15.06.2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
// Use the incbin library to embedd the cert binary
|
||||||
|
// extern const uint8_t rootca_crt_bundle_start[] asm(
|
||||||
|
// "_binary_data_cert_x509_crt_bundle_bin_start");
|
||||||
|
|
||||||
|
WiFiMulti wifiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
void setClock() {
|
||||||
|
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
USE_SERIAL.print(F("Waiting for NTP time sync: "));
|
||||||
|
time_t nowSecs = time(nullptr);
|
||||||
|
while(nowSecs < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
USE_SERIAL.print(F("."));
|
||||||
|
yield();
|
||||||
|
nowSecs = time(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&nowSecs, &timeinfo);
|
||||||
|
USE_SERIAL.print(F("Current time: "));
|
||||||
|
USE_SERIAL.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t * src = (const uint8_t *)mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiMulti.addAP("SSID", "WIFI_PASSPHRASE");
|
||||||
|
|
||||||
|
// WiFi.disconnect();
|
||||||
|
while(wifiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
setClock();
|
||||||
|
|
||||||
|
// server address, port and URL. This server can be flakey.
|
||||||
|
// Expected response: Request served by 0123456789abcdef
|
||||||
|
// webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, "");
|
||||||
|
// ESP32 3.0.4 or higher needs the size of the bundle
|
||||||
|
// webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, sizeof(rootca_crt_bundle_start), "");
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", NULL, 0, "");
|
||||||
|
#else
|
||||||
|
webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", NULL, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional enable if needed
|
||||||
|
// webSocket.setAuthorization("user", "Password");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSocketIOack.ino
|
||||||
|
*
|
||||||
|
* Created on: 20.07.2019
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
#include <SocketIOclient.h>
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
SocketIOclient socketIO;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
|
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
|
break;
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
{
|
||||||
|
char * sptr = NULL;
|
||||||
|
int id = strtol((char *)payload, &sptr, 10);
|
||||||
|
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
|
||||||
|
if(id) {
|
||||||
|
payload = (uint8_t *)sptr;
|
||||||
|
}
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
DeserializationError error = deserializeJson(doc, payload, length);
|
||||||
|
if(error) {
|
||||||
|
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||||
|
USE_SERIAL.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String eventName = doc[0];
|
||||||
|
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
||||||
|
|
||||||
|
// Message Includes a ID for a ACK (callback)
|
||||||
|
if(id) {
|
||||||
|
// create JSON message for Socket.IO (ack)
|
||||||
|
DynamicJsonDocument docOut(1024);
|
||||||
|
JsonArray array = docOut.to<JsonArray>();
|
||||||
|
|
||||||
|
// add payload (parameters) for the ack (callback function)
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = millis();
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
output += id;
|
||||||
|
serializeJson(docOut, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.send(sIOtype_ACK, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case sIOtype_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
//USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = WiFi.localIP().toString();
|
||||||
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
socketIO.onEvent(socketIOEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long messageTimestamp = 0;
|
||||||
|
void loop() {
|
||||||
|
socketIO.loop();
|
||||||
|
|
||||||
|
uint64_t now = millis();
|
||||||
|
|
||||||
|
if(now - messageTimestamp > 2000) {
|
||||||
|
messageTimestamp = now;
|
||||||
|
|
||||||
|
// create JSON message for Socket.IO (event)
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
|
// add event name
|
||||||
|
// Hint: socket.on('event_name', ....
|
||||||
|
array.add("event_name");
|
||||||
|
|
||||||
|
// add payload (parameters) for the event
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = (uint32_t) now;
|
||||||
|
|
||||||
|
// JSON to String (serialization)
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
|
// Print JSON for debugging
|
||||||
|
USE_SERIAL.println(output);
|
||||||
|
}
|
||||||
|
}
|
@ -42,8 +42,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length
|
|||||||
IPAddress ip = webSocket.remoteIP(num);
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
// send message to client
|
// send message to client
|
||||||
webSocket.sendTXT(num, "Connected");
|
webSocket.sendTXT(num, "Connected");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WStype_TEXT:
|
case WStype_TEXT:
|
||||||
@ -62,12 +62,12 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length
|
|||||||
// send message to client
|
// send message to client
|
||||||
// webSocket.sendBIN(num, payload, length);
|
// webSocket.sendBIN(num, payload, length);
|
||||||
break;
|
break;
|
||||||
case WStype_ERROR:
|
case WStype_ERROR:
|
||||||
case WStype_FRAGMENT_TEXT_START:
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
case WStype_FRAGMENT_BIN_START:
|
case WStype_FRAGMENT_BIN_START:
|
||||||
case WStype_FRAGMENT:
|
case WStype_FRAGMENT:
|
||||||
case WStype_FRAGMENT_FIN:
|
case WStype_FRAGMENT_FIN:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
8
examples/esp32_pio/WebSocketClientSSLBundle/.gitignore
vendored
Normal file
8
examples/esp32_pio/WebSocketClientSSLBundle/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
|
*secret*
|
||||||
|
!*secrets.hpp.template
|
||||||
|
*x509_crt_bundle.bin
|
3581
examples/esp32_pio/WebSocketClientSSLBundle/cacrt_all.pem
Normal file
3581
examples/esp32_pio/WebSocketClientSSLBundle/cacrt_all.pem
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@
|
|||||||
|
Owner,Common Name or Certificate Name
|
||||||
|
Amazon Trust Services,Amazon Root CA 1
|
||||||
|
Amazon Trust Services,Amazon Root CA 2
|
||||||
|
Amazon Trust Services,Amazon Root CA 3
|
||||||
|
Amazon Trust Services,Amazon Root CA 4
|
||||||
|
Amazon Trust Services,Starfield Services Root Certificate Authority - G2
|
||||||
|
DigiCert,Baltimore CyberTrust Root
|
||||||
|
DigiCert,Cybertrust Global Root
|
||||||
|
DigiCert,DigiCert Assured ID Root CA
|
||||||
|
DigiCert,DigiCert Assured ID Root G2
|
||||||
|
DigiCert,DigiCert Assured ID Root G3
|
||||||
|
DigiCert,DigiCert Global Root CA
|
||||||
|
DigiCert,DigiCert Global Root G2
|
||||||
|
DigiCert,DigiCert Global Root G3
|
||||||
|
DigiCert,DigiCert High Assurance EV Root CA
|
||||||
|
DigiCert,DigiCert Trusted Root G4
|
||||||
|
GlobalSign,GlobalSign ECC Root CA - R5
|
||||||
|
GlobalSign,GlobalSign Root CA - R3
|
||||||
|
GlobalSign,GlobalSign Root CA - R6
|
||||||
|
GlobalSign,GlobalSign Root CA
|
||||||
|
GoDaddy,Go Daddy Class 2 CA
|
||||||
|
GoDaddy,Go Daddy Root Certificate Authority - G2
|
||||||
|
GoDaddy,Starfield Class 2 CA
|
||||||
|
GoDaddy,Starfield Root Certificate Authority - G2
|
||||||
|
Google Trust Services LLC (GTS),GlobalSign ECC Root CA - R4
|
||||||
|
Google Trust Services LLC (GTS),GlobalSign Root CA - R2
|
||||||
|
Google Trust Services LLC (GTS),GTS Root R1
|
||||||
|
Google Trust Services LLC (GTS),GTS Root R2
|
||||||
|
Google Trust Services LLC (GTS),GTS Root R3
|
||||||
|
Google Trust Services LLC (GTS),GTS Root R4
|
||||||
|
"IdenTrust Services, LLC",DST Root CA X3
|
||||||
|
"IdenTrust Services, LLC",IdenTrust Commercial Root CA 1
|
||||||
|
"IdenTrust Services, LLC",IdenTrust Public Sector Root CA 1
|
||||||
|
Sectigo,Comodo AAA Services root
|
||||||
|
Sectigo,COMODO Certification Authority
|
||||||
|
Sectigo,COMODO ECC Certification Authority
|
||||||
|
Sectigo,COMODO RSA Certification Authority
|
||||||
|
Sectigo,USERTrust ECC Certification Authority
|
||||||
|
Sectigo,USERTrust RSA Certification Authority
|
|
227
examples/esp32_pio/WebSocketClientSSLBundle/gen_crt_bundle.py
Normal file
227
examples/esp32_pio/WebSocketClientSSLBundle/gen_crt_bundle.py
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# ESP32 x509 certificate bundle generation utility
|
||||||
|
#
|
||||||
|
# Converts PEM and DER certificates to a custom bundle format which stores just the
|
||||||
|
# subject name and public key to reduce space
|
||||||
|
#
|
||||||
|
# The bundle will have the format: number of certificates; crt 1 subject name length; crt 1 public key length;
|
||||||
|
# crt 1 subject name; crt 1 public key; crt 2...
|
||||||
|
#
|
||||||
|
# Copyright 2018-2019 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.
|
||||||
|
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
from io import open
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
except ImportError:
|
||||||
|
print('The cryptography package is not installed.'
|
||||||
|
'Please refer to the Get Started section of the ESP-IDF Programming Guide for '
|
||||||
|
'setting up the required packages.')
|
||||||
|
raise
|
||||||
|
|
||||||
|
ca_bundle_bin_file = 'x509_crt_bundle'
|
||||||
|
|
||||||
|
quiet = False
|
||||||
|
|
||||||
|
|
||||||
|
def status(msg):
|
||||||
|
""" Print status message to stderr """
|
||||||
|
if not quiet:
|
||||||
|
critical(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def critical(msg):
|
||||||
|
""" Print critical message to stderr """
|
||||||
|
sys.stderr.write('gen_crt_bundle.py: ')
|
||||||
|
sys.stderr.write(msg)
|
||||||
|
sys.stderr.write('\n')
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateBundle:
|
||||||
|
def __init__(self):
|
||||||
|
self.certificates = []
|
||||||
|
self.compressed_crts = []
|
||||||
|
|
||||||
|
if os.path.isfile(ca_bundle_bin_file):
|
||||||
|
os.remove(ca_bundle_bin_file)
|
||||||
|
|
||||||
|
def add_from_path(self, crts_path):
|
||||||
|
|
||||||
|
found = False
|
||||||
|
for file_path in os.listdir(crts_path):
|
||||||
|
found |= self.add_from_file(os.path.join(crts_path, file_path))
|
||||||
|
|
||||||
|
if found is False:
|
||||||
|
raise InputError('No valid x509 certificates found in %s' % crts_path)
|
||||||
|
|
||||||
|
def add_from_file(self, file_path):
|
||||||
|
try:
|
||||||
|
if file_path.endswith('.pem'):
|
||||||
|
status('Parsing certificates from %s' % file_path)
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
crt_str = f.read()
|
||||||
|
self.add_from_pem(crt_str)
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif file_path.endswith('.der'):
|
||||||
|
status('Parsing certificates from %s' % file_path)
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
crt_str = f.read()
|
||||||
|
self.add_from_der(crt_str)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
critical('Invalid certificate in %s' % file_path)
|
||||||
|
raise InputError('Invalid certificate')
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_from_pem(self, crt_str):
|
||||||
|
""" A single PEM file may have multiple certificates """
|
||||||
|
|
||||||
|
crt = ''
|
||||||
|
count = 0
|
||||||
|
start = False
|
||||||
|
|
||||||
|
for strg in crt_str.splitlines(True):
|
||||||
|
if strg == '-----BEGIN CERTIFICATE-----\n' and start is False:
|
||||||
|
crt = ''
|
||||||
|
start = True
|
||||||
|
elif strg == '-----END CERTIFICATE-----\n' and start is True:
|
||||||
|
crt += strg + '\n'
|
||||||
|
start = False
|
||||||
|
self.certificates.append(x509.load_pem_x509_certificate(crt.encode(), default_backend()))
|
||||||
|
count += 1
|
||||||
|
if start is True:
|
||||||
|
crt += strg
|
||||||
|
|
||||||
|
if(count == 0):
|
||||||
|
raise InputError('No certificate found')
|
||||||
|
|
||||||
|
status('Successfully added %d certificates' % count)
|
||||||
|
|
||||||
|
def add_from_der(self, crt_str):
|
||||||
|
self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend()))
|
||||||
|
status('Successfully added 1 certificate')
|
||||||
|
|
||||||
|
def create_bundle(self):
|
||||||
|
# Sort certificates in order to do binary search when looking up certificates
|
||||||
|
self.certificates = sorted(self.certificates, key=lambda cert: cert.subject.public_bytes(default_backend()))
|
||||||
|
|
||||||
|
bundle = struct.pack('>H', len(self.certificates))
|
||||||
|
|
||||||
|
for crt in self.certificates:
|
||||||
|
""" Read the public key as DER format """
|
||||||
|
pub_key = crt.public_key()
|
||||||
|
pub_key_der = pub_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo)
|
||||||
|
|
||||||
|
""" Read the subject name as DER format """
|
||||||
|
sub_name_der = crt.subject.public_bytes(default_backend())
|
||||||
|
|
||||||
|
name_len = len(sub_name_der)
|
||||||
|
key_len = len(pub_key_der)
|
||||||
|
len_data = struct.pack('>HH', name_len, key_len)
|
||||||
|
|
||||||
|
bundle += len_data
|
||||||
|
bundle += sub_name_der
|
||||||
|
bundle += pub_key_der
|
||||||
|
|
||||||
|
return bundle
|
||||||
|
|
||||||
|
def add_with_filter(self, crts_path, filter_path):
|
||||||
|
|
||||||
|
filter_set = set()
|
||||||
|
with open(filter_path, 'r', encoding='utf-8') as f:
|
||||||
|
csv_reader = csv.reader(f, delimiter=',')
|
||||||
|
|
||||||
|
# Skip header
|
||||||
|
next(csv_reader)
|
||||||
|
for row in csv_reader:
|
||||||
|
filter_set.add(row[1])
|
||||||
|
|
||||||
|
status('Parsing certificates from %s' % crts_path)
|
||||||
|
crt_str = []
|
||||||
|
with open(crts_path, 'r', encoding='utf-8') as f:
|
||||||
|
crt_str = f.read()
|
||||||
|
|
||||||
|
# Split all certs into a list of (name, certificate string) tuples
|
||||||
|
pem_crts = re.findall(r'(^.+?)\n(=+\n[\s\S]+?END CERTIFICATE-----\n)', crt_str, re.MULTILINE)
|
||||||
|
|
||||||
|
filtered_crts = ''
|
||||||
|
for name, crt in pem_crts:
|
||||||
|
if name in filter_set:
|
||||||
|
filtered_crts += crt
|
||||||
|
|
||||||
|
self.add_from_pem(filtered_crts)
|
||||||
|
|
||||||
|
|
||||||
|
class InputError(RuntimeError):
|
||||||
|
def __init__(self, e):
|
||||||
|
super(InputError, self).__init__(e)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global quiet
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='ESP-IDF x509 certificate bundle utility')
|
||||||
|
|
||||||
|
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
|
||||||
|
parser.add_argument('--input', '-i', nargs='+', required=True,
|
||||||
|
help='Paths to the custom certificate folders or files to parse, parses all .pem or .der files')
|
||||||
|
parser.add_argument('--filter', '-f', help='Path to CSV-file where the second columns contains the name of the certificates \
|
||||||
|
that should be included from cacrt_all.pem')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
quiet = args.quiet
|
||||||
|
|
||||||
|
bundle = CertificateBundle()
|
||||||
|
|
||||||
|
for path in args.input:
|
||||||
|
if os.path.isfile(path):
|
||||||
|
if os.path.basename(path) == 'cacrt_all.pem' and args.filter:
|
||||||
|
bundle.add_with_filter(path, args.filter)
|
||||||
|
else:
|
||||||
|
bundle.add_from_file(path)
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
bundle.add_from_path(path)
|
||||||
|
else:
|
||||||
|
raise InputError('Invalid --input=%s, is neither file nor folder' % args.input)
|
||||||
|
|
||||||
|
status('Successfully added %d certificates in total' % len(bundle.certificates))
|
||||||
|
|
||||||
|
crt_bundle = bundle.create_bundle()
|
||||||
|
|
||||||
|
with open(ca_bundle_bin_file, 'wb') as f:
|
||||||
|
f.write(crt_bundle)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except InputError as e:
|
||||||
|
print(e)
|
||||||
|
sys.exit(2)
|
46
examples/esp32_pio/WebSocketClientSSLBundle/lib/README
Normal file
46
examples/esp32_pio/WebSocketClientSSLBundle/lib/README
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
25
examples/esp32_pio/WebSocketClientSSLBundle/platformio.ini
Normal file
25
examples/esp32_pio/WebSocketClientSSLBundle/platformio.ini
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp32dev]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32dev
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_speed = 921600
|
||||||
|
build_flags =
|
||||||
|
-DCORE_DEBUG_LEVEL=5
|
||||||
|
lib_deps = ../../../src
|
||||||
|
|
||||||
|
extra_scripts =
|
||||||
|
pre:run_gen_script.py
|
||||||
|
|
||||||
|
board_build.embed_txtfiles =
|
||||||
|
data/cert/x509_crt_bundle.bin
|
12
examples/esp32_pio/WebSocketClientSSLBundle/readme.md
Normal file
12
examples/esp32_pio/WebSocketClientSSLBundle/readme.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
This is a PlatformIO project that uses a modified WiFiClientSecure library (in `lib`) to
|
||||||
|
implement proper SSL support using root certificates as discussed
|
||||||
|
[here](https://github.com/espressif/arduino-esp32/issues/3646#issuecomment-648292677)
|
||||||
|
|
||||||
|
It is based on the work by [meltdonw03](https://github.com/meltdown03) in that thread, and the
|
||||||
|
[BasicHttpsClient example](https://github.com/espressif/arduino-esp32/blob/1.0.4/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino) from the arduino-esp32 project.
|
||||||
|
|
||||||
|
Just copy `include/secrets.hpp.template` to `include/secrets.hpp` and fill in your WiFi details.
|
||||||
|
Then it should be pretty much ready to go. The local WiFiClientSecure library should take priority.
|
||||||
|
Debug is set to verbose, so you'll see a lot of noise, but there should also be this readme on success :)
|
||||||
|
|
||||||
|
To get a current CA cert bundle download it from [curl's website](https://curl.se/docs/caextract.html).
|
@ -0,0 +1,6 @@
|
|||||||
|
Import("env")
|
||||||
|
|
||||||
|
env.Execute("$PYTHONEXE -m pip install cryptography")
|
||||||
|
env.Execute("$PYTHONEXE gen_crt_bundle.py --input cacrt_all.pem")
|
||||||
|
env.Execute("mkdir -p data/cert")
|
||||||
|
env.Execute("mv -f x509_crt_bundle data/cert/x509_crt_bundle.bin")
|
127
examples/esp32_pio/WebSocketClientSSLBundle/src/main.cpp
Normal file
127
examples/esp32_pio/WebSocketClientSSLBundle/src/main.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* main.cpp
|
||||||
|
*
|
||||||
|
* Created on: 15.06.2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
extern const uint8_t rootca_crt_bundle_start[] asm(
|
||||||
|
"_binary_data_cert_x509_crt_bundle_bin_start");
|
||||||
|
|
||||||
|
WiFiMulti wifiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
void setClock() {
|
||||||
|
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
USE_SERIAL.print(F("Waiting for NTP time sync: "));
|
||||||
|
time_t nowSecs = time(nullptr);
|
||||||
|
while(nowSecs < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
USE_SERIAL.print(F("."));
|
||||||
|
yield();
|
||||||
|
nowSecs = time(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&nowSecs, &timeinfo);
|
||||||
|
USE_SERIAL.print(F("Current time: "));
|
||||||
|
USE_SERIAL.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t * src = (const uint8_t *)mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiMulti.addAP("SSID", "WIFI_PASSPHRASE");
|
||||||
|
|
||||||
|
// WiFi.disconnect();
|
||||||
|
while(wifiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
setClock();
|
||||||
|
|
||||||
|
// server address, port and URL. This server can be flakey.
|
||||||
|
// Expected response: Request served by 0123456789abcdef
|
||||||
|
webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, "");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional enable if needed
|
||||||
|
// webSocket.setAuthorization("user", "Password");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
27
examples/esp8266_pico/WebSocketClientOTA/README.md
Normal file
27
examples/esp8266_pico/WebSocketClientOTA/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
## Minimal example of WebsocketClientOTA and Python server
|
||||||
|
|
||||||
|
Take this as small example, how achieve OTA update on ESP8266 and ESP32.
|
||||||
|
|
||||||
|
Python server was wrote from train so take it only as bare example.
|
||||||
|
It's working, but it's not mean to run in production.
|
||||||
|
|
||||||
|
|
||||||
|
### Usage:
|
||||||
|
|
||||||
|
Start server:
|
||||||
|
```bash
|
||||||
|
cd python_ota_server
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Flash ESP with example sketch and start it.
|
||||||
|
|
||||||
|
Change version inside example sketch to higher and compile it and save it to bin file.
|
||||||
|
|
||||||
|
Rename it to `mydevice-1.0.1-esp8266.bin` and place it inside new folder firmware (server create it).
|
||||||
|
|
||||||
|
When the ESP connect to server, it check if version flashed is equal to fw in firmware folder. If higher FW version is present,
|
||||||
|
start the flash process.
|
264
examples/esp8266_pico/WebSocketClientOTA/WebSocketClientOTA.ino
Normal file
264
examples/esp8266_pico/WebSocketClientOTA/WebSocketClientOTA.ino
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientOTA.ino
|
||||||
|
*
|
||||||
|
* Created on: 25.10.2021
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <Updater.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include "ESPmDNS.h"
|
||||||
|
#include <Update.h>
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
#else
|
||||||
|
#error Unsupported device
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
// Variables:
|
||||||
|
// Settable:
|
||||||
|
const char *version = "1.0.0";
|
||||||
|
const char *name = "mydevice";
|
||||||
|
|
||||||
|
// Others:
|
||||||
|
#ifdef ESP8266
|
||||||
|
const char *chip = "esp8266";
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
const char *chip = "esp32";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t maxSketchSpace = 0;
|
||||||
|
int SketchSize = 0;
|
||||||
|
bool ws_conn = false;
|
||||||
|
|
||||||
|
|
||||||
|
void greetings_(){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
doc["type"] = "greetings";
|
||||||
|
doc["mac"] = WiFi.macAddress().c_str();
|
||||||
|
doc["ip"] = WiFi.localIP().toString().c_str();
|
||||||
|
doc["version"] = version;
|
||||||
|
doc["name"] = name;
|
||||||
|
doc["chip"] = chip;
|
||||||
|
|
||||||
|
char data[200];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
webSocket.sendTXT(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_(){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
doc["type"] = "register";
|
||||||
|
doc["mac"] = WiFi.macAddress().c_str();
|
||||||
|
|
||||||
|
char data[200];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
webSocket.sendTXT(data);
|
||||||
|
ws_conn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*CALLBACK_FUNCTION)(JsonDocument &msg);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char type[50];
|
||||||
|
CALLBACK_FUNCTION func;
|
||||||
|
} RESPONSES_STRUCT;
|
||||||
|
|
||||||
|
void OTA_RESPONSES(JsonDocument &msg){
|
||||||
|
USE_SERIAL.print(F("[WSc] OTA mode: "));
|
||||||
|
String val = msg["value"];
|
||||||
|
if(val == "go") {
|
||||||
|
USE_SERIAL.print(F("go\n"));
|
||||||
|
SketchSize = int(msg["size"]);
|
||||||
|
maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
USE_SERIAL.printf("[WSc] Max sketch size: %u\n", maxSketchSpace);
|
||||||
|
USE_SERIAL.printf("[WSc] Sketch size: %d\n", SketchSize);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
if (!Update.begin(maxSketchSpace)) { //start with max available size
|
||||||
|
Update.printError(Serial);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
} else if (val == "ok") {
|
||||||
|
USE_SERIAL.print(F("OK\n"));
|
||||||
|
register_();
|
||||||
|
} else {
|
||||||
|
USE_SERIAL.print(F("unknown value : "));
|
||||||
|
USE_SERIAL.print(val);
|
||||||
|
USE_SERIAL.print(F("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void STA_RESPONSES(JsonDocument &msg){
|
||||||
|
// Do something with message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count of responses handled by RESPONSES_STRUCT
|
||||||
|
// increase increase if another response handler is added
|
||||||
|
const int nrOfResponses = 2;
|
||||||
|
|
||||||
|
RESPONSES_STRUCT responses[nrOfResponses] = {
|
||||||
|
{"ota", OTA_RESPONSES},
|
||||||
|
{"state", STA_RESPONSES},
|
||||||
|
};
|
||||||
|
|
||||||
|
void text(uint8_t * payload, size_t length){
|
||||||
|
// Convert message to something usable
|
||||||
|
char msgch[length];
|
||||||
|
for (unsigned int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
USE_SERIAL.print((char)payload[i]);
|
||||||
|
msgch[i] = ((char)payload[i]);
|
||||||
|
}
|
||||||
|
msgch[length] = '\0';
|
||||||
|
|
||||||
|
// Parse Json
|
||||||
|
StaticJsonDocument<200> doc_in;
|
||||||
|
DeserializationError error = deserializeJson(doc_in, msgch);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||||
|
USE_SERIAL.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle each TYPE of message
|
||||||
|
int b = 0;
|
||||||
|
|
||||||
|
String t = doc_in["type"];
|
||||||
|
for( b=0 ; b<nrOfResponses ; b++ )
|
||||||
|
{
|
||||||
|
if(t == responses[b].type) {
|
||||||
|
responses[b].func(doc_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
// webSocket.sendTXT("Connected");
|
||||||
|
greetings_();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
text(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
// hexdump(payload, length);
|
||||||
|
if (Update.write(payload, length) != length) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
SketchSize -= length;
|
||||||
|
USE_SERIAL.printf("[WSc] Sketch size left: %u\n", SketchSize);
|
||||||
|
if (SketchSize < 1){
|
||||||
|
if (Update.end(true)) { //true to set the size to the current progress
|
||||||
|
USE_SERIAL.printf("Update Success: \nRebooting...\n");
|
||||||
|
delay(5);
|
||||||
|
yield();
|
||||||
|
ESP.restart();
|
||||||
|
} else {
|
||||||
|
Update.printError(USE_SERIAL);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
USE_SERIAL.setDebugOutput(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_PING:
|
||||||
|
// pong will be send automatically
|
||||||
|
USE_SERIAL.printf("[WSc] get ping\n");
|
||||||
|
break;
|
||||||
|
case WStype_PONG:
|
||||||
|
// answer to a ping we send
|
||||||
|
USE_SERIAL.printf("[WSc] get pong\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.print(F("\nMAC: "));
|
||||||
|
USE_SERIAL.println(WiFi.macAddress());
|
||||||
|
USE_SERIAL.print(F("\nDevice: "));
|
||||||
|
USE_SERIAL.println(name);
|
||||||
|
USE_SERIAL.printf("\nVersion: %s\n", version);
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "PASS");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("10.0.1.5", 8081, "/");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional remove if not needed
|
||||||
|
// webSocket.setAuthorization("USER", "PASS");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
|
||||||
|
// start heartbeat (optional)
|
||||||
|
// ping server every 15000 ms
|
||||||
|
// expect pong from server within 3000 ms
|
||||||
|
// consider connection disconnected if pong is not received 2 times
|
||||||
|
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,235 @@
|
|||||||
|
"""Minimal example of Python websocket server
|
||||||
|
handling OTA updates for ESP32 amd ESP8266
|
||||||
|
|
||||||
|
Check and upload of firmware works.
|
||||||
|
Register and state function are jus for example.
|
||||||
|
"""
|
||||||
|
# pylint: disable=W0703,E1101
|
||||||
|
import asyncio
|
||||||
|
import copy
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from os import listdir
|
||||||
|
from os.path import join as join_pth
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import websockets
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
|
# Logger settings
|
||||||
|
logging.basicConfig(filename="ws_server.log")
|
||||||
|
Logger = logging.getLogger('WS-OTA')
|
||||||
|
Logger.addHandler(logging.StreamHandler())
|
||||||
|
Logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Path to directory with FW
|
||||||
|
fw_path = join_pth(Path().absolute(), "firmware")
|
||||||
|
|
||||||
|
|
||||||
|
def create_path(path: str) -> None:
|
||||||
|
"""Check if path exist or create it"""
|
||||||
|
Path(path).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def shell(command):
|
||||||
|
"""Handle execution of shell commands"""
|
||||||
|
with subprocess.Popen(command, shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
universal_newlines=True
|
||||||
|
) as process:
|
||||||
|
for stdout_line in iter(process.stdout.readline, ""):
|
||||||
|
Logger.debug(stdout_line)
|
||||||
|
process.stdout.close()
|
||||||
|
return_code = process.wait()
|
||||||
|
Logger.debug("Shell returned: %s", return_code)
|
||||||
|
|
||||||
|
return process.returncode
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def binary_send(websocket, fw_file):
|
||||||
|
"""Read firmware file, divide it to chunks and send them"""
|
||||||
|
with open(fw_file, "rb") as binaryfile:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
chunk = binaryfile.read(4096)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
await websocket.send(chunk)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.exception(exception)
|
||||||
|
return False
|
||||||
|
asyncio.sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
def version_checker(name, vdev, vapp):
|
||||||
|
"""Parse and compare FW version"""
|
||||||
|
|
||||||
|
if version.parse(vdev) < version.parse(vapp):
|
||||||
|
Logger.info("Client(%s) version %s is smaller than %s: Go for update", name, vdev, vapp)
|
||||||
|
return True
|
||||||
|
Logger.info("Client(%s) version %s is greater or equal to %s: Not updating", name, vdev, vapp)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class WsOtaHandler (threading.Thread):
|
||||||
|
"""Thread handling ota update
|
||||||
|
|
||||||
|
Running ota directly from message would kill WS
|
||||||
|
as message bus would timeout.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, message, websocket):
|
||||||
|
threading.Thread.__init__(self, daemon=True)
|
||||||
|
self.name = name
|
||||||
|
self.msg = message
|
||||||
|
self.websocket = websocket
|
||||||
|
|
||||||
|
def run(self, ):
|
||||||
|
try:
|
||||||
|
asyncio.run(self.start_())
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.exception(exception)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def start_(self):
|
||||||
|
"""Start _ota se asyncio future"""
|
||||||
|
msg_task = asyncio.ensure_future(
|
||||||
|
self._ota())
|
||||||
|
|
||||||
|
done, pending = await asyncio.wait(
|
||||||
|
[msg_task],
|
||||||
|
return_when=asyncio.FIRST_COMPLETED,
|
||||||
|
)
|
||||||
|
Logger.info("WS Ota Handler done: %s", done)
|
||||||
|
for task in pending:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
async def _ota(self):
|
||||||
|
"""Check for new fw and update or pass"""
|
||||||
|
device_name = self.msg['name']
|
||||||
|
device_chip = self.msg['chip']
|
||||||
|
device_version = self.msg['version']
|
||||||
|
fw_version = ''
|
||||||
|
fw_name = ''
|
||||||
|
fw_device = ''
|
||||||
|
|
||||||
|
for filename in listdir(fw_path):
|
||||||
|
fw_info = filename.split("-")
|
||||||
|
fw_device = fw_info[0]
|
||||||
|
if fw_device == device_name:
|
||||||
|
fw_version = fw_info[1]
|
||||||
|
fw_name = filename
|
||||||
|
break
|
||||||
|
|
||||||
|
if not fw_version:
|
||||||
|
Logger.info("Client(%s): No fw found!", device_name)
|
||||||
|
msg = '{"type": "ota", "value":"ok"}'
|
||||||
|
await self.websocket.send(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not version_checker(device_name, device_version, fw_version):
|
||||||
|
return
|
||||||
|
|
||||||
|
fw_file = join_pth(fw_path, fw_name)
|
||||||
|
if device_chip == 'esp8266' and not fw_file.endswith('.gz'):
|
||||||
|
# We can compress fw to make it smaller for upload
|
||||||
|
fw_cpress = fw_file
|
||||||
|
fw_file = fw_cpress + ".gz"
|
||||||
|
cpress = f"gzip -9 {fw_cpress}"
|
||||||
|
cstate = shell(cpress)
|
||||||
|
if cstate:
|
||||||
|
Logger.error("Cannot compress firmware: %s", fw_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get size of fw
|
||||||
|
size = Path(fw_file).stat().st_size
|
||||||
|
|
||||||
|
# Request ota mode
|
||||||
|
msg = '{"type": "ota", "value":"go", "size":' + str(size) + '}'
|
||||||
|
await self.websocket.send(msg)
|
||||||
|
|
||||||
|
# send file by chunks trough websocket
|
||||||
|
await binary_send(self.websocket, fw_file)
|
||||||
|
|
||||||
|
|
||||||
|
async def _register(websocket, message):
|
||||||
|
mac = message.get('mac')
|
||||||
|
name = message.get('name')
|
||||||
|
Logger.info("Client(%s) mac: %s", name, mac)
|
||||||
|
# Some code
|
||||||
|
|
||||||
|
response = {'type': 'registry', 'state': 'ok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _state(websocket, message):
|
||||||
|
mac = message.get('mac')
|
||||||
|
name = message.get('name')
|
||||||
|
Logger.info("Client(%s) mac: %s", name, mac)
|
||||||
|
# Some code
|
||||||
|
|
||||||
|
response = {'type': 'state', 'state': 'ok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _unhandled(websocket, msg):
|
||||||
|
Logger.info("Unhandled message from device: %s", str(msg))
|
||||||
|
response = {'type': 'response', 'state': 'nok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _greetings(websocket, message):
|
||||||
|
WsOtaHandler('thread_ota', copy.deepcopy(message), websocket).start()
|
||||||
|
|
||||||
|
|
||||||
|
async def message_received(websocket, message) -> None:
|
||||||
|
"""Handle incoming messages
|
||||||
|
|
||||||
|
Check if message contain json and run waned function
|
||||||
|
"""
|
||||||
|
switcher = {"greetings": _greetings,
|
||||||
|
"register": _register,
|
||||||
|
"state": _state
|
||||||
|
}
|
||||||
|
|
||||||
|
if message[0:1] == "{":
|
||||||
|
try:
|
||||||
|
msg_json = json.loads(message)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.error(exception)
|
||||||
|
return
|
||||||
|
|
||||||
|
type_ = msg_json.get('type')
|
||||||
|
name = msg_json.get('name')
|
||||||
|
func = switcher.get(type_, _unhandled)
|
||||||
|
Logger.debug("Client(%s)said: %s", name, type_)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await func(websocket, msg_json)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.error(exception)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=W0613
|
||||||
|
async def ws_server(websocket, path) -> None:
|
||||||
|
"""Run in cycle and wait for new messages"""
|
||||||
|
async for message in websocket:
|
||||||
|
await message_received(websocket, message)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Server starter
|
||||||
|
|
||||||
|
Normal user can bind only port numbers greater than 1024
|
||||||
|
"""
|
||||||
|
async with websockets.serve(ws_server, "10.0.1.5", 8081):
|
||||||
|
await asyncio.Future() # run forever
|
||||||
|
|
||||||
|
|
||||||
|
create_path(fw_path)
|
||||||
|
asyncio.run(main())
|
@ -0,0 +1,2 @@
|
|||||||
|
packaging
|
||||||
|
websockets
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSSLWithCA.ino
|
||||||
|
*
|
||||||
|
* Created on: 27.10.2019
|
||||||
|
*
|
||||||
|
* note SSL is only possible with the ESP8266
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
|
||||||
|
// Can be obtained with:
|
||||||
|
// openssl s_client -showcerts -connect echo.websocket.org:443 </dev/null
|
||||||
|
const char ENDPOINT_CA_CERT[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||||
|
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||||
|
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||||
|
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||||
|
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||||
|
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||||
|
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||||
|
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||||
|
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||||
|
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||||
|
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlGPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||||
|
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
//When using BearSSL, client certificate and private key can be set:
|
||||||
|
//webSocket.setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
//clientCert and clientPrivateKey can be of types (const char *, const char *) , or of types (BearSSL::X509List, BearSSL::PrivateKey)
|
||||||
|
|
||||||
|
webSocket.beginSslWithCA("echo.websocket.org", 443, "/", ENDPOINT_CA_CERT);
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -29,6 +29,9 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
|
|||||||
break;
|
break;
|
||||||
case sIOtype_CONNECT:
|
case sIOtype_CONNECT:
|
||||||
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
break;
|
break;
|
||||||
case sIOtype_EVENT:
|
case sIOtype_EVENT:
|
||||||
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
|
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
|
||||||
@ -85,7 +88,7 @@ void setup() {
|
|||||||
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
// server address, port and URL
|
// server address, port and URL
|
||||||
socketIO.begin("10.11.100.100", 8880);
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
// event handler
|
// event handler
|
||||||
socketIO.onEvent(socketIOEvent);
|
socketIO.onEvent(socketIOEvent);
|
@ -30,6 +30,9 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
|
|||||||
break;
|
break;
|
||||||
case sIOtype_CONNECT:
|
case sIOtype_CONNECT:
|
||||||
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
break;
|
break;
|
||||||
case sIOtype_EVENT:
|
case sIOtype_EVENT:
|
||||||
{
|
{
|
||||||
@ -122,7 +125,7 @@ void setup() {
|
|||||||
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
// server address, port and URL
|
// server address, port and URL
|
||||||
socketIO.begin("10.11.100.100", 8880);
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
// event handler
|
// event handler
|
||||||
socketIO.onEvent(socketIOEvent);
|
socketIO.onEvent(socketIOEvent);
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServerHooked.ino
|
||||||
|
*
|
||||||
|
* Created on: 22.05.2015
|
||||||
|
* Hooked on: 28.10.2020
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <WebSockets4WebServer.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
ESP8266WebServer server(80);
|
||||||
|
WebSockets4WebServer webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
webSocket.sendTXT(num, "Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendTXT(num, "message here");
|
||||||
|
|
||||||
|
// send data to all connected clients
|
||||||
|
// webSocket.broadcastTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendBIN(num, payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
server.on("/", []() {
|
||||||
|
server.send(200, "text/plain", "I am a regular webserver on port 80!\r\n");
|
||||||
|
server.send(200, "text/plain", "I am also a websocket server on '/ws' on the same port 80\r\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.addHook(webSocket.hookForWebserver("/ws", webSocketEvent));
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
Serial.println("HTTP server started on port 80");
|
||||||
|
Serial.println("WebSocket server started on the same port");
|
||||||
|
Serial.printf("my network address is either 'arduinoWebsockets.local' (mDNS) or '%s'\n", WiFi.localIP().toString().c_str());
|
||||||
|
|
||||||
|
if (!MDNS.begin("arduinoWebsockets")) {
|
||||||
|
Serial.println("Error setting up MDNS responder!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
server.handleClient();
|
||||||
|
webSocket.loop();
|
||||||
|
MDNS.update();
|
||||||
|
}
|
20
examples/esp8266_pico/WebSocketServerHooked/emu
Executable file
20
examples/esp8266_pico/WebSocketServerHooked/emu
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# linux script to compile&run arduinoWebSockets in a mock environment
|
||||||
|
|
||||||
|
if [ -z "$ESP8266ARDUINO" ]; then
|
||||||
|
echo "please set ESP8266ARDUINO env-var to where esp8266/arduino sits"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
where=$(pwd)
|
||||||
|
|
||||||
|
cd $ESP8266ARDUINO/tests/host/
|
||||||
|
|
||||||
|
make -j FORCE32=0 \
|
||||||
|
ULIBDIRS=../../libraries/Hash/:~/dev/proj/arduino/libraries/arduinoWebSockets \
|
||||||
|
${where}/WebSocketServerHooked
|
||||||
|
|
||||||
|
valgrind ./bin/WebSocketServerHooked/WebSocketServerHooked -b "$@"
|
45
examples/esp8266_pico/WebSocketServerHooked/ws-testclient.py
Executable file
45
examples/esp8266_pico/WebSocketServerHooked/ws-testclient.py
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# python websocket client to test with
|
||||||
|
# emulator: server is at ws://127.0.0.1:9080/ws
|
||||||
|
# esp8266: server is at ws:///ws
|
||||||
|
# (uncomment the right line below)
|
||||||
|
|
||||||
|
#uri = "ws://127.0.0.1:9080/ws"
|
||||||
|
uri = "ws://arduinoWebsockets.local/ws"
|
||||||
|
|
||||||
|
import websocket
|
||||||
|
try:
|
||||||
|
import thread
|
||||||
|
except ImportError:
|
||||||
|
import _thread as thread
|
||||||
|
import time
|
||||||
|
|
||||||
|
def on_message(ws, message):
|
||||||
|
print("message");
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def on_error(ws, error):
|
||||||
|
print("error")
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
def on_close(ws):
|
||||||
|
print("### closed ###")
|
||||||
|
|
||||||
|
def on_open(ws):
|
||||||
|
print("opened")
|
||||||
|
def run(*args):
|
||||||
|
for i in range(3):
|
||||||
|
time.sleep(1)
|
||||||
|
ws.send("Hello %d" % i)
|
||||||
|
time.sleep(1)
|
||||||
|
ws.close()
|
||||||
|
print("thread terminating...")
|
||||||
|
thread.start_new_thread(run, ())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
websocket.enableTrace(True)
|
||||||
|
ws = websocket.WebSocketApp(uri, on_message = on_message, on_error = on_error, on_close = on_close)
|
||||||
|
ws.on_open = on_open
|
||||||
|
ws.run_forever()
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClient.ino
|
||||||
|
*
|
||||||
|
* Created on: 10.08.2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <rpcWiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
WiFiMulti wifiMulti;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t* src = (const uint8_t*) mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_PONG:
|
||||||
|
case WStype_PING:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(wifiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("192.168.0.123", 81, "/");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional remove if not needed
|
||||||
|
webSocket.setAuthorization("user", "Password");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
24
library.json
24
library.json
@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "WebSockets",
|
|
||||||
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
|
||||||
"keywords": "wifi, http, web, server, client, websocket",
|
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
"maintainer": true,
|
||||||
"name": "Markus Sattler",
|
"name": "Markus Sattler",
|
||||||
"url": "https://github.com/Links2004",
|
"url": "https://github.com/Links2004"
|
||||||
"maintainer": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"repository": {
|
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
|
||||||
},
|
|
||||||
"version": "2.3.0",
|
|
||||||
"license": "LGPL-2.1",
|
|
||||||
"export": {
|
"export": {
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"tests"
|
"tests"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": "atmelavr, espressif8266, espressif32"
|
"keywords": "wifi, http, web, server, client, websocket",
|
||||||
|
"license": "LGPL-2.1",
|
||||||
|
"name": "WebSockets",
|
||||||
|
"platforms": "*",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
||||||
|
},
|
||||||
|
"version": "2.6.1"
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
name=WebSockets
|
name=WebSockets
|
||||||
version=2.3.0
|
version=2.6.1
|
||||||
author=Markus Sattler
|
author=Markus Sattler
|
||||||
maintainer=Markus Sattler
|
maintainer=Markus Sattler
|
||||||
sentence=WebSockets for Arduino (Server + Client)
|
sentence=WebSockets for Arduino (Server + Client)
|
||||||
|
@ -15,14 +15,62 @@ SocketIOclient::SocketIOclient() {
|
|||||||
SocketIOclient::~SocketIOclient() {
|
SocketIOclient::~SocketIOclient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
|
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||||
|
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||||
|
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SocketIOclient::configureEIOping(bool disableHeartbeat) {
|
||||||
|
_disableHeartbeat = disableHeartbeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::initClient(void) {
|
||||||
|
if(_client.cUrl.indexOf("EIO=4") != -1) {
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n");
|
||||||
|
configureEIOping(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +85,18 @@ bool SocketIOclient::isConnected(void) {
|
|||||||
return WebSocketsClient::isConnected();
|
return WebSocketsClient::isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setExtraHeaders(const char * extraHeaders) {
|
||||||
|
return WebSocketsClient::setExtraHeaders(extraHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setReconnectInterval(unsigned long time) {
|
||||||
|
return WebSocketsClient::setReconnectInterval(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::disconnect(void) {
|
||||||
|
WebSocketsClient::disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send text data to client
|
* send text data to client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
@ -51,7 +111,7 @@ bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t
|
|||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
length = strlen((const char *)payload);
|
length = strlen((const char *)payload);
|
||||||
}
|
}
|
||||||
if(clientIsConnected(&_client)) {
|
if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) {
|
||||||
if(!headerToPayload) {
|
if(!headerToPayload) {
|
||||||
// webSocket Header
|
// webSocket Header
|
||||||
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
|
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
|
||||||
@ -118,8 +178,8 @@ bool SocketIOclient::sendEVENT(String & payload) {
|
|||||||
void SocketIOclient::loop(void) {
|
void SocketIOclient::loop(void) {
|
||||||
WebSocketsClient::loop();
|
WebSocketsClient::loop();
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) {
|
if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) {
|
||||||
_lastConnectionFail = t;
|
_lastHeartbeat = t;
|
||||||
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
||||||
WebSocketsClient::sendTXT(eIOtype_PING);
|
WebSocketsClient::sendTXT(eIOtype_PING);
|
||||||
}
|
}
|
||||||
@ -135,6 +195,7 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
|
|||||||
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
|
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
|
||||||
// send message to server when Connected
|
// send message to server when Connected
|
||||||
// Engine.io upgrade confirmation message (required)
|
// Engine.io upgrade confirmation message (required)
|
||||||
|
WebSocketsClient::sendTXT("2probe");
|
||||||
WebSocketsClient::sendTXT(eIOtype_UPGRADE);
|
WebSocketsClient::sendTXT(eIOtype_UPGRADE);
|
||||||
runIOCbEvent(sIOtype_CONNECT, payload, length);
|
runIOCbEvent(sIOtype_CONNECT, payload, length);
|
||||||
} break;
|
} break;
|
||||||
@ -165,6 +226,8 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
|
|||||||
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
|
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
|
||||||
break;
|
break;
|
||||||
case sIOtype_CONNECT:
|
case sIOtype_CONNECT:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data);
|
||||||
|
return;
|
||||||
case sIOtype_DISCONNECT:
|
case sIOtype_DISCONNECT:
|
||||||
case sIOtype_ACK:
|
case sIOtype_ACK:
|
||||||
case sIOtype_ERROR:
|
case sIOtype_ERROR:
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define SOCKETIOCLIENT_H_
|
#define SOCKETIOCLIENT_H_
|
||||||
|
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
#include "WebSocketsClient.h"
|
||||||
|
|
||||||
#define EIO_HEARTBEAT_INTERVAL 20000
|
#define EIO_HEARTBEAT_INTERVAL 20000
|
||||||
|
|
||||||
@ -46,12 +47,25 @@ class SocketIOclient : protected WebSocketsClient {
|
|||||||
SocketIOclient(void);
|
SocketIOclient(void);
|
||||||
virtual ~SocketIOclient(void);
|
virtual ~SocketIOclient(void);
|
||||||
|
|
||||||
void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
|
|
||||||
|
#ifdef HAS_SSL
|
||||||
|
void beginSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
|
void beginSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
|
#ifndef SSL_AXTLS
|
||||||
|
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
|
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino", uint32_t pingInterval = 60 * 1000, uint32_t pongTimeout = 90 * 1000, uint8_t disconnectTimeoutCount = 5);
|
||||||
|
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
bool isConnected(void);
|
bool isConnected(void);
|
||||||
|
|
||||||
void onEvent(SocketIOclientEvent cbEvent);
|
void onEvent(SocketIOclientEvent cbEvent);
|
||||||
|
void disconnect(void);
|
||||||
|
|
||||||
bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool sendEVENT(const uint8_t * payload, size_t length = 0);
|
bool sendEVENT(const uint8_t * payload, size_t length = 0);
|
||||||
@ -65,9 +79,15 @@ class SocketIOclient : protected WebSocketsClient {
|
|||||||
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
||||||
bool send(socketIOmessageType_t type, String & payload);
|
bool send(socketIOmessageType_t type, String & payload);
|
||||||
|
|
||||||
|
void setExtraHeaders(const char * extraHeaders = NULL);
|
||||||
|
void setReconnectInterval(unsigned long time);
|
||||||
|
|
||||||
void loop(void);
|
void loop(void);
|
||||||
|
|
||||||
|
void configureEIOping(bool disableHeartbeat = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool _disableHeartbeat = false;
|
||||||
uint64_t _lastHeartbeat = 0;
|
uint64_t _lastHeartbeat = 0;
|
||||||
SocketIOclientEvent _cbEvent;
|
SocketIOclientEvent _cbEvent;
|
||||||
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
@ -76,6 +96,8 @@ class SocketIOclient : protected WebSocketsClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initClient(void);
|
||||||
|
|
||||||
// Handeling events from websocket layer
|
// Handeling events from websocket layer
|
||||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
handleCbEvent(type, payload, length);
|
handleCbEvent(type, payload, length);
|
||||||
|
@ -42,7 +42,11 @@ extern "C" {
|
|||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||||
|
#if(ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(1, 0, 6))
|
||||||
|
#include "sha/sha_parallel_engine.h"
|
||||||
|
#else
|
||||||
#include <esp32/sha.h>
|
#include <esp32/sha.h>
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <hwcrypto/sha.h>
|
#include <hwcrypto/sha.h>
|
||||||
#endif
|
#endif
|
||||||
@ -468,7 +472,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
payload[header->payloadLen] = 0x00;
|
payload[header->payloadLen] = 0x00;
|
||||||
|
|
||||||
if(header->mask) {
|
if(header->mask) {
|
||||||
//decode XOR
|
// decode XOR
|
||||||
for(size_t i = 0; i < header->payloadLen; i++) {
|
for(size_t i = 0; i < header->payloadLen; i++) {
|
||||||
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
||||||
}
|
}
|
||||||
@ -478,7 +482,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
switch(header->opCode) {
|
switch(header->opCode) {
|
||||||
case WSop_text:
|
case WSop_text:
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
||||||
// no break here!
|
// fallthrough
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
case WSop_continuation:
|
case WSop_continuation:
|
||||||
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||||
@ -501,7 +505,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
reasonCode = payload[0] << 8 | payload[1];
|
reasonCode = payload[0] << 8 | payload[1];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode);
|
||||||
if(header->payloadLen > 2) {
|
if(header->payloadLen > 2) {
|
||||||
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
|
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
|
||||||
} else {
|
} else {
|
||||||
@ -510,6 +514,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
clientDisconnect(client, 1000);
|
clientDisconnect(client, 1000);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode);
|
||||||
clientDisconnect(client, 1002);
|
clientDisconnect(client, 1002);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -521,7 +526,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
// reset input
|
// reset input
|
||||||
client->cWsRXsize = 0;
|
client->cWsRXsize = 0;
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
//register callback for next message
|
// register callback for next message
|
||||||
handleWebsocketWaitFor(client, 2);
|
handleWebsocketWaitFor(client, 2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -566,6 +571,7 @@ String WebSockets::acceptKey(String & clientKey) {
|
|||||||
*/
|
*/
|
||||||
String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
||||||
size_t size = ((length * 1.6f) + 1);
|
size_t size = ((length * 1.6f) + 1);
|
||||||
|
size = std::max(size, (size_t)5); // minimum buffer size
|
||||||
char * buffer = (char *)malloc(size);
|
char * buffer = (char *)malloc(size);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
base64_encodestate _state;
|
base64_encodestate _state;
|
||||||
@ -630,7 +636,7 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!client->tcp->available()) {
|
if(!client->tcp->available()) {
|
||||||
WEBSOCKETS_YIELD();
|
WEBSOCKETS_YIELD_MORE();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,11 +645,13 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
t = millis();
|
t = millis();
|
||||||
out += len;
|
out += len;
|
||||||
n -= len;
|
n -= len;
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
} else {
|
} else {
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
|
}
|
||||||
|
if(n > 0) {
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
}
|
}
|
||||||
WEBSOCKETS_YIELD();
|
|
||||||
}
|
}
|
||||||
if(cb) {
|
if(cb) {
|
||||||
cb(client, true);
|
cb(client, true);
|
||||||
@ -691,11 +699,13 @@ size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
|
|||||||
out += len;
|
out += len;
|
||||||
n -= len;
|
n -= len;
|
||||||
total += len;
|
total += len;
|
||||||
//DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
||||||
} else {
|
} else {
|
||||||
//DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n);
|
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n);
|
||||||
|
}
|
||||||
|
if(n > 0) {
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
}
|
}
|
||||||
WEBSOCKETS_YIELD();
|
|
||||||
}
|
}
|
||||||
WEBSOCKETS_YIELD();
|
WEBSOCKETS_YIELD();
|
||||||
return total;
|
return total;
|
||||||
@ -740,7 +750,7 @@ void WebSockets::handleHBTimeout(WSclient_t * client) {
|
|||||||
client->pongTimeoutCount++;
|
client->pongTimeoutCount++;
|
||||||
client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run
|
client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%d pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount);
|
DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%lu pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount);
|
||||||
|
|
||||||
if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) {
|
if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) {
|
||||||
DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount);
|
DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount);
|
||||||
|
172
src/WebSockets.h
172
src/WebSockets.h
@ -40,11 +40,17 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "WebSocketsVersion.h"
|
||||||
|
|
||||||
#ifndef NODEBUG_WEBSOCKETS
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
#ifdef DEBUG_ESP_PORT
|
#ifdef DEBUG_ESP_PORT
|
||||||
#define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf(__VA_ARGS__)
|
#define DEBUG_WEBSOCKETS(...) \
|
||||||
|
{ \
|
||||||
|
DEBUG_ESP_PORT.printf(__VA_ARGS__); \
|
||||||
|
DEBUG_ESP_PORT.flush(); \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
// #define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -61,12 +67,14 @@
|
|||||||
#define WEBSOCKETS_USE_BIG_MEM
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
#define GET_FREE_HEAP ESP.getFreeHeap()
|
#define GET_FREE_HEAP ESP.getFreeHeap()
|
||||||
// moves all Header strings to Flash (~300 Byte)
|
// moves all Header strings to Flash (~300 Byte)
|
||||||
//#define WEBSOCKETS_SAVE_RAM
|
// #define WEBSOCKETS_SAVE_RAM
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
#define WEBSOCKETS_YIELD() delay(0)
|
#define WEBSOCKETS_YIELD() delay(0)
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
#define WEBSOCKETS_YIELD() yield()
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(STM32_DEVICE)
|
#elif defined(STM32_DEVICE)
|
||||||
@ -75,18 +83,47 @@
|
|||||||
#define WEBSOCKETS_USE_BIG_MEM
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
#define GET_FREE_HEAP System.freeMemory()
|
#define GET_FREE_HEAP System.freeMemory()
|
||||||
#define WEBSOCKETS_YIELD()
|
#define WEBSOCKETS_YIELD()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE()
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
|
#define GET_FREE_HEAP rp2040.getFreeHeap()
|
||||||
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_UNOWIFIR4)
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
|
||||||
|
#elif defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0)
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
//atmega328p has only 2KB ram!
|
// atmega328p has only 2KB ram!
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
||||||
// moves all Header strings to Flash
|
// moves all Header strings to Flash
|
||||||
#define WEBSOCKETS_SAVE_RAM
|
#define WEBSOCKETS_SAVE_RAM
|
||||||
#define WEBSOCKETS_YIELD()
|
#define WEBSOCKETS_YIELD()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETS_TCP_TIMEOUT
|
||||||
#define WEBSOCKETS_TCP_TIMEOUT (5000)
|
#define WEBSOCKETS_TCP_TIMEOUT (5000)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NETWORK_ESP8266_ASYNC (0)
|
#define NETWORK_ESP8266_ASYNC (0)
|
||||||
#define NETWORK_ESP8266 (1)
|
#define NETWORK_ESP8266 (1)
|
||||||
@ -94,6 +131,10 @@
|
|||||||
#define NETWORK_ENC28J60 (3)
|
#define NETWORK_ENC28J60 (3)
|
||||||
#define NETWORK_ESP32 (4)
|
#define NETWORK_ESP32 (4)
|
||||||
#define NETWORK_ESP32_ETH (5)
|
#define NETWORK_ESP32_ETH (5)
|
||||||
|
#define NETWORK_RP2040 (6)
|
||||||
|
#define NETWORK_UNOWIFIR4 (7)
|
||||||
|
#define NETWORK_WIFI_NINA (8)
|
||||||
|
#define NETWORK_SAMD_SEED (9)
|
||||||
|
|
||||||
// max size of the WS Message Header
|
// max size of the WS Message Header
|
||||||
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
||||||
@ -102,12 +143,25 @@
|
|||||||
// select Network type based
|
// select Network type based
|
||||||
#if defined(ESP8266) || defined(ESP31B)
|
#if defined(ESP8266) || defined(ESP31B)
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
// #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
// #define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||||
|
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
|
// #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_RP2040
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_UNOWIFIR4)
|
||||||
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_UNOWIFIR4
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
|
||||||
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_WIFI_NINA
|
||||||
|
|
||||||
|
#elif defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0)
|
||||||
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_SAMD_SEED
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||||
|
|
||||||
@ -191,6 +245,47 @@
|
|||||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#define SSL_BARESSL
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_UNOWIFIR4)
|
||||||
|
|
||||||
|
#include <WiFiS3.h>
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA)
|
||||||
|
#if __has_include(<WiFiNINA.h>)
|
||||||
|
#include <WiFiNINA.h>
|
||||||
|
#else
|
||||||
|
#error "Please install WiFiNINA library!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiSSLClient
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED)
|
||||||
|
#if __has_include(<rpcWiFi.h>) && __has_include(<rpcWiFiClientSecure.h>)
|
||||||
|
#include <rpcWiFi.h>
|
||||||
|
#include <rpcWiFiClientSecure.h>
|
||||||
|
#else
|
||||||
|
#error "Please install rpcWiFi library!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||||
|
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "no network type selected!"
|
#error "no network type selected!"
|
||||||
#endif
|
#endif
|
||||||
@ -209,6 +304,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
WSC_NOT_CONNECTED,
|
WSC_NOT_CONNECTED,
|
||||||
WSC_HEADER,
|
WSC_HEADER,
|
||||||
|
WSC_BODY,
|
||||||
WSC_CONNECTED
|
WSC_CONNECTED
|
||||||
} WSclientsStatus_t;
|
} WSclientsStatus_t;
|
||||||
|
|
||||||
@ -252,34 +348,44 @@ typedef struct {
|
|||||||
} WSMessageHeader_t;
|
} WSMessageHeader_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num; ///< connection number
|
void init(uint8_t num,
|
||||||
|
uint32_t pingInterval,
|
||||||
|
uint32_t pongTimeout,
|
||||||
|
uint8_t disconnectTimeoutCount) {
|
||||||
|
this->num = num;
|
||||||
|
this->pingInterval = pingInterval;
|
||||||
|
this->pongTimeout = pongTimeout;
|
||||||
|
this->disconnectTimeoutCount = disconnectTimeoutCount;
|
||||||
|
}
|
||||||
|
|
||||||
WSclientsStatus_t status;
|
uint8_t num = 0; ///< connection number
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcp;
|
WSclientsStatus_t status = WSC_NOT_CONNECTED;
|
||||||
|
|
||||||
bool isSocketIO; ///< client for socket.io server
|
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr;
|
||||||
|
|
||||||
|
bool isSocketIO = false; ///< client for socket.io server
|
||||||
|
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
bool isSSL; ///< run in ssl mode
|
bool isSSL = false; ///< run in ssl mode
|
||||||
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String cUrl; ///< http url
|
String cUrl; ///< http url
|
||||||
uint16_t cCode; ///< http code
|
uint16_t cCode = 0; ///< http code
|
||||||
|
|
||||||
bool cIsClient = false; ///< will be used for masking
|
bool cIsClient = false; ///< will be used for masking
|
||||||
bool cIsUpgrade; ///< Connection == Upgrade
|
bool cIsUpgrade = false; ///< Connection == Upgrade
|
||||||
bool cIsWebsocket; ///< Upgrade == websocket
|
bool cIsWebsocket = false; ///< Upgrade == websocket
|
||||||
|
|
||||||
String cSessionId; ///< client Set-Cookie (session id)
|
String cSessionId; ///< client Set-Cookie (session id)
|
||||||
String cKey; ///< client Sec-WebSocket-Key
|
String cKey; ///< client Sec-WebSocket-Key
|
||||||
String cAccept; ///< client Sec-WebSocket-Accept
|
String cAccept; ///< client Sec-WebSocket-Accept
|
||||||
String cProtocol; ///< client Sec-WebSocket-Protocol
|
String cProtocol; ///< client Sec-WebSocket-Protocol
|
||||||
String cExtensions; ///< client Sec-WebSocket-Extensions
|
String cExtensions; ///< client Sec-WebSocket-Extensions
|
||||||
uint16_t cVersion; ///< client Sec-WebSocket-Version
|
uint16_t cVersion = 0; ///< client Sec-WebSocket-Version
|
||||||
|
|
||||||
uint8_t cWsRXsize; ///< State of the RX
|
uint8_t cWsRXsize = 0; ///< State of the RX
|
||||||
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
||||||
WSMessageHeader_t cWsHeaderDecode;
|
WSMessageHeader_t cWsHeaderDecode;
|
||||||
|
|
||||||
@ -288,15 +394,15 @@ typedef struct {
|
|||||||
|
|
||||||
String extraHeaders;
|
String extraHeaders;
|
||||||
|
|
||||||
bool cHttpHeadersValid; ///< non-websocket http header validity indicator
|
bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator
|
||||||
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
||||||
|
|
||||||
bool pongReceived;
|
bool pongReceived = false;
|
||||||
uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active"
|
uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active"
|
||||||
uint32_t lastPing; // millis when last pong has been received
|
uint32_t lastPing = 0; // millis when last pong has been received
|
||||||
uint32_t pongTimeout; // interval in millis after which pong is considered to timeout
|
uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout
|
||||||
uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
||||||
uint8_t pongTimeoutCount; // current pong timeout count
|
uint8_t pongTimeoutCount = 0; // current pong timeout count
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
String cHttpLine; ///< HTTP header lines
|
String cHttpLine; ///< HTTP header lines
|
||||||
|
86
src/WebSockets4WebServer.h
Normal file
86
src/WebSockets4WebServer.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* @file WebSocketsServer.cpp
|
||||||
|
* @date 28.10.2020
|
||||||
|
* @author Markus Sattler & esp8266/arduino community
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* 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 __WEBSOCKETS4WEBSERVER_H
|
||||||
|
#define __WEBSOCKETS4WEBSERVER_H
|
||||||
|
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
|
||||||
|
#if((WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)) && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
class WebSockets4WebServer : public WebSocketsServerCore {
|
||||||
|
#if defined(ESP8266)
|
||||||
|
using WebServerClass = ESP8266WebServer;
|
||||||
|
#else
|
||||||
|
using WebServerClass = WebServer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
|
||||||
|
: WebSocketsServerCore(origin, protocol) {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
WebServerClass::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
|
||||||
|
onEvent(event);
|
||||||
|
|
||||||
|
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, WebServerClass::ContentTypeFunction contentType) {
|
||||||
|
(void)contentType;
|
||||||
|
|
||||||
|
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
|
||||||
|
return WebServerClass::CLIENT_REQUEST_CAN_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
|
||||||
|
WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
|
||||||
|
|
||||||
|
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
|
||||||
|
WSclient_t * client = handleNewClient(newTcpClient);
|
||||||
|
|
||||||
|
if(client) {
|
||||||
|
// give "GET <url>"
|
||||||
|
String headerLine;
|
||||||
|
headerLine.reserve(url.length() + 5);
|
||||||
|
headerLine = "GET ";
|
||||||
|
headerLine += url;
|
||||||
|
handleHeader(client, &headerLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell webserver to not close but forget about this client
|
||||||
|
return WebServerClass::CLIENT_IS_GIVEN;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
#ifndef WEBSERVER_HAS_HOOK
|
||||||
|
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
|
||||||
|
#else
|
||||||
|
#error Your Hardware Platform does not support Webserver Hook Functions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
#endif // __WEBSOCKETS4WEBSERVER_H
|
@ -48,6 +48,12 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
|
|||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
_CA_cert = NULL;
|
_CA_cert = NULL;
|
||||||
|
#ifdef ESP32
|
||||||
|
_CA_bundle = NULL;
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
_CA_bundle_size = 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_client.num = 0;
|
_client.num = 0;
|
||||||
@ -76,6 +82,8 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
|
|||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
randomSeed(RANDOM_REG32);
|
randomSeed(RANDOM_REG32);
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
randomSeed(rp2040.hwrand32());
|
||||||
#else
|
#else
|
||||||
// todo find better seed
|
// todo find better seed
|
||||||
randomSeed(millis());
|
randomSeed(millis());
|
||||||
@ -86,6 +94,8 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
|
|||||||
|
|
||||||
_lastConnectionFail = 0;
|
_lastConnectionFail = 0;
|
||||||
_lastHeaderSent = 0;
|
_lastHeaderSent = 0;
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
||||||
@ -103,6 +113,7 @@ void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * u
|
|||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
_CA_cert = NULL;
|
_CA_cert = NULL;
|
||||||
|
_CA_bundle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
||||||
@ -114,7 +125,28 @@ void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const ch
|
|||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
_CA_cert = CA_cert;
|
_CA_cert = CA_cert;
|
||||||
|
_CA_bundle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ESP32) && ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
void WebSocketsClient::beginSslWithBundle(const char * host, uint16_t port, const char * url, const uint8_t * CA_bundle, size_t CA_bundle_size, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = NULL;
|
||||||
|
_CA_bundle = CA_bundle;
|
||||||
|
_CA_bundle_size = CA_bundle_size;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void WebSocketsClient::beginSslWithBundle(const char * host, uint16_t port, const char * url, const uint8_t * CA_bundle, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = NULL;
|
||||||
|
_CA_bundle = CA_bundle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
|
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
|
||||||
begin(host, port, url, protocol);
|
begin(host, port, url, protocol);
|
||||||
@ -122,19 +154,29 @@ void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * u
|
|||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
_CA_cert = NULL;
|
_CA_cert = NULL;
|
||||||
}
|
}
|
||||||
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
|
||||||
begin(host, port, url, protocol);
|
|
||||||
_client.isSSL = true;
|
|
||||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
|
||||||
_CA_cert = new BearSSL::X509List(CA_cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
begin(host, port, url, protocol);
|
begin(host, port, url, protocol);
|
||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
_CA_cert = CA_cert;
|
_CA_cert = CA_cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
|
beginSslWithCA(host, port, url, new BearSSL::X509List(CA_cert), protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||||
|
setSSLClientCertKey(new BearSSL::X509List(clientCert), new BearSSL::PrivateKey(clientPrivateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||||
|
_client_cert = clientCert;
|
||||||
|
_client_key = clientPrivateKey;
|
||||||
|
}
|
||||||
|
#endif // SSL_BARESSL
|
||||||
|
|
||||||
#endif // SSL_AXTLS
|
#endif // SSL_AXTLS
|
||||||
#endif // HAS_SSL
|
#endif // HAS_SSL
|
||||||
|
|
||||||
@ -159,17 +201,28 @@ void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url,
|
|||||||
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
|
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSocketIO = true;
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = CA_cert;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
begin(host, port, url, protocol);
|
begin(host, port, url, protocol);
|
||||||
_client.isSocketIO = true;
|
_client.isSocketIO = true;
|
||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
#if defined(SSL_AXTLS)
|
#if defined(SSL_BARESSL)
|
||||||
_CA_cert = CA_cert;
|
|
||||||
#else
|
|
||||||
_CA_cert = new BearSSL::X509List(CA_cert);
|
_CA_cert = new BearSSL::X509List(CA_cert);
|
||||||
|
#else
|
||||||
|
_CA_cert = CA_cert;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
@ -191,7 +244,12 @@ void WebSocketsClient::loop(void) {
|
|||||||
if(_client.isSSL) {
|
if(_client.isSSL) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
|
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
|
||||||
if(_client.ssl) {
|
if(_client.ssl) {
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_UNOWIFIR4)
|
||||||
|
// does not support delete (no destructor)
|
||||||
|
#else
|
||||||
delete _client.ssl;
|
delete _client.ssl;
|
||||||
|
#endif
|
||||||
|
|
||||||
_client.ssl = NULL;
|
_client.ssl = NULL;
|
||||||
_client.tcp = NULL;
|
_client.tcp = NULL;
|
||||||
}
|
}
|
||||||
@ -203,22 +261,44 @@ void WebSocketsClient::loop(void) {
|
|||||||
_client.ssl->setCACert(_CA_cert);
|
_client.ssl->setCACert(_CA_cert);
|
||||||
#elif defined(ESP8266) && defined(SSL_AXTLS)
|
#elif defined(ESP8266) && defined(SSL_AXTLS)
|
||||||
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
|
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
|
||||||
#elif defined(ESP8266) && defined(SSL_BARESSL)
|
#elif(defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)) && defined(SSL_BARESSL)
|
||||||
_client.ssl->setTrustAnchors(_CA_cert);
|
_client.ssl->setTrustAnchors(_CA_cert);
|
||||||
|
#elif defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0)
|
||||||
|
_client.ssl->setCACert(_CA_cert);
|
||||||
|
#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
|
||||||
|
// no setCACert
|
||||||
#else
|
#else
|
||||||
#error setCACert not implemented
|
#error setCACert not implemented
|
||||||
#endif
|
#endif
|
||||||
#if defined(SSL_BARESSL)
|
#if defined(ESP32)
|
||||||
} else if(_fingerprint) {
|
} else if(_CA_bundle) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] setting CA bundle");
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
_client.ssl->setCACertBundle(_CA_bundle, _CA_bundle_size);
|
||||||
|
#else
|
||||||
|
_client.ssl->setCACertBundle(_CA_bundle);
|
||||||
|
#endif
|
||||||
|
} else if(!SSL_FINGERPRINT_IS_SET) {
|
||||||
|
_client.ssl->setInsecure();
|
||||||
|
#elif defined(SSL_BARESSL)
|
||||||
|
} else if(SSL_FINGERPRINT_IS_SET) {
|
||||||
_client.ssl->setFingerprint(_fingerprint);
|
_client.ssl->setFingerprint(_fingerprint);
|
||||||
} else {
|
} else {
|
||||||
_client.ssl->setInsecure();
|
_client.ssl->setInsecure();
|
||||||
|
}
|
||||||
|
if(_client_cert && _client_key) {
|
||||||
|
_client.ssl->setClientRSACert(_client_cert, _client_key);
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] setting client certificate and key");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
|
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
|
||||||
if(_client.tcp) {
|
if(_client.tcp) {
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_UNOWIFIR4)
|
||||||
|
// does not support delete (no destructor)
|
||||||
|
#else
|
||||||
delete _client.tcp;
|
delete _client.tcp;
|
||||||
|
#endif
|
||||||
_client.tcp = NULL;
|
_client.tcp = NULL;
|
||||||
}
|
}
|
||||||
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
||||||
@ -398,9 +478,9 @@ bool WebSocketsClient::isConnected(void) {
|
|||||||
return (_client.status == WSC_CONNECTED);
|
return (_client.status == WSC_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -445,7 +525,7 @@ void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, u
|
|||||||
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
||||||
bool event = false;
|
bool event = false;
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
if(client->isSSL && client->ssl) {
|
if(client->isSSL && client->ssl) {
|
||||||
if(client->ssl->connected()) {
|
if(client->ssl->connected()) {
|
||||||
client->ssl->flush();
|
client->ssl->flush();
|
||||||
@ -468,8 +548,12 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
event = true;
|
event = true;
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
#else
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_UNOWIFIR4)
|
||||||
|
// does not support delete (no destructor)
|
||||||
#else
|
#else
|
||||||
delete client->tcp;
|
delete client->tcp;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
}
|
}
|
||||||
@ -482,7 +566,8 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
client->cIsWebsocket = false;
|
client->cIsWebsocket = false;
|
||||||
client->cSessionId = "";
|
client->cSessionId = "";
|
||||||
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
_lastConnectionFail = millis();
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
||||||
if(event) {
|
if(event) {
|
||||||
@ -525,12 +610,13 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
|||||||
* Handel incomming data from Client
|
* Handel incomming data from Client
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::handleClientData(void) {
|
void WebSocketsClient::handleClientData(void) {
|
||||||
if(_client.status == WSC_HEADER && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
|
if((_client.status == WSC_HEADER || _client.status == WSC_BODY) && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
|
||||||
clientDisconnect(&_client);
|
clientDisconnect(&_client);
|
||||||
WEBSOCKETS_YIELD();
|
WEBSOCKETS_YIELD();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = _client.tcp->available();
|
int len = _client.tcp->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
switch(_client.status) {
|
switch(_client.status) {
|
||||||
@ -538,6 +624,12 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
String headerLine = _client.tcp->readStringUntil('\n');
|
String headerLine = _client.tcp->readStringUntil('\n');
|
||||||
handleHeader(&_client, &headerLine);
|
handleHeader(&_client, &headerLine);
|
||||||
} break;
|
} break;
|
||||||
|
case WSC_BODY: {
|
||||||
|
char buf[256] = { 0 };
|
||||||
|
_client.tcp->readBytes(&buf[0], std::min((size_t)len, sizeof(buf)));
|
||||||
|
String bodyLine = buf;
|
||||||
|
handleHeader(&_client, &bodyLine);
|
||||||
|
} break;
|
||||||
case WSC_CONNECTED:
|
case WSC_CONNECTED:
|
||||||
WebSockets::handleWebsocket(&_client);
|
WebSockets::handleWebsocket(&_client);
|
||||||
break;
|
break;
|
||||||
@ -613,7 +705,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add extra headers; by default this includes "Origin: file://"
|
// add extra headers; by default this includes "Origin: file://"
|
||||||
if(client->extraHeaders) {
|
if(client->extraHeaders.length() > 0) {
|
||||||
handshake += client->extraHeaders + NEW_LINE;
|
handshake += client->extraHeaders + NEW_LINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,6 +741,22 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
||||||
headerLine->trim(); // remove \r
|
headerLine->trim(); // remove \r
|
||||||
|
|
||||||
|
// this code handels the http body for Socket.IO V3 requests
|
||||||
|
if(headerLine->length() > 0 && client->isSocketIO && client->status == WSC_BODY && client->cSessionId.length() == 0) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] socket.io json: %s\n", headerLine->c_str());
|
||||||
|
String sid_begin = WEBSOCKETS_STRING("\"sid\":\"");
|
||||||
|
if(headerLine->indexOf(sid_begin) > -1) {
|
||||||
|
int start = headerLine->indexOf(sid_begin) + sid_begin.length();
|
||||||
|
int end = headerLine->indexOf('"', start);
|
||||||
|
client->cSessionId = headerLine->substring(start, end);
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||||
|
|
||||||
|
// Trigger websocket connection code path
|
||||||
|
*headerLine = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// headle HTTP header
|
||||||
if(headerLine->length() > 0) {
|
if(headerLine->length() > 0) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
||||||
|
|
||||||
@ -681,8 +789,8 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
client->cExtensions = headerValue;
|
client->cExtensions = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
||||||
client->cVersion = headerValue.toInt();
|
client->cVersion = headerValue.toInt();
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie")) && headerValue.indexOf(" io=") > -1) {
|
||||||
if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) {
|
if(headerValue.indexOf(';') > -1) {
|
||||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
|
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
|
||||||
} else {
|
} else {
|
||||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
|
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
|
||||||
@ -713,6 +821,14 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||||
|
|
||||||
|
if(client->isSocketIO && client->cSessionId.length() == 0 && clientIsConnected(client)) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still missing cSessionId try socket.io V3\n");
|
||||||
|
client->status = WSC_BODY;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
client->status = WSC_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
@ -724,9 +840,11 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
if(client->isSocketIO) {
|
if(client->isSocketIO) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// falls through
|
||||||
case 403: ///< Forbidden
|
case 403: ///< Forbidden
|
||||||
// todo handle login
|
// todo handle login
|
||||||
default: ///< Server dont unterstand requrst
|
// falls through
|
||||||
|
default: ///< Server dont unterstand requrst
|
||||||
ok = false;
|
ok = false;
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
@ -754,15 +872,18 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
|
|
||||||
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
} else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
|
} else if(client->isSocketIO) {
|
||||||
if(_client.tcp->available()) {
|
if(client->cSessionId.length() > 0) {
|
||||||
// read not needed data
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] found cSessionId\n");
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
|
if(clientIsConnected(client) && _client.tcp->available()) {
|
||||||
while(_client.tcp->available() > 0) {
|
// read not needed data
|
||||||
_client.tcp->read();
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
|
||||||
|
while(_client.tcp->available() > 0) {
|
||||||
|
_client.tcp->read();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sendHeader(client);
|
||||||
}
|
}
|
||||||
sendHeader(client);
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
||||||
@ -799,20 +920,20 @@ void WebSocketsClient::connectedCb() {
|
|||||||
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
_client.tcp->setNoDelay(true);
|
_client.tcp->setNoDelay(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
#if defined(SSL_AXTLS) || defined(ESP32)
|
#if defined(SSL_AXTLS) || defined(ESP32)
|
||||||
if(_client.isSSL && _fingerprint.length()) {
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
||||||
WebSockets::clientDisconnect(&_client, 1000);
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(_client.isSSL && _fingerprint) {
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
#endif
|
#endif
|
||||||
} else if(_client.isSSL && !_CA_cert) {
|
} else if(_client.isSSL && !_CA_cert) {
|
||||||
#if defined(SSL_BARESSL)
|
#if defined(SSL_BARESSL)
|
||||||
@ -885,6 +1006,9 @@ void WebSocketsClient::handleHBPing() {
|
|||||||
if(sendPing()) {
|
if(sendPing()) {
|
||||||
_client.lastPing = millis();
|
_client.lastPing = millis();
|
||||||
_client.pongReceived = false;
|
_client.pongReceived = false;
|
||||||
|
} else {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n");
|
||||||
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,20 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
||||||
#else
|
#else
|
||||||
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
|
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||||
|
#endif
|
||||||
|
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||||
#endif
|
#endif
|
||||||
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
|
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
#ifdef ESP32
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
void beginSslWithBundle(const char * host, uint16_t port, const char * url = "/", const uint8_t * CA_bundle = NULL, size_t CA_bundle_size = 0, const char * protocol = "arduino");
|
||||||
|
#else
|
||||||
|
void beginSslWithBundle(const char * host, uint16_t port, const char * url = "/", const uint8_t * CA_bundle = NULL, const char * protocol = "arduino");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
@ -59,7 +70,11 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||||
|
|
||||||
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
@ -106,13 +121,30 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
#ifdef SSL_AXTLS
|
#ifdef SSL_AXTLS
|
||||||
String _fingerprint;
|
String _fingerprint;
|
||||||
const char * _CA_cert;
|
const char * _CA_cert;
|
||||||
|
const uint8_t * _CA_bundle;
|
||||||
|
#if defined(ESP32)
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)
|
||||||
|
size_t _CA_bundle_size;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint.length())
|
||||||
#define SSL_FINGERPRINT_NULL ""
|
#define SSL_FINGERPRINT_NULL ""
|
||||||
#else
|
#else
|
||||||
const uint8_t * _fingerprint;
|
const uint8_t * _fingerprint;
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
BearSSL::X509List * _CA_cert;
|
BearSSL::X509List * _CA_cert;
|
||||||
|
BearSSL::X509List * _client_cert;
|
||||||
|
BearSSL::PrivateKey * _client_key;
|
||||||
|
#endif
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL)
|
||||||
#define SSL_FINGERPRINT_NULL NULL
|
#define SSL_FINGERPRINT_NULL NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA)
|
||||||
|
const char * _CA_cert;
|
||||||
|
const uint8_t * _CA_bundle;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
WSclient_t _client;
|
WSclient_t _client;
|
||||||
|
|
||||||
@ -144,11 +176,11 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(type, payload, length);
|
_cbEvent(type, payload, length);
|
||||||
|
@ -25,8 +25,15 @@
|
|||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
#include "WebSocketsServer.h"
|
#include "WebSocketsServer.h"
|
||||||
|
|
||||||
WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) {
|
#ifdef ESP32
|
||||||
_port = port;
|
#if defined __has_include
|
||||||
|
#if __has_include("soc/wdev_reg.h")
|
||||||
|
#include "soc/wdev_reg.h"
|
||||||
|
#endif // __has_include
|
||||||
|
#endif // defined __has_include
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) {
|
||||||
_origin = origin;
|
_origin = origin;
|
||||||
_protocol = protocol;
|
_protocol = protocol;
|
||||||
_runnning = false;
|
_runnning = false;
|
||||||
@ -34,25 +41,28 @@ WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol
|
|||||||
_pongTimeout = 0;
|
_pongTimeout = 0;
|
||||||
_disconnectTimeoutCount = 0;
|
_disconnectTimeoutCount = 0;
|
||||||
|
|
||||||
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
_server->onClient([](void * s, AsyncClient * c) {
|
|
||||||
((WebSocketsServer *)s)->newClient(new AsyncTCPbuffer(c));
|
|
||||||
},
|
|
||||||
this);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_cbEvent = NULL;
|
_cbEvent = NULL;
|
||||||
|
|
||||||
_httpHeaderValidationFunc = NULL;
|
_httpHeaderValidationFunc = NULL;
|
||||||
_mandatoryHttpHeaders = NULL;
|
_mandatoryHttpHeaders = NULL;
|
||||||
_mandatoryHttpHeaderCount = 0;
|
_mandatoryHttpHeaderCount = 0;
|
||||||
|
|
||||||
memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketsServer::~WebSocketsServer() {
|
WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol)
|
||||||
|
: WebSocketsServerCore(origin, protocol) {
|
||||||
|
_port = port;
|
||||||
|
|
||||||
|
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
_server->onClient([](void * s, AsyncClient * c) {
|
||||||
|
((WebSocketsServerCore *)s)->newClient(new AsyncTCPbuffer(c));
|
||||||
|
},
|
||||||
|
this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketsServerCore::~WebSocketsServerCore() {
|
||||||
// disconnect all clients
|
// disconnect all clients
|
||||||
close();
|
close();
|
||||||
|
|
||||||
@ -62,92 +72,62 @@ WebSocketsServer::~WebSocketsServer() {
|
|||||||
_mandatoryHttpHeaderCount = 0;
|
_mandatoryHttpHeaderCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebSocketsServer::~WebSocketsServer() {
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED)
|
||||||
|
// does not support delete (no destructor)
|
||||||
|
#else
|
||||||
|
delete _server;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called to initialize the Websocket server
|
* called to initialize the Websocket server
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::begin(void) {
|
void WebSocketsServerCore::begin(void) {
|
||||||
WSclient_t * client;
|
// adjust clients storage:
|
||||||
|
// _clients[i]'s constructor are already called,
|
||||||
// init client storage
|
// all its members are initialized to their default value,
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
// except the ones explicitly detailed in WSclient_t() constructor.
|
||||||
client = &_clients[i];
|
// Then we need to initialize some members to non-trivial values:
|
||||||
|
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client->num = i;
|
_clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount);
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
client->tcp = NULL;
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
|
||||||
client->isSSL = false;
|
|
||||||
client->ssl = NULL;
|
|
||||||
#endif
|
|
||||||
client->cUrl = "";
|
|
||||||
client->cCode = 0;
|
|
||||||
client->cKey = "";
|
|
||||||
client->cProtocol = "";
|
|
||||||
client->cVersion = 0;
|
|
||||||
client->cIsUpgrade = false;
|
|
||||||
client->cIsWebsocket = false;
|
|
||||||
|
|
||||||
client->base64Authorization = "";
|
|
||||||
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->cHttpLine = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
client->pingInterval = _pingInterval;
|
|
||||||
client->pongTimeout = _pongTimeout;
|
|
||||||
client->disconnectTimeoutCount = _disconnectTimeoutCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
randomSeed(RANDOM_REG32);
|
randomSeed(RANDOM_REG32);
|
||||||
|
#elif defined(ESP32) && defined(WDEV_RND_REG)
|
||||||
|
randomSeed(REG_READ(WDEV_RND_REG));
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
#define DR_REG_RNG_BASE 0x3ff75144
|
#define DR_REG_RNG_BASE 0x3ff75144
|
||||||
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
|
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
randomSeed(rp2040.hwrand32());
|
||||||
#else
|
#else
|
||||||
// TODO find better seed
|
// TODO find better seed
|
||||||
randomSeed(millis());
|
randomSeed(millis());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_runnning = true;
|
_runnning = true;
|
||||||
_server->begin();
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
|
DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsServer::close(void) {
|
void WebSocketsServerCore::close(void) {
|
||||||
_runnning = false;
|
_runnning = false;
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
// restore _clients[] to their initial state
|
||||||
_server->close();
|
// before next call to ::begin()
|
||||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
_server->end();
|
_clients[i] = WSclient_t();
|
||||||
#else
|
|
||||||
// TODO how to close server?
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
|
||||||
* called in arduino loop
|
|
||||||
*/
|
|
||||||
void WebSocketsServer::loop(void) {
|
|
||||||
if(_runnning) {
|
|
||||||
WEBSOCKETS_YIELD();
|
|
||||||
handleNewClients();
|
|
||||||
WEBSOCKETS_YIELD();
|
|
||||||
handleClientData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set callback function
|
* set callback function
|
||||||
* @param cbEvent WebSocketServerEvent
|
* @param cbEvent WebSocketServerEvent
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
|
void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) {
|
||||||
_cbEvent = cbEvent;
|
_cbEvent = cbEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +137,7 @@ void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
|
|||||||
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
|
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
|
||||||
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
|
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::onValidateHttpHeader(
|
void WebSocketsServerCore::onValidateHttpHeader(
|
||||||
WebSocketServerHttpHeaderValFunc validationFunc,
|
WebSocketServerHttpHeaderValFunc validationFunc,
|
||||||
const char * mandatoryHttpHeaders[],
|
const char * mandatoryHttpHeaders[],
|
||||||
size_t mandatoryHttpHeaderCount) {
|
size_t mandatoryHttpHeaderCount) {
|
||||||
@ -182,7 +162,7 @@ void WebSocketsServer::onValidateHttpHeader(
|
|||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -196,19 +176,19 @@ bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
|
||||||
return sendTXT(num, (uint8_t *)payload, length);
|
return sendTXT(num, (uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
|
||||||
return sendTXT(num, (uint8_t *)payload, length, headerToPayload);
|
return sendTXT(num, (uint8_t *)payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) {
|
bool WebSocketsServerCore::sendTXT(uint8_t num, const char * payload, size_t length) {
|
||||||
return sendTXT(num, (uint8_t *)payload, length);
|
return sendTXT(num, (uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, String & payload) {
|
bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) {
|
||||||
return sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
|
return sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +199,7 @@ bool WebSocketsServer::sendTXT(uint8_t num, String & payload) {
|
|||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
@ -238,19 +218,19 @@ bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool heade
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::broadcastTXT(const uint8_t * payload, size_t length) {
|
||||||
return broadcastTXT((uint8_t *)payload, length);
|
return broadcastTXT((uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
|
||||||
return broadcastTXT((uint8_t *)payload, length, headerToPayload);
|
return broadcastTXT((uint8_t *)payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) {
|
bool WebSocketsServerCore::broadcastTXT(const char * payload, size_t length) {
|
||||||
return broadcastTXT((uint8_t *)payload, length);
|
return broadcastTXT((uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(String & payload) {
|
bool WebSocketsServerCore::broadcastTXT(String & payload) {
|
||||||
return broadcastTXT((uint8_t *)payload.c_str(), payload.length());
|
return broadcastTXT((uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +242,7 @@ bool WebSocketsServer::broadcastTXT(String & payload) {
|
|||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -273,7 +253,7 @@ bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
|
||||||
return sendBIN(num, (uint8_t *)payload, length);
|
return sendBIN(num, (uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +264,7 @@ bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t leng
|
|||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
@ -299,7 +279,7 @@ bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool heade
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length) {
|
||||||
return broadcastBIN((uint8_t *)payload, length);
|
return broadcastBIN((uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +290,7 @@ bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
|
|||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @return true if ping is send out
|
* @return true if ping is send out
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t length) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -321,7 +301,7 @@ bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendPing(uint8_t num, String & payload) {
|
bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) {
|
||||||
return sendPing(num, (uint8_t *)payload.c_str(), payload.length());
|
return sendPing(num, (uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +311,7 @@ bool WebSocketsServer::sendPing(uint8_t num, String & payload) {
|
|||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @return true if ping is send out
|
* @return true if ping is send out
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
|
bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
@ -346,14 +326,14 @@ bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastPing(String & payload) {
|
bool WebSocketsServerCore::broadcastPing(String & payload) {
|
||||||
return broadcastPing((uint8_t *)payload.c_str(), payload.length());
|
return broadcastPing((uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* disconnect all clients
|
* disconnect all clients
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::disconnect(void) {
|
void WebSocketsServerCore::disconnect(void) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client = &_clients[i];
|
client = &_clients[i];
|
||||||
@ -367,7 +347,7 @@ void WebSocketsServer::disconnect(void) {
|
|||||||
* disconnect one client
|
* disconnect one client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::disconnect(uint8_t num) {
|
void WebSocketsServerCore::disconnect(uint8_t num) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -382,7 +362,7 @@ void WebSocketsServer::disconnect(uint8_t num) {
|
|||||||
* @param user const char *
|
* @param user const char *
|
||||||
* @param password const char *
|
* @param password const char *
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::setAuthorization(const char * user, const char * password) {
|
void WebSocketsServerCore::setAuthorization(const char * user, const char * password) {
|
||||||
if(user && password) {
|
if(user && password) {
|
||||||
String auth = user;
|
String auth = user;
|
||||||
auth += ":";
|
auth += ":";
|
||||||
@ -395,7 +375,7 @@ void WebSocketsServer::setAuthorization(const char * user, const char * password
|
|||||||
* set the Authorizatio for the http request
|
* set the Authorizatio for the http request
|
||||||
* @param auth const char * base64
|
* @param auth const char * base64
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::setAuthorization(const char * auth) {
|
void WebSocketsServerCore::setAuthorization(const char * auth) {
|
||||||
if(auth) {
|
if(auth) {
|
||||||
_base64Authorization = auth;
|
_base64Authorization = auth;
|
||||||
}
|
}
|
||||||
@ -405,7 +385,7 @@ void WebSocketsServer::setAuthorization(const char * auth) {
|
|||||||
* count the connected clients (optional ping them)
|
* count the connected clients (optional ping them)
|
||||||
* @param ping bool ping the connected clients
|
* @param ping bool ping the connected clients
|
||||||
*/
|
*/
|
||||||
int WebSocketsServer::connectedClients(bool ping) {
|
int WebSocketsServerCore::connectedClients(bool ping) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
@ -423,7 +403,7 @@ int WebSocketsServer::connectedClients(bool ping) {
|
|||||||
* see if one client is connected
|
* see if one client is connected
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::clientIsConnected(uint8_t num) {
|
bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -431,13 +411,13 @@ bool WebSocketsServer::clientIsConnected(uint8_t num) {
|
|||||||
return clientIsConnected(client);
|
return clientIsConnected(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
/**
|
/**
|
||||||
* get an IP for a client
|
* get an IP for a client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
* @return IPAddress
|
* @return IPAddress
|
||||||
*/
|
*/
|
||||||
IPAddress WebSocketsServer::remoteIP(uint8_t num) {
|
IPAddress WebSocketsServerCore::remoteIP(uint8_t num) {
|
||||||
if(num < WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num < WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
WSclient_t * client = &_clients[num];
|
WSclient_t * client = &_clients[num];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
@ -449,22 +429,30 @@ IPAddress WebSocketsServer::remoteIP(uint8_t num) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
//#################################################################################
|
// #################################################################################
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle new client connection
|
* handle new client connection
|
||||||
* @param client
|
* @param client
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
// search free list entry for client
|
// search free list entry for client
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client = &_clients[i];
|
client = &_clients[i];
|
||||||
|
|
||||||
// state is not connected or tcp connection is lost
|
// look for match to existing socket before creating a new one
|
||||||
if(!clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
||||||
|
// Check to see if it is the same socket - if so, return it
|
||||||
|
if(client->tcp->getSocketNumber() == TCPclient->getSocketNumber()) {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// state is not connected or tcp connection is lost
|
||||||
client->tcp = TCPclient;
|
client->tcp = TCPclient;
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||||
@ -476,7 +464,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|||||||
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||||
#endif
|
#endif
|
||||||
client->status = WSC_HEADER;
|
client->status = WSC_HEADER;
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
#ifndef NODEBUG_WEBSOCKETS
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
IPAddress ip = client->tcp->remoteIP();
|
IPAddress ip = client->tcp->remoteIP();
|
||||||
#endif
|
#endif
|
||||||
@ -486,7 +474,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
client->tcp->onDisconnect(std::bind([](WebSocketsServerCore * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
||||||
|
|
||||||
AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
|
AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
|
||||||
@ -498,7 +486,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|||||||
},
|
},
|
||||||
this, std::placeholders::_1, client));
|
this, std::placeholders::_1, client));
|
||||||
|
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
|
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
client->pingInterval = _pingInterval;
|
client->pingInterval = _pingInterval;
|
||||||
@ -507,11 +495,11 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|||||||
client->lastPing = millis();
|
client->lastPing = millis();
|
||||||
client->pongReceived = false;
|
client->pongReceived = false;
|
||||||
|
|
||||||
return true;
|
return client;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -521,7 +509,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
||||||
WStype_t type = WStype_ERROR;
|
WStype_t type = WStype_ERROR;
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
@ -548,12 +536,38 @@ void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, u
|
|||||||
runCbEvent(client->num, type, payload, length);
|
runCbEvent(client->num, type, payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard a native client
|
||||||
|
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
|
||||||
|
*/
|
||||||
|
void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
||||||
|
if(!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(client->tcp) {
|
||||||
|
if(client->tcp->connected()) {
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_RP2040)
|
||||||
|
client->tcp->flush();
|
||||||
|
#endif
|
||||||
|
client->tcp->stop();
|
||||||
|
}
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED)
|
||||||
|
// does not support delete (no destructor)
|
||||||
|
#else
|
||||||
|
delete client->tcp;
|
||||||
|
#endif
|
||||||
|
client->tcp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect an client
|
* Disconnect an client
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
if(client->isSSL && client->ssl) {
|
if(client->isSSL && client->ssl) {
|
||||||
if(client->ssl->connected()) {
|
if(client->ssl->connected()) {
|
||||||
client->ssl->flush();
|
client->ssl->flush();
|
||||||
@ -565,20 +579,7 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(client->tcp) {
|
dropNativeClient(client);
|
||||||
if(client->tcp->connected()) {
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->flush();
|
|
||||||
#endif
|
|
||||||
client->tcp->stop();
|
|
||||||
}
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
#else
|
|
||||||
delete client->tcp;
|
|
||||||
#endif
|
|
||||||
client->tcp = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->cUrl = "";
|
client->cUrl = "";
|
||||||
client->cKey = "";
|
client->cKey = "";
|
||||||
@ -605,7 +606,7 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @return true = connected
|
* @return true = connected
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
|
bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) {
|
||||||
if(!client->tcp) {
|
if(!client->tcp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -632,20 +633,48 @@ bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
/**
|
||||||
|
* Handle incoming Connection Request
|
||||||
|
*/
|
||||||
|
WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient) {
|
||||||
|
WSclient_t * client = newClient(tcpClient);
|
||||||
|
|
||||||
|
if(!client) {
|
||||||
|
// no free space to handle client
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
|
IPAddress ip = tcpClient->remoteIP();
|
||||||
|
#endif
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||||
|
#else
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
||||||
|
#endif
|
||||||
|
// no client! => create dummy!
|
||||||
|
WSclient_t dummy = WSclient_t();
|
||||||
|
client = &dummy;
|
||||||
|
client->tcp = tcpClient;
|
||||||
|
dropNativeClient(client);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle incoming Connection Request
|
* Handle incoming Connection Request
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleNewClients(void) {
|
void WebSocketsServer::handleNewClients(void) {
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
while(_server->hasClient()) {
|
while(_server->hasClient()) {
|
||||||
#endif
|
#endif
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
// store new connection
|
||||||
// store new connection
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA)
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
||||||
#else
|
#else
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->accept());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!tcpClient) {
|
if(!tcpClient) {
|
||||||
@ -653,23 +682,9 @@ void WebSocketsServer::handleNewClients(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = newClient(tcpClient);
|
handleNewClient(tcpClient);
|
||||||
|
|
||||||
if(!ok) {
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
// no free space to handle client
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
|
||||||
#ifndef NODEBUG_WEBSOCKETS
|
|
||||||
IPAddress ip = tcpClient->remoteIP();
|
|
||||||
#endif
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
|
||||||
#else
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
|
||||||
#endif
|
|
||||||
tcpClient->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
WEBSOCKETS_YIELD();
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -677,14 +692,14 @@ void WebSocketsServer::handleNewClients(void) {
|
|||||||
/**
|
/**
|
||||||
* Handel incomming data from Client
|
* Handel incomming data from Client
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleClientData(void) {
|
void WebSocketsServerCore::handleClientData(void) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client = &_clients[i];
|
client = &_clients[i];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
int len = client->tcp->available();
|
int len = client->tcp->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
//DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
// DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
||||||
switch(client->status) {
|
switch(client->status) {
|
||||||
case WSC_HEADER: {
|
case WSC_HEADER: {
|
||||||
String headerLine = client->tcp->readStringUntil('\n');
|
String headerLine = client->tcp->readStringUntil('\n');
|
||||||
@ -694,6 +709,7 @@ void WebSocketsServer::handleClientData(void) {
|
|||||||
WebSockets::handleWebsocket(client);
|
WebSockets::handleWebsocket(client);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] unknown client status %d\n", client->num, client->status);
|
||||||
WebSockets::clientDisconnect(client, 1002);
|
WebSockets::clientDisconnect(client, 1002);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -711,7 +727,7 @@ void WebSocketsServer::handleClientData(void) {
|
|||||||
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||||
* @param headerName String ///< the name of the header being checked
|
* @param headerName String ///< the name of the header being checked
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::hasMandatoryHeader(String headerName) {
|
bool WebSocketsServerCore::hasMandatoryHeader(String headerName) {
|
||||||
for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
||||||
if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
|
if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
|
||||||
return true;
|
return true;
|
||||||
@ -724,7 +740,7 @@ bool WebSocketsServer::hasMandatoryHeader(String headerName) {
|
|||||||
* @param client WSclient_t * ///< pointer to the client struct
|
* @param client WSclient_t * ///< pointer to the client struct
|
||||||
* @param headerLine String ///< the header being read / processed
|
* @param headerLine String ///< the header being read / processed
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine) {
|
||||||
static const char * NEW_LINE = "\r\n";
|
static const char * NEW_LINE = "\r\n";
|
||||||
|
|
||||||
headerLine->trim(); // remove \r
|
headerLine->trim(); // remove \r
|
||||||
@ -737,7 +753,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
// cut URL out
|
// cut URL out
|
||||||
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
||||||
|
|
||||||
//reset non-websocket http header validation state for this client
|
// reset non-websocket http header validation state for this client
|
||||||
client->cHttpHeadersValid = true;
|
client->cHttpHeadersValid = true;
|
||||||
client->cMandatoryHeadersCount = 0;
|
client->cMandatoryHeadersCount = 0;
|
||||||
|
|
||||||
@ -783,7 +799,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
|
|
||||||
(*headerLine) = "";
|
(*headerLine) = "";
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
|
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
|
||||||
@ -880,7 +896,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
/**
|
/**
|
||||||
* send heartbeat ping to server in set intervals
|
* send heartbeat ping to server in set intervals
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleHBPing(WSclient_t * client) {
|
void WebSocketsServerCore::handleHBPing(WSclient_t * client) {
|
||||||
if(client->pingInterval == 0)
|
if(client->pingInterval == 0)
|
||||||
return;
|
return;
|
||||||
uint32_t pi = millis() - client->lastPing;
|
uint32_t pi = millis() - client->lastPing;
|
||||||
@ -899,7 +915,7 @@ void WebSocketsServer::handleHBPing(WSclient_t * client) {
|
|||||||
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||||
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
void WebSocketsServerCore::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
_pingInterval = pingInterval;
|
_pingInterval = pingInterval;
|
||||||
_pongTimeout = pongTimeout;
|
_pongTimeout = pongTimeout;
|
||||||
_disconnectTimeoutCount = disconnectTimeoutCount;
|
_disconnectTimeoutCount = disconnectTimeoutCount;
|
||||||
@ -914,7 +930,7 @@ void WebSocketsServer::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeo
|
|||||||
/**
|
/**
|
||||||
* disable ping/pong heartbeat process
|
* disable ping/pong heartbeat process
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::disableHeartbeat() {
|
void WebSocketsServerCore::disableHeartbeat() {
|
||||||
_pingInterval = 0;
|
_pingInterval = 0;
|
||||||
|
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
@ -923,3 +939,50 @@ void WebSocketsServer::disableHeartbeat() {
|
|||||||
client->pingInterval = 0;
|
client->pingInterval = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// WebSocketServer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called to initialize the Websocket server
|
||||||
|
*/
|
||||||
|
void WebSocketsServer::begin(void) {
|
||||||
|
WebSocketsServerCore::begin();
|
||||||
|
_server->begin();
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsServer::close(void) {
|
||||||
|
WebSocketsServerCore::close();
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
|
_server->close();
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
_server->end();
|
||||||
|
#else
|
||||||
|
// TODO how to close server?
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
/**
|
||||||
|
* called in arduino loop
|
||||||
|
*/
|
||||||
|
void WebSocketsServerCore::loop(void) {
|
||||||
|
if(_runnning) {
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
handleClientData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called in arduino loop
|
||||||
|
*/
|
||||||
|
void WebSocketsServer::loop(void) {
|
||||||
|
if(_runnning) {
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
handleNewClients();
|
||||||
|
WebSocketsServerCore::loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -31,8 +31,14 @@
|
|||||||
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class WebSocketsServer : protected WebSockets {
|
class WebSocketsServerCore : protected WebSockets {
|
||||||
public:
|
public:
|
||||||
|
WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino");
|
||||||
|
virtual ~WebSocketsServerCore(void);
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void close(void);
|
||||||
|
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
||||||
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
|
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
|
||||||
@ -41,19 +47,6 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
|
typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino");
|
|
||||||
virtual ~WebSocketsServer(void);
|
|
||||||
|
|
||||||
void begin(void);
|
|
||||||
void close(void);
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void loop(void);
|
|
||||||
#else
|
|
||||||
// Async interface not need a loop call
|
|
||||||
void loop(void) __attribute__((deprecated)) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void onEvent(WebSocketServerEvent cbEvent);
|
void onEvent(WebSocketServerEvent cbEvent);
|
||||||
void onValidateHttpHeader(
|
void onValidateHttpHeader(
|
||||||
WebSocketServerHttpHeaderValFunc validationFunc,
|
WebSocketServerHttpHeaderValFunc validationFunc,
|
||||||
@ -97,20 +90,23 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||||
void disableHeartbeat();
|
void disableHeartbeat();
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||||
IPAddress remoteIP(uint8_t num);
|
IPAddress remoteIP(uint8_t num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void loop(void); // handle client data only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint16_t _port;
|
|
||||||
String _origin;
|
String _origin;
|
||||||
String _protocol;
|
String _protocol;
|
||||||
String _base64Authorization; ///< Base64 encoded Auth request
|
String _base64Authorization; ///< Base64 encoded Auth request
|
||||||
String * _mandatoryHttpHeaders;
|
String * _mandatoryHttpHeaders;
|
||||||
size_t _mandatoryHttpHeaderCount;
|
size_t _mandatoryHttpHeaderCount;
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
|
||||||
|
|
||||||
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
||||||
|
|
||||||
WebSocketServerEvent _cbEvent;
|
WebSocketServerEvent _cbEvent;
|
||||||
@ -122,15 +118,12 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
uint32_t _pongTimeout;
|
uint32_t _pongTimeout;
|
||||||
uint8_t _disconnectTimeoutCount;
|
uint8_t _disconnectTimeoutCount;
|
||||||
|
|
||||||
bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
|
||||||
|
|
||||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
void clientDisconnect(WSclient_t * client);
|
||||||
bool clientIsConnected(WSclient_t * client);
|
bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
void handleNewClients(void);
|
|
||||||
void handleClientData(void);
|
void handleClientData(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -139,10 +132,10 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Websocket connection is coming in.
|
* called if a non Websocket connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
||||||
client->tcp->write(
|
client->tcp->write(
|
||||||
@ -158,10 +151,10 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Authorization connection is coming in.
|
* called if a non Authorization connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
||||||
client->tcp->write(
|
client->tcp->write(
|
||||||
"HTTP/1.1 401 Unauthorized\r\n"
|
"HTTP/1.1 401 Unauthorized\r\n"
|
||||||
@ -177,12 +170,12 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param num uint8_t
|
* @param num uint8_t
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(num, type, payload, length);
|
_cbEvent(num, type, payload, length);
|
||||||
@ -190,28 +183,61 @@ class WebSocketsServer : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called at client socket connect handshake negotiation time for each http header that is not
|
* Called at client socket connect handshake negotiation time for each http header that is not
|
||||||
* a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
|
* a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
|
||||||
* If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
|
* If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
|
||||||
* socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
|
* socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
|
||||||
* This mechanism can be used to enable custom authentication schemes e.g. test the value
|
* This mechanism can be used to enable custom authentication schemes e.g. test the value
|
||||||
* of a session cookie to determine if a user is logged on / authenticated
|
* of a session cookie to determine if a user is logged on / authenticated
|
||||||
*/
|
*/
|
||||||
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
||||||
if(_httpHeaderValidationFunc) {
|
if(_httpHeaderValidationFunc) {
|
||||||
//return the value of the custom http header validation function
|
// return the value of the custom http header validation function
|
||||||
return _httpHeaderValidationFunc(headerName, headerValue);
|
return _httpHeaderValidationFunc(headerName, headerValue);
|
||||||
}
|
}
|
||||||
//no custom http header validation so just assume all is good
|
// no custom http header validation so just assume all is good
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drop native tcp connection (client->tcp)
|
||||||
|
*/
|
||||||
|
void dropNativeClient(WSclient_t * client);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||||
* @param headerName String ///< the name of the header being checked
|
* @param headerName String ///< the name of the header being checked
|
||||||
*/
|
*/
|
||||||
bool hasMandatoryHeader(String headerName);
|
bool hasMandatoryHeader(String headerName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WebSocketsServer : public WebSocketsServerCore {
|
||||||
|
public:
|
||||||
|
WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino");
|
||||||
|
virtual ~WebSocketsServer(void);
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void close(void);
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void loop(void); // handle incoming client and client data
|
||||||
|
#else
|
||||||
|
// Async interface not need a loop call
|
||||||
|
void loop(void) __attribute__((deprecated)) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void handleNewClients(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t _port;
|
||||||
|
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* WEBSOCKETSSERVER_H_ */
|
#endif /* WEBSOCKETSSERVER_H_ */
|
||||||
|
36
src/WebSocketsVersion.h
Normal file
36
src/WebSocketsVersion.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date 06.09.2024
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* 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 WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "2.6.1"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR 2
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR 6
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH 1
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT 2006001
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
#include <core_esp8266_features.h>
|
#include <core_esp8266_features.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0)
|
||||||
#define CORE_HAS_LIBB64
|
#define CORE_HAS_LIBB64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
#include <core_esp8266_features.h>
|
#include <core_esp8266_features.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0)
|
||||||
#define CORE_HAS_LIBB64
|
#define CORE_HAS_LIBB64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
116
travis/common.sh
116
travis/common.sh
@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
function build_sketches()
|
function build_sketches()
|
||||||
{
|
{
|
||||||
@ -27,27 +28,132 @@ function build_sketches()
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function build_sketch_cli()
|
||||||
|
{
|
||||||
|
local sketch=$1
|
||||||
|
local board=$2
|
||||||
|
arduino-cli --log --log-level info compile -b "$board" "$sketch"
|
||||||
|
result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($sketch) build verbose..."
|
||||||
|
arduino-cli --log --log-level debug compile -b "$board" "$sketch"
|
||||||
|
result=$?
|
||||||
|
fi
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($1) $sketch"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_sketch()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local sketch=$2
|
||||||
|
$arduino --verify --verbose $sketch;
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($sketch) build verbose..."
|
||||||
|
$arduino --verify --verbose --preserve-temp-files $sketch
|
||||||
|
result=$?
|
||||||
|
fi
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($1) $sketch"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
echo -en "["
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "\"$sketch\""
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
echo -en "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json_matrix()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local cliversion=$4
|
||||||
|
local board=$5
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "{\"name\":\"$sketchname\",\"board\":\"$board\",\"cliversion\":\"$cliversion\",\"cpu\":\"$platform\",\"sketch\":\"$sketch\"}"
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_core_cli() {
|
||||||
|
export ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS="https://arduino.esp8266.com/stable/package_esp8266com_index.json https://espressif.github.io/arduino-esp32/package_esp32_index.json https://github.com/earlephilhower/arduino-pico/releases/download/3.9.2/package_rp2040_index.json"
|
||||||
|
arduino-cli core update-index
|
||||||
|
arduino-cli core install esp8266:esp8266
|
||||||
|
arduino-cli core install esp32:esp32
|
||||||
|
arduino-cli core install rp2040:rp2040
|
||||||
|
}
|
||||||
|
|
||||||
function get_core()
|
function get_core()
|
||||||
{
|
{
|
||||||
echo Setup core for $1
|
echo Setup core for $1
|
||||||
|
|
||||||
cd $HOME/arduino_ide/hardware
|
mkdir -p $HOME/arduino_ide/packages/hardware
|
||||||
|
cd $HOME/arduino_ide/packages/hardware
|
||||||
|
|
||||||
if [ "$1" = "esp8266" ] ; then
|
if [ "$1" = "esp8266" ] ; then
|
||||||
mkdir esp8266com
|
mkdir esp8266com
|
||||||
cd esp8266com
|
cd esp8266com
|
||||||
git clone https://github.com/esp8266/Arduino.git esp8266
|
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266
|
||||||
cd esp8266/tools
|
cd esp8266/
|
||||||
|
git submodule update --init
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
python get.py
|
python get.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" = "esp32" ] ; then
|
if [ "$1" = "esp32" ] ; then
|
||||||
mkdir espressif
|
mkdir espressif
|
||||||
cd espressif
|
cd espressif
|
||||||
git clone https://github.com/espressif/arduino-esp32.git esp32
|
git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32
|
||||||
cd esp32/tools
|
cd esp32/
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
python get.py
|
python get.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clone_library() {
|
||||||
|
local url=$1
|
||||||
|
echo clone $(basename $url)
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
git clone --depth 1 $url
|
||||||
|
rm -rf */.git
|
||||||
|
rm -rf */.github
|
||||||
|
rm -rf */examples
|
||||||
|
}
|
||||||
|
|
||||||
|
function hash_library_names() {
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
ls | sha1sum -z | cut -c1-5
|
||||||
|
}
|
132
travis/version.py
Executable file
132
travis/version.py
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import configparser
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
travis_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
base_dir = os.path.abspath(travis_dir + "/../")
|
||||||
|
|
||||||
|
def write_header_file(version):
|
||||||
|
hvs = version.split('.')
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
text = f'''/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date {now.strftime("%d.%m.%Y")}
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* 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 WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "{version}"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR {hvs[0]}
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR {hvs[1]}
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH {hvs[2]}
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT {intversion}
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
||||||
|
'''
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'w') as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_properties_version():
|
||||||
|
library_properties = {}
|
||||||
|
with open(f'{base_dir}/library.properties', 'r') as f:
|
||||||
|
library_properties = configparser.ConfigParser()
|
||||||
|
library_properties.read_string('[root]\n' + f.read())
|
||||||
|
return library_properties['root']['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_json_version():
|
||||||
|
library_json = {}
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
return library_json['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_header_versions():
|
||||||
|
data = {}
|
||||||
|
define = re.compile('^#define WEBSOCKETS_VERSION_?(.*) "?([0-9\.]*)"?$')
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
m = define.match(line)
|
||||||
|
if m:
|
||||||
|
name = m[1]
|
||||||
|
if name == "":
|
||||||
|
name = "VERSION"
|
||||||
|
data[name] = m[2]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Checks and update Version files')
|
||||||
|
parser.add_argument(
|
||||||
|
'--update', action='store_true', default=False)
|
||||||
|
parser.add_argument(
|
||||||
|
'--check', action='store_true', default=True)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.update:
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
|
||||||
|
library_json['version'] = library_properties_version
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'w') as f:
|
||||||
|
json.dump(library_json, f, indent=4, sort_keys=True)
|
||||||
|
|
||||||
|
write_header_file(library_properties_version)
|
||||||
|
|
||||||
|
|
||||||
|
library_json_version = get_library_json_version()
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
header_version = get_header_versions()
|
||||||
|
|
||||||
|
print("WebSocketsVersion.h", header_version)
|
||||||
|
print(f"library.json: {library_json_version}")
|
||||||
|
print(f"library.properties: {library_properties_version}")
|
||||||
|
|
||||||
|
if args.check:
|
||||||
|
if library_json_version != library_properties_version or header_version['VERSION'] != library_properties_version:
|
||||||
|
raise Exception('versions did not match!')
|
||||||
|
|
||||||
|
hvs = header_version['VERSION'].split('.')
|
||||||
|
if header_version['MAJOR'] != hvs[0]:
|
||||||
|
raise Exception('header MAJOR version wrong!')
|
||||||
|
if header_version['MINOR'] != hvs[1]:
|
||||||
|
raise Exception('header MINOR version wrong!')
|
||||||
|
if header_version['PATCH'] != hvs[2]:
|
||||||
|
raise Exception('header PATCH version wrong!')
|
||||||
|
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
if int(header_version['INT']) != intversion:
|
||||||
|
raise Exception('header INT version wrong!')
|
Reference in New Issue
Block a user