├── .clang-format ├── .github ├── dependabot.yml └── workflows │ ├── arduino-lint.yaml │ ├── compile-arduino_wifinina-examples.yaml │ ├── compile-seeed-studio-examples.yaml │ ├── compile-unor4wifi-examples.yaml │ └── main.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── Nginx │ └── esp8266.ssl.reverse.proxy.conf ├── arduino_renesas │ └── arduino_uno_r4_wifi │ │ └── arduino_uno_r4_wifi.ino ├── arduino_wifinina │ └── arduino_wifinina.ino ├── avr │ └── WebSocketClientAVR │ │ └── WebSocketClientAVR.ino ├── esp32 │ ├── WebSocketClient │ │ └── WebSocketClient.ino │ ├── WebSocketClientSSL │ │ └── WebSocketClientSSL.ino │ ├── WebSocketClientSSLBundle │ │ └── WebSocketClientSSLBundle.ino │ ├── WebSocketClientSocketIOack │ │ └── WebSocketClientSocketIOack.ino │ └── WebSocketServer │ │ └── WebSocketServer.ino ├── esp32_pio │ └── WebSocketClientSSLBundle │ │ ├── .gitignore │ │ ├── cacrt_all.pem │ │ ├── cmn_crt_authorities.csv │ │ ├── gen_crt_bundle.py │ │ ├── lib │ │ └── README │ │ ├── platformio.ini │ │ ├── readme.md │ │ ├── run_gen_script.py │ │ └── src │ │ └── main.cpp ├── esp8266_pico │ ├── WebSocketClient │ │ └── WebSocketClient.ino │ ├── WebSocketClientOTA │ │ ├── README.md │ │ ├── WebSocketClientOTA.ino │ │ └── python_ota_server │ │ │ ├── main.py │ │ │ └── requirements.txt │ ├── WebSocketClientSSL │ │ └── WebSocketClientSSL.ino │ ├── WebSocketClientSSLWithCA │ │ └── WebSocketClientSSLWithCA.ino │ ├── WebSocketClientSocketIO │ │ └── WebSocketClientSocketIO.ino │ ├── WebSocketClientSocketIOack │ │ └── WebSocketClientSocketIOack.ino │ ├── WebSocketClientStomp │ │ └── WebSocketClientStomp.ino │ ├── WebSocketClientStompOverSockJs │ │ └── WebSocketClientStompOverSockJs.ino │ ├── WebSocketServer │ │ └── WebSocketServer.ino │ ├── WebSocketServerAllFunctionsDemo │ │ └── WebSocketServerAllFunctionsDemo.ino │ ├── WebSocketServerFragmentation │ │ └── WebSocketServerFragmentation.ino │ ├── WebSocketServerHooked │ │ ├── WebSocketServerHooked.ino │ │ ├── emu │ │ └── ws-testclient.py │ ├── WebSocketServerHttpHeaderValidation │ │ └── WebSocketServerHttpHeaderValidation.ino │ └── WebSocketServer_LEDcontrol │ │ └── WebSocketServer_LEDcontrol.ino ├── particle │ └── ParticleWebSocketClient │ │ └── application.cpp └── seeed-studio │ └── xio-wio-terminal │ └── WebSocketClient │ └── WebSocketClient.ino ├── library.json ├── library.properties ├── src ├── SocketIOclient.cpp ├── SocketIOclient.h ├── WebSockets.cpp ├── WebSockets.h ├── WebSockets4WebServer.h ├── WebSocketsClient.cpp ├── WebSocketsClient.h ├── WebSocketsServer.cpp ├── WebSocketsServer.h ├── WebSocketsVersion.h ├── libb64 │ ├── AUTHORS │ ├── LICENSE │ ├── cdecode.c │ ├── cdecode_inc.h │ ├── cencode.c │ └── cencode_inc.h └── libsha1 │ ├── libsha1.c │ └── libsha1.h ├── tests ├── webSocket.html └── webSocketServer │ ├── index.js │ └── package.json └── travis ├── common.sh └── version.py /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: '-2' 4 | AlignAfterOpenBracket: DontAlign 5 | AlignConsecutiveAssignments: 'true' 6 | AlignConsecutiveDeclarations: 'false' 7 | AlignEscapedNewlines: Left 8 | AlignTrailingComments: 'true' 9 | AllowAllParametersOfDeclarationOnNextLine: 'false' 10 | AllowShortBlocksOnASingleLine: 'false' 11 | AllowShortCaseLabelsOnASingleLine: 'false' 12 | AllowShortFunctionsOnASingleLine: InlineOnly 13 | AllowShortIfStatementsOnASingleLine: 'true' 14 | AllowShortLoopsOnASingleLine: 'true' 15 | AlwaysBreakAfterDefinitionReturnType: None 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakBeforeMultilineStrings: 'true' 18 | AlwaysBreakTemplateDeclarations: 'false' 19 | BinPackParameters: 'true' 20 | BreakAfterJavaFieldAnnotations: 'false' 21 | BreakBeforeBinaryOperators: None 22 | BreakBeforeBraces: Attach 23 | BreakBeforeInheritanceComma: 'false' 24 | BreakBeforeTernaryOperators: 'false' 25 | BreakConstructorInitializers: BeforeColon 26 | BreakStringLiterals: 'false' 27 | ColumnLimit: '0' 28 | CompactNamespaces: 'true' 29 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' 30 | ConstructorInitializerIndentWidth: '4' 31 | ContinuationIndentWidth: '4' 32 | Cpp11BracedListStyle: 'false' 33 | DerivePointerAlignment: 'false' 34 | FixNamespaceComments: 'true' 35 | IndentCaseLabels: 'true' 36 | IndentWidth: '4' 37 | IndentWrappedFunctionNames: 'false' 38 | JavaScriptQuotes: Single 39 | JavaScriptWrapImports: 'false' 40 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 41 | MaxEmptyLinesToKeep: '1' 42 | NamespaceIndentation: All 43 | ObjCBlockIndentWidth: '4' 44 | ObjCSpaceAfterProperty: 'false' 45 | ObjCSpaceBeforeProtocolList: 'false' 46 | PointerAlignment: Middle 47 | SortIncludes: 'false' 48 | SortUsingDeclarations: 'true' 49 | SpaceAfterCStyleCast: 'false' 50 | SpaceAfterTemplateKeyword: 'false' 51 | SpaceBeforeAssignmentOperators: 'true' 52 | SpaceBeforeParens: Never 53 | SpaceInEmptyParentheses: 'false' 54 | SpacesBeforeTrailingComments: '4' 55 | SpacesInAngles: 'false' 56 | SpacesInCStyleCastParentheses: 'false' 57 | SpacesInContainerLiterals: 'false' 58 | SpacesInParentheses: 'false' 59 | SpacesInSquareBrackets: 'false' 60 | TabWidth: '4' 61 | UseTab: Never 62 | 63 | ... 64 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/arduino-lint.yaml: -------------------------------------------------------------------------------- 1 | name: Arduino library compliance (Lint) 2 | on: [push, pull_request] 3 | jobs: 4 | lint: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - uses: arduino/arduino-lint-action@v2 9 | with: 10 | library-manager: update 11 | -------------------------------------------------------------------------------- /.github/workflows/compile-arduino_wifinina-examples.yaml: -------------------------------------------------------------------------------- 1 | name: Compile Arduino WiFiNINA Examples 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/compile-arduino_wifinina-examples.yaml" 8 | - "examples/arduino_wifinina/**" 9 | - "src/**" 10 | pull_request: 11 | paths: 12 | - ".github/workflows/compile-arduino_wifinina-examples.yaml" 13 | - "examples/arduino_wifinina/**" 14 | - "src/**" 15 | schedule: 16 | # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). 17 | - cron: "0 8 * * TUE" 18 | workflow_dispatch: 19 | repository_dispatch: 20 | 21 | jobs: 22 | build: 23 | name: ${{ matrix.board.fqbn }} 24 | runs-on: ubuntu-latest 25 | 26 | env: 27 | SKETCHES_REPORTS_PATH: sketches-reports 28 | 29 | strategy: 30 | fail-fast: false 31 | 32 | matrix: 33 | board: 34 | - fqbn: arduino:samd:mkrwifi1010 35 | platforms: | 36 | - name: arduino:samd 37 | artifact-name-suffix: arduino-samd-mkrwifi1010 38 | libraries: | 39 | - name: WiFiNINA 40 | - fqbn: arduino:samd:nano_33_iot 41 | platforms: | 42 | - name: arduino:samd 43 | artifact-name-suffix: arduino-samd-nano_33_iot 44 | libraries: | 45 | - name: WiFiNINA 46 | steps: 47 | - name: Checkout repository 48 | uses: actions/checkout@v4 49 | 50 | - name: Compile examples 51 | uses: arduino/compile-sketches@v1 52 | with: 53 | fqbn: ${{ matrix.board.fqbn }} 54 | platforms: ${{ matrix.board.platforms }} 55 | libraries: | 56 | # Install the library from the local path. 57 | - source-path: ./ 58 | ${{ matrix.board.libraries }} 59 | sketch-paths: | 60 | - examples/arduino_wifinina/arduino_wifinina.ino 61 | enable-deltas-report: true 62 | sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} 63 | 64 | - name: Save sketches report as workflow artifact 65 | uses: actions/upload-artifact@v4 66 | with: 67 | if-no-files-found: error 68 | path: ${{ env.SKETCHES_REPORTS_PATH }} 69 | name: sketches-report-${{ matrix.board.artifact-name-suffix }} 70 | -------------------------------------------------------------------------------- /.github/workflows/compile-seeed-studio-examples.yaml: -------------------------------------------------------------------------------- 1 | name: Compile SeedStudio Examples 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/compile-seeed-studio-examples.yaml" 8 | - "examples/seeed-studio/**" 9 | - "src/**" 10 | pull_request: 11 | paths: 12 | - ".github/workflows/compile-seeed-studio-examples.yaml" 13 | - "examples/seeed-studio/**" 14 | - "src/**" 15 | schedule: 16 | # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). 17 | - cron: "0 8 * * TUE" 18 | workflow_dispatch: 19 | repository_dispatch: 20 | 21 | jobs: 22 | build: 23 | name: ${{ matrix.board.fqbn }} 24 | runs-on: ubuntu-latest 25 | 26 | env: 27 | SKETCHES_REPORTS_PATH: sketches-reports 28 | 29 | strategy: 30 | fail-fast: false 31 | 32 | matrix: 33 | board: 34 | - fqbn: Seeeduino:samd:seeed_XIAO_m0:usbstack=arduino,debug=off 35 | platforms: | 36 | - name: Seeeduino:samd 37 | source-url: https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json 38 | libraries: | 39 | - name: Seeed Arduino rpcWiFi 40 | - name: Seeed Arduino rpcUnified 41 | - name: Seeed_Arduino_mbedtls 42 | - name: Seeed Arduino FS 43 | - name: Seeed Arduino SFUD 44 | artifact-name-suffix: seeeduino-xia0 45 | - fqbn: Seeeduino:samd:seeed_wio_terminal 46 | platforms: | 47 | - name: Seeeduino:samd 48 | source-url: https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json 49 | libraries: | 50 | - name: Seeed Arduino rpcWiFi 51 | - name: Seeed Arduino rpcUnified 52 | - name: Seeed_Arduino_mbedtls 53 | - name: Seeed Arduino FS 54 | - name: Seeed Arduino SFUD 55 | artifact-name-suffix: seeeduino-wio_terminal 56 | 57 | steps: 58 | - name: Checkout repository 59 | uses: actions/checkout@v4 60 | 61 | - name: Compile examples 62 | uses: arduino/compile-sketches@v1 63 | with: 64 | github-token: ${{ secrets.GITHUB_TOKEN }} 65 | fqbn: ${{ matrix.board.fqbn }} 66 | platforms: ${{ matrix.board.platforms }} 67 | libraries: | 68 | # Install the library from the local path. 69 | - source-path: ./ 70 | ${{ matrix.board.libraries }} 71 | sketch-paths: | 72 | - examples/seeed-studio/xio-wio-terminal/WebSocketClient 73 | enable-deltas-report: true 74 | sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} 75 | 76 | - name: Save sketches report as workflow artifact 77 | uses: actions/upload-artifact@v4 78 | with: 79 | if-no-files-found: error 80 | path: ${{ env.SKETCHES_REPORTS_PATH }} 81 | name: sketches-report-${{ matrix.board.artifact-name-suffix }} -------------------------------------------------------------------------------- /.github/workflows/compile-unor4wifi-examples.yaml: -------------------------------------------------------------------------------- 1 | name: Compile Arduino UNO R4 WiFi Examples 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/compile-unor4wifi-examples.yaml" 8 | - "examples/arduino_renesas/**" 9 | - "src/**" 10 | pull_request: 11 | paths: 12 | - ".github/workflows/compile-unor4wifi-examples.yaml" 13 | - "examples/arduino_renesas/**" 14 | - "src/**" 15 | schedule: 16 | # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). 17 | - cron: "0 8 * * TUE" 18 | workflow_dispatch: 19 | repository_dispatch: 20 | 21 | jobs: 22 | build: 23 | name: ${{ matrix.board.fqbn }} 24 | runs-on: ubuntu-latest 25 | 26 | env: 27 | SKETCHES_REPORTS_PATH: sketches-reports 28 | 29 | strategy: 30 | fail-fast: false 31 | 32 | matrix: 33 | board: 34 | - fqbn: arduino:renesas_uno:unor4wifi 35 | platforms: | 36 | - name: arduino:renesas_uno 37 | 38 | steps: 39 | - name: Checkout repository 40 | uses: actions/checkout@v4 41 | 42 | - name: Compile examples 43 | uses: arduino/compile-sketches@v1 44 | with: 45 | fqbn: ${{ matrix.board.fqbn }} 46 | platforms: ${{ matrix.board.platforms }} 47 | libraries: | 48 | # Install the library from the local path. 49 | - source-path: ./ 50 | sketch-paths: | 51 | - examples/arduino_renesas/arduino_uno_r4_wifi 52 | enable-deltas-report: true 53 | sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} 54 | 55 | - name: Save sketches report as workflow artifact 56 | uses: actions/upload-artifact@v4 57 | with: 58 | if-no-files-found: error 59 | path: ${{ env.SKETCHES_REPORTS_PATH }} 60 | name: sketches-report-${{ matrix.board.artifact-name-suffix }} 61 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | schedule: 4 | - cron: '0 0 * * 5' 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | release: 10 | types: [ published, created, edited ] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | check_version_files: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: check version 23 | run: | 24 | $GITHUB_WORKSPACE/travis/version.py --check 25 | 26 | prepare_example_json: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: generate examples 32 | id: set-matrix 33 | run: | 34 | source $GITHUB_WORKSPACE/travis/common.sh 35 | cd $GITHUB_WORKSPACE 36 | 37 | echo -en "matrix=" >> $GITHUB_OUTPUT 38 | echo -en "[" >> $GITHUB_OUTPUT 39 | 40 | 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 41 | echo -en "," >> $GITHUB_OUTPUT 42 | 43 | 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 44 | echo -en "," >> $GITHUB_OUTPUT 45 | 46 | get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 0.35.3 esp32:esp32:esp32:FlashFreq=80 >> $GITHUB_OUTPUT 47 | 48 | echo -en "]" >> $GITHUB_OUTPUT 49 | echo >> $GITHUB_OUTPUT 50 | outputs: 51 | matrix: ${{ steps.set-matrix.outputs.matrix }} 52 | 53 | prepare_ide: 54 | runs-on: ubuntu-latest 55 | strategy: 56 | fail-fast: false 57 | matrix: 58 | CLI_VERSION: [0.35.3] 59 | env: 60 | CLI_VERSION: ${{ matrix.CLI_VERSION }} 61 | ARDUINO_DIRECTORIES_DATA: /home/runner/arduino_ide 62 | 63 | steps: 64 | - uses: actions/checkout@v4 65 | 66 | - name: Get hash 67 | id: get-hash 68 | run: | 69 | echo "hash=$(/bin/date -u "+%Y%m%d")-$(md5sum ".github/workflows/main.yml" | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT 70 | shell: bash 71 | 72 | - uses: actions/cache@v4 73 | id: cache_all 74 | with: 75 | path: | 76 | /home/runner/arduino_ide 77 | /home/runner/Arduino 78 | key: ${{ runner.os }}-${{ steps.get-hash.outputs.hash }}-${{ matrix.CLI_VERSION }}-cli 79 | 80 | - name: download IDE 81 | if: steps.cache_all.outputs.cache-hit != 'true' 82 | run: | 83 | wget https://github.com/arduino/arduino-cli/releases/download/v${CLI_VERSION}/arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz -q 84 | tar xf arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz 85 | mkdir -p $ARDUINO_DIRECTORIES_DATA 86 | mv arduino-cli $ARDUINO_DIRECTORIES_DATA/ 87 | 88 | - name: download ArduinoJson 89 | if: steps.cache_all.outputs.cache-hit != 'true' 90 | run: | 91 | mkdir -p $HOME/Arduino/libraries 92 | wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip -q 93 | unzip 6.x.zip 94 | mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson 95 | 96 | - name: download cores 97 | if: steps.cache_all.outputs.cache-hit != 'true' 98 | run: | 99 | export PATH="$ARDUINO_DIRECTORIES_DATA:$PATH" 100 | source $GITHUB_WORKSPACE/travis/common.sh 101 | get_core_cli 102 | 103 | build: 104 | needs: [prepare_ide, prepare_example_json] 105 | runs-on: ubuntu-latest 106 | strategy: 107 | fail-fast: false 108 | matrix: 109 | include: ${{ fromJson(needs.prepare_example_json.outputs.matrix) }} 110 | env: 111 | CPU: ${{ matrix.cpu }} 112 | BOARD: ${{ matrix.board }} 113 | CLI_VERSION: ${{ matrix.cliversion }} 114 | SKETCH: ${{ matrix.sketch }} 115 | ARDUINO_DIRECTORIES_DATA: /home/runner/arduino_ide 116 | 117 | # Steps represent a sequence of tasks that will be executed as part of the job 118 | steps: 119 | - uses: actions/checkout@v4 120 | 121 | - name: install libgtk2.0-0 122 | run: | 123 | sudo apt-get install -y libgtk2.0-0 124 | 125 | - name: Get hash 126 | id: get-hash 127 | run: | 128 | echo "hash=$(/bin/date -u "+%Y%m%d")-$(md5sum ".github/workflows/main.yml" | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT 129 | shell: bash 130 | 131 | - uses: actions/cache@v4 132 | id: cache_all 133 | with: 134 | path: | 135 | /home/runner/arduino_ide 136 | /home/runner/Arduino 137 | key: ${{ runner.os }}-${{ steps.get-hash.outputs.hash }}-${{ matrix.cliversion }}-cli 138 | 139 | - name: install python serial 140 | if: matrix.cpu == 'esp32' 141 | run: | 142 | sudo pip3 install pyserial 143 | sudo pip install pyserial 144 | # sudo apt install python-is-python3 145 | 146 | - name: test IDE 147 | run: | 148 | export PATH="$ARDUINO_DIRECTORIES_DATA:$PATH" 149 | which arduino-cli 150 | 151 | - name: copy code 152 | run: | 153 | mkdir -p $HOME/Arduino/libraries/ 154 | cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/arduinoWebSockets 155 | 156 | - name: build example 157 | timeout-minutes: 20 158 | run: | 159 | set -ex 160 | export PATH="$HOME/arduino_ide:$PATH" 161 | source $GITHUB_WORKSPACE/travis/common.sh 162 | cd $GITHUB_WORKSPACE 163 | build_sketch_cli "$SKETCH" "$BOARD" 164 | 165 | done: 166 | needs: [prepare_ide, prepare_example_json, build, check_version_files] 167 | runs-on: ubuntu-latest 168 | steps: 169 | - name: Done 170 | run: | 171 | echo DONE 172 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | /tests/webSocketServer/node_modules 30 | 31 | # IDE 32 | .vscode 33 | .cproject 34 | .project 35 | .settings 36 | *.swp 37 | 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: 3 | - xenial 4 | addons: 5 | apt: 6 | packages: 7 | - xvfb 8 | language: bash 9 | os: 10 | - linux 11 | env: 12 | matrix: 13 | - CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.13 14 | - CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.13 15 | - CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13 16 | - CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5 17 | - CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9 18 | - CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.13 19 | script: 20 | - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16 21 | - export DISPLAY=:1.0 22 | - sleep 3 23 | - wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz 24 | - tar xf arduino-$IDE_VERSION-linux64.tar.xz 25 | - mv arduino-$IDE_VERSION $HOME/arduino_ide 26 | - export PATH="$HOME/arduino_ide:$PATH" 27 | - which arduino 28 | - mkdir -p $HOME/Arduino/libraries 29 | 30 | - wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip 31 | - unzip 6.x.zip 32 | - mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson 33 | - cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets 34 | - source $TRAVIS_BUILD_DIR/travis/common.sh 35 | - get_core $CPU 36 | - cd $TRAVIS_BUILD_DIR 37 | - arduino --board $BOARD --save-prefs 38 | - arduino --get-pref sketchbook.path 39 | - arduino --pref update.check=false 40 | - build_sketches arduino $HOME/Arduino/libraries/arduinoWebSockets/examples/$CPU $CPU 41 | 42 | notifications: 43 | email: 44 | on_success: change 45 | on_failure: change 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebSocket Server and Client for Arduino [![Build Status](https://github.com/Links2004/arduinoWebSockets/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/Links2004/arduinoWebSockets/actions?query=branch%3Amaster) 2 | =========================================== 3 | 4 | a WebSocket Server and Client for Arduino based on RFC6455. 5 | 6 | 7 | ##### Supported features of RFC6455 ##### 8 | - text frame 9 | - binary frame 10 | - connection close 11 | - ping 12 | - pong 13 | - continuation frame 14 | 15 | ##### Limitations ##### 16 | - max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define 17 | - max output length has no limit (the hardware is the limit) 18 | - Client send big frames with mask 0x00000000 (on AVR all frames) 19 | - continuation frame reassembly need to be handled in the application code 20 | 21 | ##### Limitations for Async ##### 22 | - Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround. 23 | - wss / SSL is not possible. 24 | 25 | ##### Supported Hardware ##### 26 | - ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/) 27 | - ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32) 28 | - ESP31B 29 | - Raspberry Pi Pico W [Arduino for Pico](https://github.com/earlephilhower/arduino-pico) 30 | - Particle with STM32 ARM Cortex M3 31 | - ATmega328 with Ethernet Shield (ATmega branch) 32 | - ATmega328 with enc28j60 (ATmega branch) 33 | - ATmega2560 with Ethernet Shield (ATmega branch) 34 | - ATmega2560 with enc28j60 (ATmega branch) 35 | - Arduino UNO [R4 WiFi](https://github.com/arduino/ArduinoCore-renesas) 36 | - Arduino Nano 33 IoT, MKR WIFI 1010 (requires [WiFiNINA](https://github.com/arduino-libraries/WiFiNINA/) library) 37 | - Seeeduino XIAO, Seeeduino Wio Terminal (requires [rpcWiFi](https://github.com/Seeed-Studio/Seeed_Arduino_rpcWiFi) library) 38 | 39 | ###### Note: ###### 40 | 41 | version 2.0.0 and up is not compatible with AVR/ATmega, check ATmega branch. 42 | 43 | version 2.3.0 has API changes for the ESP8266 BareSSL (may brakes existing code) 44 | 45 | Arduino for AVR not supports std namespace of c++. 46 | 47 | ### wss / SSL ### 48 | supported for: 49 | - wss client on the ESP8266 50 | - wss / SSL for ESP32 in client mode 51 | - wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets 52 | by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a 53 | sample Nginx server configuration file to enable this. 54 | 55 | ### Root CA Cert Bundles for SSL/TLS connections ### 56 | 57 | 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. 58 | 59 | - For [technical details](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html) 60 | - For a [PlatformIO setup](https://github.com/Duckle29/esp32-certBundle/) 61 | - For an [example](examples/esp32/WebSocketClientSSLBundle/) 62 | 63 | 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. 64 | 65 | ### ESP Async TCP ### 66 | 67 | This libary can run in Async TCP mode on the ESP. 68 | 69 | The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define). 70 | 71 | [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required. 72 | 73 | 74 | ### High Level Client API ### 75 | 76 | - `begin` : Initiate connection sequence to the websocket host. 77 | ```c++ 78 | void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); 79 | void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); 80 | ``` 81 | - `onEvent`: Callback to handle for websocket events 82 | 83 | ```c++ 84 | void onEvent(WebSocketClientEvent cbEvent); 85 | ``` 86 | 87 | - `WebSocketClientEvent`: Handler for websocket events 88 | ```c++ 89 | void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length) 90 | ``` 91 | Where `WStype_t type` is defined as: 92 | ```c++ 93 | typedef enum { 94 | WStype_ERROR, 95 | WStype_DISCONNECTED, 96 | WStype_CONNECTED, 97 | WStype_TEXT, 98 | WStype_BIN, 99 | WStype_FRAGMENT_TEXT_START, 100 | WStype_FRAGMENT_BIN_START, 101 | WStype_FRAGMENT, 102 | WStype_FRAGMENT_FIN, 103 | WStype_PING, 104 | WStype_PONG, 105 | } WStype_t; 106 | ``` 107 | 108 | ### Issues ### 109 | Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues 110 | 111 | ### License and credits ### 112 | 113 | The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE) 114 | 115 | [libb64](http://libb64.sourceforge.net/) written by Chris Venter. It is distributed under Public Domain see [LICENSE](https://github.com/Links2004/arduinoWebSockets/blob/master/src/libb64/LICENSE). 116 | -------------------------------------------------------------------------------- /examples/Nginx/esp8266.ssl.reverse.proxy.conf: -------------------------------------------------------------------------------- 1 | # ESP8266 nginx SSL reverse proxy configuration file (tested and working on nginx v1.10.0) 2 | 3 | # proxy cache location 4 | proxy_cache_path /opt/etc/nginx/cache levels=1:2 keys_zone=ESP8266_cache:10m max_size=10g inactive=5m use_temp_path=off; 5 | 6 | # webserver proxy 7 | server { 8 | 9 | # general server parameters 10 | listen 50080; 11 | server_name myDomain.net; 12 | access_log /opt/var/log/nginx/myDomain.net.access.log; 13 | 14 | # SSL configuration 15 | ssl on; 16 | ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem; 17 | ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem; 18 | ssl_session_cache builtin:1000 shared:SSL:10m; 19 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 20 | ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; 21 | ssl_prefer_server_ciphers on; 22 | 23 | location / { 24 | 25 | # proxy caching configuration 26 | proxy_cache ESP8266_cache; 27 | proxy_cache_revalidate on; 28 | proxy_cache_min_uses 1; 29 | proxy_cache_use_stale off; 30 | proxy_cache_lock on; 31 | # proxy_cache_bypass $http_cache_control; 32 | # include the sessionId cookie value as part of the cache key - keeps the cache per user 33 | # proxy_cache_key $proxy_host$request_uri$cookie_sessionId; 34 | 35 | # header pass through configuration 36 | proxy_set_header Host $host; 37 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 38 | proxy_set_header X-Forwarded-Proto $scheme; 39 | 40 | # ESP8266 custom headers which identify to the device that it's running through an SSL proxy 41 | proxy_set_header X-SSL On; 42 | proxy_set_header X-SSL-WebserverPort 50080; 43 | proxy_set_header X-SSL-WebsocketPort 50081; 44 | 45 | # extra debug headers 46 | add_header X-Proxy-Cache $upstream_cache_status; 47 | add_header X-Forwarded-For $proxy_add_x_forwarded_for; 48 | 49 | # actual proxying configuration 50 | proxy_ssl_session_reuse on; 51 | # target the IP address of the device with proxy_pass 52 | proxy_pass http://192.168.0.20; 53 | proxy_read_timeout 90; 54 | } 55 | } 56 | 57 | # websocket proxy 58 | server { 59 | 60 | # general server parameters 61 | listen 50081; 62 | server_name myDomain.net; 63 | access_log /opt/var/log/nginx/myDomain.net.wss.access.log; 64 | 65 | # SSL configuration 66 | ssl on; 67 | ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem; 68 | ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem; 69 | ssl_session_cache builtin:1000 shared:SSL:10m; 70 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 71 | ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; 72 | ssl_prefer_server_ciphers on; 73 | 74 | location / { 75 | 76 | # websocket upgrade tunnel configuration 77 | proxy_pass http://192.168.0.20:81; 78 | proxy_http_version 1.1; 79 | proxy_set_header Upgrade $http_upgrade; 80 | proxy_set_header Connection "Upgrade"; 81 | proxy_read_timeout 86400; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/arduino_renesas/arduino_uno_r4_wifi/arduino_uno_r4_wifi.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "WiFiS3.h" 6 | #include 7 | 8 | #define WIFI_SSID "" 9 | #define WIFI_PASS "" 10 | 11 | WebSocketsClient webSocket; 12 | 13 | void webSocketEvent(WStype_t type, uint8_t *payload, size_t length) { 14 | 15 | switch (type) { 16 | case WStype_DISCONNECTED: 17 | Serial.println("[WSc] Disconnected!"); 18 | break; 19 | case WStype_CONNECTED: 20 | Serial.println("[WSc] Connected!"); 21 | 22 | // send message to server when Connected 23 | webSocket.sendTXT("Connected"); 24 | break; 25 | case WStype_TEXT: 26 | Serial.print("[WSc] get text:"); 27 | Serial.println((char *)payload); 28 | 29 | // send message to server 30 | // webSocket.sendTXT("message here"); 31 | break; 32 | case WStype_BIN: 33 | // send data to server 34 | // webSocket.sendBIN(payload, length); 35 | break; 36 | case WStype_ERROR: 37 | case WStype_FRAGMENT_TEXT_START: 38 | case WStype_FRAGMENT_BIN_START: 39 | case WStype_FRAGMENT: 40 | case WStype_FRAGMENT_FIN: 41 | break; 42 | } 43 | } 44 | 45 | void setup() { 46 | Serial.begin(115200); 47 | 48 | while (!Serial) { 49 | ; // wait for serial port to connect. Needed for native USB port only 50 | } 51 | 52 | Serial.println(); 53 | Serial.println(); 54 | Serial.println(); 55 | 56 | for (uint8_t t = 4; t > 0; t--) { 57 | Serial.println("[SETUP] BOOT WAIT ..."); 58 | Serial.flush(); 59 | delay(1000); 60 | } 61 | 62 | // check for the WiFi module: 63 | if (WiFi.status() == WL_NO_MODULE) { 64 | Serial.println("Communication with WiFi module failed!"); 65 | // don't continue 66 | while (true) 67 | ; 68 | } 69 | 70 | String fv = WiFi.firmwareVersion(); 71 | if (fv < WIFI_FIRMWARE_LATEST_VERSION) { 72 | Serial.println("Please upgrade the firmware"); 73 | } 74 | 75 | Serial.println("[Wifi]: Connecting"); 76 | 77 | int status = WL_IDLE_STATUS; 78 | 79 | // attempt to connect to WiFi network: 80 | while (status != WL_CONNECTED) { 81 | Serial.print("[Wifi]: Attempting to connect to SSID: "); 82 | Serial.println(WIFI_SSID); 83 | 84 | // Connect to WPA/WPA2 network. Change this line if using open or WEP network: 85 | status = WiFi.begin(WIFI_SSID, WIFI_PASS); 86 | 87 | delay(1000); 88 | } 89 | 90 | Serial.println("Connected!"); 91 | 92 | // print your board's IP address: 93 | IPAddress ip = WiFi.localIP(); 94 | Serial.print("IP Address: "); 95 | Serial.println(ip); 96 | 97 | // server address, port and URL 98 | webSocket.begin("192.168.0.123", 8011); 99 | 100 | // event handler 101 | webSocket.onEvent(webSocketEvent); 102 | 103 | // try ever 5000 again if connection has failed 104 | webSocket.setReconnectInterval(5000); 105 | } 106 | 107 | void loop() { 108 | webSocket.loop(); 109 | } -------------------------------------------------------------------------------- /examples/arduino_wifinina/arduino_wifinina.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WIFI_SSID "" 7 | #define WIFI_PASS "" 8 | 9 | int status = WL_IDLE_STATUS; 10 | WiFiClient client; 11 | WebSocketsClient webSocket; 12 | 13 | void webSocketEvent(WStype_t type, uint8_t *payload, size_t length) { 14 | 15 | switch (type) { 16 | case WStype_DISCONNECTED: 17 | Serial.println("[WSc] Disconnected!"); 18 | break; 19 | case WStype_CONNECTED: 20 | Serial.println("[WSc] Connected!"); 21 | 22 | // send message to server when Connected 23 | webSocket.sendTXT("Connected"); 24 | break; 25 | case WStype_TEXT: 26 | Serial.print("[WSc] get text:"); 27 | Serial.println((char *)payload); 28 | 29 | // send message to server 30 | // webSocket.sendTXT("message here"); 31 | break; 32 | case WStype_BIN: 33 | // send data to server 34 | // webSocket.sendBIN(payload, length); 35 | break; 36 | case WStype_ERROR: 37 | case WStype_FRAGMENT_TEXT_START: 38 | case WStype_FRAGMENT_BIN_START: 39 | case WStype_FRAGMENT: 40 | case WStype_PING: 41 | case WStype_PONG: 42 | case WStype_FRAGMENT_FIN: 43 | break; 44 | } 45 | } 46 | 47 | void setup() { 48 | Serial.begin(115200); 49 | 50 | while (!Serial) { 51 | ; // wait for serial port to connect. Needed for native USB port only 52 | } 53 | 54 | Serial.println(); 55 | Serial.println(); 56 | Serial.println(); 57 | 58 | // check for the WiFi module: 59 | if (WiFi.status() == WL_NO_MODULE) { 60 | Serial.println("Communication with WiFi module failed!"); 61 | // don't continue 62 | while (true); 63 | } 64 | 65 | String fv = WiFi.firmwareVersion(); 66 | if (fv < WIFI_FIRMWARE_LATEST_VERSION) { 67 | Serial.println("Please upgrade the firmware"); 68 | } 69 | 70 | // attempt to connect to WiFi network: 71 | while (status != WL_CONNECTED) { 72 | Serial.print("Attempting to connect to SSID: "); 73 | Serial.println(WIFI_SSID); 74 | // Connect to WPA/WPA2 network. Change this line if using open or WEP network: 75 | status = WiFi.begin(WIFI_SSID, WIFI_PASS); 76 | 77 | // wait 10 seconds for connection: 78 | delay(10000); 79 | } 80 | 81 | Serial.println("Connected to WiFi"); 82 | 83 | // print your board's IP address: 84 | IPAddress ip = WiFi.localIP(); 85 | Serial.print("IP Address: "); 86 | Serial.println(ip); 87 | 88 | // server address, port and URL 89 | webSocket.begin("192.168.0.123", 8011); 90 | 91 | // event handler 92 | webSocket.onEvent(webSocketEvent); 93 | 94 | // try ever 5000 again if connection has failed 95 | webSocket.setReconnectInterval(5000); 96 | } 97 | 98 | void loop() { 99 | webSocket.loop(); 100 | } -------------------------------------------------------------------------------- /examples/avr/WebSocketClientAVR/WebSocketClientAVR.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientAVR.ino 3 | * 4 | * Created on: 10.12.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | 16 | 17 | // Enter a MAC address for your controller below. 18 | // Newer Ethernet shields have a MAC address printed on a sticker on the shield 19 | byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 20 | 21 | // Set the static IP address to use if the DHCP fails to assign 22 | IPAddress ip(192, 168, 0, 177); 23 | 24 | WebSocketsClient webSocket; 25 | 26 | 27 | 28 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 29 | 30 | 31 | switch(type) { 32 | case WStype_DISCONNECTED: 33 | Serial.println("[WSc] Disconnected!\n"); 34 | break; 35 | case WStype_CONNECTED: 36 | { 37 | Serial.print("[WSc] Connected to url: "); 38 | Serial.println((char *)payload); 39 | // send message to server when Connected 40 | webSocket.sendTXT("Connected"); 41 | } 42 | break; 43 | case WStype_TEXT: 44 | Serial.print("[WSc] get text: "); 45 | Serial.println((char *)payload); 46 | // send message to server 47 | // webSocket.sendTXT("message here"); 48 | break; 49 | case WStype_BIN: 50 | Serial.print("[WSc] get binary length: "); 51 | Serial.println(length); 52 | // hexdump(payload, length); 53 | 54 | // send data to server 55 | // webSocket.sendBIN(payload, length); 56 | break; 57 | } 58 | 59 | } 60 | 61 | void setup() 62 | { 63 | // Open serial communications and wait for port to open: 64 | Serial.begin(115200); 65 | while (!Serial) {} 66 | 67 | // start the Ethernet connection: 68 | if (Ethernet.begin(mac) == 0) { 69 | Serial.println("Failed to configure Ethernet using DHCP"); 70 | // no point in carrying on, so do nothing forevermore: 71 | // try to congifure using IP address instead of DHCP: 72 | Ethernet.begin(mac, ip); 73 | } 74 | 75 | webSocket.begin("192.168.0.123", 8011); 76 | webSocket.onEvent(webSocketEvent); 77 | 78 | } 79 | 80 | 81 | void loop() 82 | { 83 | webSocket.loop(); 84 | } 85 | -------------------------------------------------------------------------------- /examples/esp32/WebSocketClient/WebSocketClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClient.ino 3 | * 4 | * Created on: 24.05.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | WiFiMulti WiFiMulti; 18 | WebSocketsClient webSocket; 19 | 20 | #define USE_SERIAL Serial1 21 | 22 | void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { 23 | const uint8_t* src = (const uint8_t*) mem; 24 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 25 | for(uint32_t i = 0; i < len; i++) { 26 | if(i % cols == 0) { 27 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 28 | } 29 | USE_SERIAL.printf("%02X ", *src); 30 | src++; 31 | } 32 | USE_SERIAL.printf("\n"); 33 | } 34 | 35 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 36 | 37 | switch(type) { 38 | case WStype_DISCONNECTED: 39 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 40 | break; 41 | case WStype_CONNECTED: 42 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 43 | 44 | // send message to server when Connected 45 | webSocket.sendTXT("Connected"); 46 | break; 47 | case WStype_TEXT: 48 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 49 | 50 | // send message to server 51 | // webSocket.sendTXT("message here"); 52 | break; 53 | case WStype_BIN: 54 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 55 | hexdump(payload, length); 56 | 57 | // send data to server 58 | // webSocket.sendBIN(payload, length); 59 | break; 60 | case WStype_ERROR: 61 | case WStype_FRAGMENT_TEXT_START: 62 | case WStype_FRAGMENT_BIN_START: 63 | case WStype_FRAGMENT: 64 | case WStype_FRAGMENT_FIN: 65 | break; 66 | } 67 | 68 | } 69 | 70 | void setup() { 71 | // USE_SERIAL.begin(921600); 72 | USE_SERIAL.begin(115200); 73 | 74 | //Serial.setDebugOutput(true); 75 | USE_SERIAL.setDebugOutput(true); 76 | 77 | USE_SERIAL.println(); 78 | USE_SERIAL.println(); 79 | USE_SERIAL.println(); 80 | 81 | for(uint8_t t = 4; t > 0; t--) { 82 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 83 | USE_SERIAL.flush(); 84 | delay(1000); 85 | } 86 | 87 | WiFiMulti.addAP("SSID", "passpasspass"); 88 | 89 | //WiFi.disconnect(); 90 | while(WiFiMulti.run() != WL_CONNECTED) { 91 | delay(100); 92 | } 93 | 94 | // server address, port and URL 95 | webSocket.begin("192.168.0.123", 81, "/"); 96 | 97 | // event handler 98 | webSocket.onEvent(webSocketEvent); 99 | 100 | // use HTTP Basic Authorization this is optional remove if not needed 101 | webSocket.setAuthorization("user", "Password"); 102 | 103 | // try ever 5000 again if connection has failed 104 | webSocket.setReconnectInterval(5000); 105 | 106 | } 107 | 108 | void loop() { 109 | webSocket.loop(); 110 | } 111 | -------------------------------------------------------------------------------- /examples/esp32/WebSocketClientSSL/WebSocketClientSSL.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSSL.ino 3 | * 4 | * Created on: 10.12.2015 5 | * 6 | * note SSL is only possible with the ESP8266 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | WiFiMulti WiFiMulti; 20 | WebSocketsClient webSocket; 21 | 22 | #define USE_SERIAL Serial1 23 | 24 | void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { 25 | const uint8_t* src = (const uint8_t*) mem; 26 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 27 | for(uint32_t i = 0; i < len; i++) { 28 | if(i % cols == 0) { 29 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 30 | } 31 | USE_SERIAL.printf("%02X ", *src); 32 | src++; 33 | } 34 | USE_SERIAL.printf("\n"); 35 | } 36 | 37 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 38 | 39 | 40 | switch(type) { 41 | case WStype_DISCONNECTED: 42 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 43 | break; 44 | case WStype_CONNECTED: 45 | { 46 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 47 | 48 | // send message to server when Connected 49 | webSocket.sendTXT("Connected"); 50 | } 51 | break; 52 | case WStype_TEXT: 53 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 54 | 55 | // send message to server 56 | // webSocket.sendTXT("message here"); 57 | break; 58 | case WStype_BIN: 59 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 60 | hexdump(payload, length); 61 | 62 | // send data to server 63 | // webSocket.sendBIN(payload, length); 64 | break; 65 | case WStype_ERROR: 66 | case WStype_FRAGMENT_TEXT_START: 67 | case WStype_FRAGMENT_BIN_START: 68 | case WStype_FRAGMENT: 69 | case WStype_FRAGMENT_FIN: 70 | break; 71 | } 72 | 73 | } 74 | 75 | void setup() { 76 | // USE_SERIAL.begin(921600); 77 | USE_SERIAL.begin(115200); 78 | 79 | //Serial.setDebugOutput(true); 80 | USE_SERIAL.setDebugOutput(true); 81 | 82 | USE_SERIAL.println(); 83 | USE_SERIAL.println(); 84 | USE_SERIAL.println(); 85 | 86 | for(uint8_t t = 4; t > 0; t--) { 87 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 88 | USE_SERIAL.flush(); 89 | delay(1000); 90 | } 91 | 92 | WiFiMulti.addAP("SSID", "passpasspass"); 93 | 94 | //WiFi.disconnect(); 95 | while(WiFiMulti.run() != WL_CONNECTED) { 96 | delay(100); 97 | } 98 | 99 | webSocket.beginSSL("192.168.0.123", 81); 100 | webSocket.onEvent(webSocketEvent); 101 | 102 | } 103 | 104 | void loop() { 105 | webSocket.loop(); 106 | } 107 | -------------------------------------------------------------------------------- /examples/esp32/WebSocketClientSSLBundle/WebSocketClientSSLBundle.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * main.cpp 3 | * 4 | * Created on: 15.06.2024 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | // Use the incbin library to embedd the cert binary 15 | // extern const uint8_t rootca_crt_bundle_start[] asm( 16 | // "_binary_data_cert_x509_crt_bundle_bin_start"); 17 | 18 | WiFiMulti wifiMulti; 19 | WebSocketsClient webSocket; 20 | 21 | #define USE_SERIAL Serial 22 | 23 | void setClock() { 24 | configTime(0, 0, "pool.ntp.org", "time.nist.gov"); 25 | 26 | USE_SERIAL.print(F("Waiting for NTP time sync: ")); 27 | time_t nowSecs = time(nullptr); 28 | while(nowSecs < 8 * 3600 * 2) { 29 | delay(500); 30 | USE_SERIAL.print(F(".")); 31 | yield(); 32 | nowSecs = time(nullptr); 33 | } 34 | 35 | USE_SERIAL.println(); 36 | struct tm timeinfo; 37 | gmtime_r(&nowSecs, &timeinfo); 38 | USE_SERIAL.print(F("Current time: ")); 39 | USE_SERIAL.print(asctime(&timeinfo)); 40 | } 41 | 42 | void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) { 43 | const uint8_t * src = (const uint8_t *)mem; 44 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 45 | for(uint32_t i = 0; i < len; i++) { 46 | if(i % cols == 0) { 47 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 48 | } 49 | USE_SERIAL.printf("%02X ", *src); 50 | src++; 51 | } 52 | USE_SERIAL.printf("\n"); 53 | } 54 | 55 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 56 | switch(type) { 57 | case WStype_DISCONNECTED: 58 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 59 | break; 60 | case WStype_CONNECTED: 61 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 62 | 63 | // send message to server when Connected 64 | webSocket.sendTXT("Connected"); 65 | break; 66 | case WStype_TEXT: 67 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 68 | 69 | // send message to server 70 | // webSocket.sendTXT("message here"); 71 | break; 72 | case WStype_BIN: 73 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 74 | hexdump(payload, length); 75 | 76 | // send data to server 77 | // webSocket.sendBIN(payload, length); 78 | break; 79 | case WStype_ERROR: 80 | case WStype_FRAGMENT_TEXT_START: 81 | case WStype_FRAGMENT_BIN_START: 82 | case WStype_FRAGMENT: 83 | case WStype_FRAGMENT_FIN: 84 | break; 85 | } 86 | } 87 | 88 | void setup() { 89 | USE_SERIAL.begin(115200); 90 | 91 | USE_SERIAL.setDebugOutput(true); 92 | 93 | USE_SERIAL.println(); 94 | USE_SERIAL.println(); 95 | USE_SERIAL.println(); 96 | 97 | for(uint8_t t = 4; t > 0; t--) { 98 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 99 | USE_SERIAL.flush(); 100 | delay(1000); 101 | } 102 | 103 | wifiMulti.addAP("SSID", "WIFI_PASSPHRASE"); 104 | 105 | // WiFi.disconnect(); 106 | while(wifiMulti.run() != WL_CONNECTED) { 107 | delay(100); 108 | } 109 | 110 | setClock(); 111 | 112 | // server address, port and URL. This server can be flakey. 113 | // Expected response: Request served by 0123456789abcdef 114 | // webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, ""); 115 | // ESP32 3.0.4 or higher needs the size of the bundle 116 | // webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, sizeof(rootca_crt_bundle_start), ""); 117 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4) 118 | webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", NULL, 0, ""); 119 | #else 120 | webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", NULL, ""); 121 | #endif 122 | 123 | // event handler 124 | webSocket.onEvent(webSocketEvent); 125 | 126 | // use HTTP Basic Authorization this is optional enable if needed 127 | // webSocket.setAuthorization("user", "Password"); 128 | 129 | // try ever 5000 again if connection has failed 130 | webSocket.setReconnectInterval(5000); 131 | } 132 | 133 | void loop() { 134 | webSocket.loop(); 135 | } 136 | -------------------------------------------------------------------------------- /examples/esp32/WebSocketClientSocketIOack/WebSocketClientSocketIOack.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSocketIOack.ino 3 | * 4 | * Created on: 20.07.2019 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | WiFiMulti WiFiMulti; 20 | SocketIOclient socketIO; 21 | 22 | #define USE_SERIAL Serial 23 | 24 | 25 | void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { 26 | switch(type) { 27 | case sIOtype_DISCONNECT: 28 | USE_SERIAL.printf("[IOc] Disconnected!\n"); 29 | break; 30 | case sIOtype_CONNECT: 31 | USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload); 32 | 33 | // join default namespace (no auto join in Socket.IO V3) 34 | socketIO.send(sIOtype_CONNECT, "/"); 35 | break; 36 | case sIOtype_EVENT: 37 | { 38 | char * sptr = NULL; 39 | int id = strtol((char *)payload, &sptr, 10); 40 | USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id); 41 | if(id) { 42 | payload = (uint8_t *)sptr; 43 | } 44 | DynamicJsonDocument doc(1024); 45 | DeserializationError error = deserializeJson(doc, payload, length); 46 | if(error) { 47 | USE_SERIAL.print(F("deserializeJson() failed: ")); 48 | USE_SERIAL.println(error.c_str()); 49 | return; 50 | } 51 | 52 | String eventName = doc[0]; 53 | USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str()); 54 | 55 | // Message Includes a ID for a ACK (callback) 56 | if(id) { 57 | // create JSON message for Socket.IO (ack) 58 | DynamicJsonDocument docOut(1024); 59 | JsonArray array = docOut.to(); 60 | 61 | // add payload (parameters) for the ack (callback function) 62 | JsonObject param1 = array.createNestedObject(); 63 | param1["now"] = millis(); 64 | 65 | // JSON to String (serializion) 66 | String output; 67 | output += id; 68 | serializeJson(docOut, output); 69 | 70 | // Send event 71 | socketIO.send(sIOtype_ACK, output); 72 | } 73 | } 74 | break; 75 | case sIOtype_ACK: 76 | USE_SERIAL.printf("[IOc] get ack: %u\n", length); 77 | break; 78 | case sIOtype_ERROR: 79 | USE_SERIAL.printf("[IOc] get error: %u\n", length); 80 | break; 81 | case sIOtype_BINARY_EVENT: 82 | USE_SERIAL.printf("[IOc] get binary: %u\n", length); 83 | break; 84 | case sIOtype_BINARY_ACK: 85 | USE_SERIAL.printf("[IOc] get binary ack: %u\n", length); 86 | break; 87 | } 88 | } 89 | 90 | void setup() { 91 | //USE_SERIAL.begin(921600); 92 | USE_SERIAL.begin(115200); 93 | 94 | //Serial.setDebugOutput(true); 95 | USE_SERIAL.setDebugOutput(true); 96 | 97 | USE_SERIAL.println(); 98 | USE_SERIAL.println(); 99 | USE_SERIAL.println(); 100 | 101 | for(uint8_t t = 4; t > 0; t--) { 102 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 103 | USE_SERIAL.flush(); 104 | delay(1000); 105 | } 106 | 107 | WiFiMulti.addAP("SSID", "passpasspass"); 108 | 109 | //WiFi.disconnect(); 110 | while(WiFiMulti.run() != WL_CONNECTED) { 111 | delay(100); 112 | } 113 | 114 | String ip = WiFi.localIP().toString(); 115 | USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str()); 116 | 117 | // server address, port and URL 118 | socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4"); 119 | 120 | // event handler 121 | socketIO.onEvent(socketIOEvent); 122 | } 123 | 124 | unsigned long messageTimestamp = 0; 125 | void loop() { 126 | socketIO.loop(); 127 | 128 | uint64_t now = millis(); 129 | 130 | if(now - messageTimestamp > 2000) { 131 | messageTimestamp = now; 132 | 133 | // create JSON message for Socket.IO (event) 134 | DynamicJsonDocument doc(1024); 135 | JsonArray array = doc.to(); 136 | 137 | // add event name 138 | // Hint: socket.on('event_name', .... 139 | array.add("event_name"); 140 | 141 | // add payload (parameters) for the event 142 | JsonObject param1 = array.createNestedObject(); 143 | param1["now"] = (uint32_t) now; 144 | 145 | // JSON to String (serialization) 146 | String output; 147 | serializeJson(doc, output); 148 | 149 | // Send event 150 | socketIO.sendEVENT(output); 151 | 152 | // Print JSON for debugging 153 | USE_SERIAL.println(output); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /examples/esp32/WebSocketServer/WebSocketServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServer.ino 3 | * 4 | * Created on: 22.05.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | WiFiMulti WiFiMulti; 17 | WebSocketsServer webSocket = WebSocketsServer(81); 18 | 19 | #define USE_SERIAL Serial1 20 | 21 | void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { 22 | const uint8_t* src = (const uint8_t*) mem; 23 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 24 | for(uint32_t i = 0; i < len; i++) { 25 | if(i % cols == 0) { 26 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 27 | } 28 | USE_SERIAL.printf("%02X ", *src); 29 | src++; 30 | } 31 | USE_SERIAL.printf("\n"); 32 | } 33 | 34 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 35 | 36 | switch(type) { 37 | case WStype_DISCONNECTED: 38 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 39 | break; 40 | case WStype_CONNECTED: 41 | { 42 | IPAddress ip = webSocket.remoteIP(num); 43 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 44 | 45 | // send message to client 46 | webSocket.sendTXT(num, "Connected"); 47 | } 48 | break; 49 | case WStype_TEXT: 50 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 51 | 52 | // send message to client 53 | // webSocket.sendTXT(num, "message here"); 54 | 55 | // send data to all connected clients 56 | // webSocket.broadcastTXT("message here"); 57 | break; 58 | case WStype_BIN: 59 | USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); 60 | hexdump(payload, length); 61 | 62 | // send message to client 63 | // webSocket.sendBIN(num, payload, length); 64 | break; 65 | case WStype_ERROR: 66 | case WStype_FRAGMENT_TEXT_START: 67 | case WStype_FRAGMENT_BIN_START: 68 | case WStype_FRAGMENT: 69 | case WStype_FRAGMENT_FIN: 70 | break; 71 | } 72 | 73 | } 74 | 75 | void setup() { 76 | // USE_SERIAL.begin(921600); 77 | USE_SERIAL.begin(115200); 78 | 79 | //Serial.setDebugOutput(true); 80 | USE_SERIAL.setDebugOutput(true); 81 | 82 | USE_SERIAL.println(); 83 | USE_SERIAL.println(); 84 | USE_SERIAL.println(); 85 | 86 | for(uint8_t t = 4; t > 0; t--) { 87 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 88 | USE_SERIAL.flush(); 89 | delay(1000); 90 | } 91 | 92 | WiFiMulti.addAP("SSID", "passpasspass"); 93 | 94 | while(WiFiMulti.run() != WL_CONNECTED) { 95 | delay(100); 96 | } 97 | 98 | webSocket.begin(); 99 | webSocket.onEvent(webSocketEvent); 100 | } 101 | 102 | void loop() { 103 | webSocket.loop(); 104 | } 105 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | *secret* 7 | !*secrets.hpp.template 8 | *x509_crt_bundle.bin -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/cmn_crt_authorities.csv: -------------------------------------------------------------------------------- 1 | Owner,Common Name or Certificate Name 2 | Amazon Trust Services,Amazon Root CA 1 3 | Amazon Trust Services,Amazon Root CA 2 4 | Amazon Trust Services,Amazon Root CA 3 5 | Amazon Trust Services,Amazon Root CA 4 6 | Amazon Trust Services,Starfield Services Root Certificate Authority - G2 7 | DigiCert,Baltimore CyberTrust Root 8 | DigiCert,Cybertrust Global Root 9 | DigiCert,DigiCert Assured ID Root CA 10 | DigiCert,DigiCert Assured ID Root G2 11 | DigiCert,DigiCert Assured ID Root G3 12 | DigiCert,DigiCert Global Root CA 13 | DigiCert,DigiCert Global Root G2 14 | DigiCert,DigiCert Global Root G3 15 | DigiCert,DigiCert High Assurance EV Root CA 16 | DigiCert,DigiCert Trusted Root G4 17 | GlobalSign,GlobalSign ECC Root CA - R5 18 | GlobalSign,GlobalSign Root CA - R3 19 | GlobalSign,GlobalSign Root CA - R6 20 | GlobalSign,GlobalSign Root CA 21 | GoDaddy,Go Daddy Class 2 CA 22 | GoDaddy,Go Daddy Root Certificate Authority - G2 23 | GoDaddy,Starfield Class 2 CA 24 | GoDaddy,Starfield Root Certificate Authority - G2 25 | Google Trust Services LLC (GTS),GlobalSign ECC Root CA - R4 26 | Google Trust Services LLC (GTS),GlobalSign Root CA - R2 27 | Google Trust Services LLC (GTS),GTS Root R1 28 | Google Trust Services LLC (GTS),GTS Root R2 29 | Google Trust Services LLC (GTS),GTS Root R3 30 | Google Trust Services LLC (GTS),GTS Root R4 31 | "IdenTrust Services, LLC",DST Root CA X3 32 | "IdenTrust Services, LLC",IdenTrust Commercial Root CA 1 33 | "IdenTrust Services, LLC",IdenTrust Public Sector Root CA 1 34 | Sectigo,Comodo AAA Services root 35 | Sectigo,COMODO Certification Authority 36 | Sectigo,COMODO ECC Certification Authority 37 | Sectigo,COMODO RSA Certification Authority 38 | Sectigo,USERTrust ECC Certification Authority 39 | Sectigo,USERTrust RSA Certification Authority 40 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/gen_crt_bundle.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ESP32 x509 certificate bundle generation utility 4 | # 5 | # Converts PEM and DER certificates to a custom bundle format which stores just the 6 | # subject name and public key to reduce space 7 | # 8 | # The bundle will have the format: number of certificates; crt 1 subject name length; crt 1 public key length; 9 | # crt 1 subject name; crt 1 public key; crt 2... 10 | # 11 | # Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 12 | # 13 | # Licensed under the Apache License, Version 2.0 (the "License"); 14 | # you may not use this file except in compliance with the License. 15 | # You may obtain a copy of the License at 16 | # 17 | # http:#www.apache.org/licenses/LICENSE-2.0 18 | # 19 | # Unless required by applicable law or agreed to in writing, software 20 | # distributed under the License is distributed on an "AS IS" BASIS, 21 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | # See the License for the specific language governing permissions and 23 | # limitations under the License. 24 | 25 | from __future__ import with_statement 26 | 27 | import argparse 28 | import csv 29 | import os 30 | import re 31 | import struct 32 | import sys 33 | from io import open 34 | 35 | try: 36 | from cryptography import x509 37 | from cryptography.hazmat.backends import default_backend 38 | from cryptography.hazmat.primitives import serialization 39 | except ImportError: 40 | print('The cryptography package is not installed.' 41 | 'Please refer to the Get Started section of the ESP-IDF Programming Guide for ' 42 | 'setting up the required packages.') 43 | raise 44 | 45 | ca_bundle_bin_file = 'x509_crt_bundle' 46 | 47 | quiet = False 48 | 49 | 50 | def status(msg): 51 | """ Print status message to stderr """ 52 | if not quiet: 53 | critical(msg) 54 | 55 | 56 | def critical(msg): 57 | """ Print critical message to stderr """ 58 | sys.stderr.write('gen_crt_bundle.py: ') 59 | sys.stderr.write(msg) 60 | sys.stderr.write('\n') 61 | 62 | 63 | class CertificateBundle: 64 | def __init__(self): 65 | self.certificates = [] 66 | self.compressed_crts = [] 67 | 68 | if os.path.isfile(ca_bundle_bin_file): 69 | os.remove(ca_bundle_bin_file) 70 | 71 | def add_from_path(self, crts_path): 72 | 73 | found = False 74 | for file_path in os.listdir(crts_path): 75 | found |= self.add_from_file(os.path.join(crts_path, file_path)) 76 | 77 | if found is False: 78 | raise InputError('No valid x509 certificates found in %s' % crts_path) 79 | 80 | def add_from_file(self, file_path): 81 | try: 82 | if file_path.endswith('.pem'): 83 | status('Parsing certificates from %s' % file_path) 84 | with open(file_path, 'r', encoding='utf-8') as f: 85 | crt_str = f.read() 86 | self.add_from_pem(crt_str) 87 | return True 88 | 89 | elif file_path.endswith('.der'): 90 | status('Parsing certificates from %s' % file_path) 91 | with open(file_path, 'rb') as f: 92 | crt_str = f.read() 93 | self.add_from_der(crt_str) 94 | return True 95 | 96 | except ValueError: 97 | critical('Invalid certificate in %s' % file_path) 98 | raise InputError('Invalid certificate') 99 | 100 | return False 101 | 102 | def add_from_pem(self, crt_str): 103 | """ A single PEM file may have multiple certificates """ 104 | 105 | crt = '' 106 | count = 0 107 | start = False 108 | 109 | for strg in crt_str.splitlines(True): 110 | if strg == '-----BEGIN CERTIFICATE-----\n' and start is False: 111 | crt = '' 112 | start = True 113 | elif strg == '-----END CERTIFICATE-----\n' and start is True: 114 | crt += strg + '\n' 115 | start = False 116 | self.certificates.append(x509.load_pem_x509_certificate(crt.encode(), default_backend())) 117 | count += 1 118 | if start is True: 119 | crt += strg 120 | 121 | if(count == 0): 122 | raise InputError('No certificate found') 123 | 124 | status('Successfully added %d certificates' % count) 125 | 126 | def add_from_der(self, crt_str): 127 | self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend())) 128 | status('Successfully added 1 certificate') 129 | 130 | def create_bundle(self): 131 | # Sort certificates in order to do binary search when looking up certificates 132 | self.certificates = sorted(self.certificates, key=lambda cert: cert.subject.public_bytes(default_backend())) 133 | 134 | bundle = struct.pack('>H', len(self.certificates)) 135 | 136 | for crt in self.certificates: 137 | """ Read the public key as DER format """ 138 | pub_key = crt.public_key() 139 | pub_key_der = pub_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo) 140 | 141 | """ Read the subject name as DER format """ 142 | sub_name_der = crt.subject.public_bytes(default_backend()) 143 | 144 | name_len = len(sub_name_der) 145 | key_len = len(pub_key_der) 146 | len_data = struct.pack('>HH', name_len, key_len) 147 | 148 | bundle += len_data 149 | bundle += sub_name_der 150 | bundle += pub_key_der 151 | 152 | return bundle 153 | 154 | def add_with_filter(self, crts_path, filter_path): 155 | 156 | filter_set = set() 157 | with open(filter_path, 'r', encoding='utf-8') as f: 158 | csv_reader = csv.reader(f, delimiter=',') 159 | 160 | # Skip header 161 | next(csv_reader) 162 | for row in csv_reader: 163 | filter_set.add(row[1]) 164 | 165 | status('Parsing certificates from %s' % crts_path) 166 | crt_str = [] 167 | with open(crts_path, 'r', encoding='utf-8') as f: 168 | crt_str = f.read() 169 | 170 | # Split all certs into a list of (name, certificate string) tuples 171 | pem_crts = re.findall(r'(^.+?)\n(=+\n[\s\S]+?END CERTIFICATE-----\n)', crt_str, re.MULTILINE) 172 | 173 | filtered_crts = '' 174 | for name, crt in pem_crts: 175 | if name in filter_set: 176 | filtered_crts += crt 177 | 178 | self.add_from_pem(filtered_crts) 179 | 180 | 181 | class InputError(RuntimeError): 182 | def __init__(self, e): 183 | super(InputError, self).__init__(e) 184 | 185 | 186 | def main(): 187 | global quiet 188 | 189 | parser = argparse.ArgumentParser(description='ESP-IDF x509 certificate bundle utility') 190 | 191 | parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') 192 | parser.add_argument('--input', '-i', nargs='+', required=True, 193 | help='Paths to the custom certificate folders or files to parse, parses all .pem or .der files') 194 | parser.add_argument('--filter', '-f', help='Path to CSV-file where the second columns contains the name of the certificates \ 195 | that should be included from cacrt_all.pem') 196 | 197 | args = parser.parse_args() 198 | 199 | quiet = args.quiet 200 | 201 | bundle = CertificateBundle() 202 | 203 | for path in args.input: 204 | if os.path.isfile(path): 205 | if os.path.basename(path) == 'cacrt_all.pem' and args.filter: 206 | bundle.add_with_filter(path, args.filter) 207 | else: 208 | bundle.add_from_file(path) 209 | elif os.path.isdir(path): 210 | bundle.add_from_path(path) 211 | else: 212 | raise InputError('Invalid --input=%s, is neither file nor folder' % args.input) 213 | 214 | status('Successfully added %d certificates in total' % len(bundle.certificates)) 215 | 216 | crt_bundle = bundle.create_bundle() 217 | 218 | with open(ca_bundle_bin_file, 'wb') as f: 219 | f.write(crt_bundle) 220 | 221 | 222 | if __name__ == '__main__': 223 | try: 224 | main() 225 | except InputError as e: 226 | print(e) 227 | sys.exit(2) 228 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32dev] 12 | platform = espressif32 13 | board = esp32dev 14 | framework = arduino 15 | monitor_speed = 115200 16 | upload_speed = 921600 17 | build_flags = 18 | -DCORE_DEBUG_LEVEL=5 19 | lib_deps = ../../../src 20 | 21 | extra_scripts = 22 | pre:run_gen_script.py 23 | 24 | board_build.embed_txtfiles = 25 | data/cert/x509_crt_bundle.bin 26 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/readme.md: -------------------------------------------------------------------------------- 1 | This is a PlatformIO project that uses a modified WiFiClientSecure library (in `lib`) to 2 | implement proper SSL support using root certificates as discussed 3 | [here](https://github.com/espressif/arduino-esp32/issues/3646#issuecomment-648292677) 4 | 5 | It is based on the work by [meltdonw03](https://github.com/meltdown03) in that thread, and the 6 | [BasicHttpsClient example](https://github.com/espressif/arduino-esp32/blob/1.0.4/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino) from the arduino-esp32 project. 7 | 8 | Just copy `include/secrets.hpp.template` to `include/secrets.hpp` and fill in your WiFi details. 9 | Then it should be pretty much ready to go. The local WiFiClientSecure library should take priority. 10 | Debug is set to verbose, so you'll see a lot of noise, but there should also be this readme on success :) 11 | 12 | To get a current CA cert bundle download it from [curl's website](https://curl.se/docs/caextract.html). -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/run_gen_script.py: -------------------------------------------------------------------------------- 1 | Import("env") 2 | 3 | env.Execute("$PYTHONEXE -m pip install cryptography") 4 | env.Execute("$PYTHONEXE gen_crt_bundle.py --input cacrt_all.pem") 5 | env.Execute("mkdir -p data/cert") 6 | env.Execute("mv -f x509_crt_bundle data/cert/x509_crt_bundle.bin") 7 | -------------------------------------------------------------------------------- /examples/esp32_pio/WebSocketClientSSLBundle/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * main.cpp 3 | * 4 | * Created on: 15.06.2024 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | extern const uint8_t rootca_crt_bundle_start[] asm( 15 | "_binary_data_cert_x509_crt_bundle_bin_start"); 16 | 17 | WiFiMulti wifiMulti; 18 | WebSocketsClient webSocket; 19 | 20 | #define USE_SERIAL Serial 21 | 22 | void setClock() { 23 | configTime(0, 0, "pool.ntp.org", "time.nist.gov"); 24 | 25 | USE_SERIAL.print(F("Waiting for NTP time sync: ")); 26 | time_t nowSecs = time(nullptr); 27 | while(nowSecs < 8 * 3600 * 2) { 28 | delay(500); 29 | USE_SERIAL.print(F(".")); 30 | yield(); 31 | nowSecs = time(nullptr); 32 | } 33 | 34 | USE_SERIAL.println(); 35 | struct tm timeinfo; 36 | gmtime_r(&nowSecs, &timeinfo); 37 | USE_SERIAL.print(F("Current time: ")); 38 | USE_SERIAL.print(asctime(&timeinfo)); 39 | } 40 | 41 | void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) { 42 | const uint8_t * src = (const uint8_t *)mem; 43 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 44 | for(uint32_t i = 0; i < len; i++) { 45 | if(i % cols == 0) { 46 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 47 | } 48 | USE_SERIAL.printf("%02X ", *src); 49 | src++; 50 | } 51 | USE_SERIAL.printf("\n"); 52 | } 53 | 54 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 55 | switch(type) { 56 | case WStype_DISCONNECTED: 57 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 58 | break; 59 | case WStype_CONNECTED: 60 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 61 | 62 | // send message to server when Connected 63 | webSocket.sendTXT("Connected"); 64 | break; 65 | case WStype_TEXT: 66 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 67 | 68 | // send message to server 69 | // webSocket.sendTXT("message here"); 70 | break; 71 | case WStype_BIN: 72 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 73 | hexdump(payload, length); 74 | 75 | // send data to server 76 | // webSocket.sendBIN(payload, length); 77 | break; 78 | case WStype_ERROR: 79 | case WStype_FRAGMENT_TEXT_START: 80 | case WStype_FRAGMENT_BIN_START: 81 | case WStype_FRAGMENT: 82 | case WStype_FRAGMENT_FIN: 83 | break; 84 | } 85 | } 86 | 87 | void setup() { 88 | USE_SERIAL.begin(115200); 89 | 90 | USE_SERIAL.setDebugOutput(true); 91 | 92 | USE_SERIAL.println(); 93 | USE_SERIAL.println(); 94 | USE_SERIAL.println(); 95 | 96 | for(uint8_t t = 4; t > 0; t--) { 97 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 98 | USE_SERIAL.flush(); 99 | delay(1000); 100 | } 101 | 102 | wifiMulti.addAP("SSID", "WIFI_PASSPHRASE"); 103 | 104 | // WiFi.disconnect(); 105 | while(wifiMulti.run() != WL_CONNECTED) { 106 | delay(100); 107 | } 108 | 109 | setClock(); 110 | 111 | // server address, port and URL. This server can be flakey. 112 | // Expected response: Request served by 0123456789abcdef 113 | webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, ""); 114 | 115 | // event handler 116 | webSocket.onEvent(webSocketEvent); 117 | 118 | // use HTTP Basic Authorization this is optional enable if needed 119 | // webSocket.setAuthorization("user", "Password"); 120 | 121 | // try ever 5000 again if connection has failed 122 | webSocket.setReconnectInterval(5000); 123 | } 124 | 125 | void loop() { 126 | webSocket.loop(); 127 | } 128 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClient/WebSocketClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClient.ino 3 | * 4 | * Created on: 24.05.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | ESP8266WiFiMulti WiFiMulti; 18 | WebSocketsClient webSocket; 19 | 20 | #define USE_SERIAL Serial1 21 | 22 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 23 | 24 | switch(type) { 25 | case WStype_DISCONNECTED: 26 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 27 | break; 28 | case WStype_CONNECTED: { 29 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 30 | 31 | // send message to server when Connected 32 | webSocket.sendTXT("Connected"); 33 | } 34 | break; 35 | case WStype_TEXT: 36 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 37 | 38 | // send message to server 39 | // webSocket.sendTXT("message here"); 40 | break; 41 | case WStype_BIN: 42 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 43 | hexdump(payload, length); 44 | 45 | // send data to server 46 | // webSocket.sendBIN(payload, length); 47 | break; 48 | case WStype_PING: 49 | // pong will be send automatically 50 | USE_SERIAL.printf("[WSc] get ping\n"); 51 | break; 52 | case WStype_PONG: 53 | // answer to a ping we send 54 | USE_SERIAL.printf("[WSc] get pong\n"); 55 | break; 56 | } 57 | 58 | } 59 | 60 | void setup() { 61 | // USE_SERIAL.begin(921600); 62 | USE_SERIAL.begin(115200); 63 | 64 | //Serial.setDebugOutput(true); 65 | USE_SERIAL.setDebugOutput(true); 66 | 67 | USE_SERIAL.println(); 68 | USE_SERIAL.println(); 69 | USE_SERIAL.println(); 70 | 71 | for(uint8_t t = 4; t > 0; t--) { 72 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 73 | USE_SERIAL.flush(); 74 | delay(1000); 75 | } 76 | 77 | WiFiMulti.addAP("SSID", "passpasspass"); 78 | 79 | //WiFi.disconnect(); 80 | while(WiFiMulti.run() != WL_CONNECTED) { 81 | delay(100); 82 | } 83 | 84 | // server address, port and URL 85 | webSocket.begin("192.168.0.123", 81, "/"); 86 | 87 | // event handler 88 | webSocket.onEvent(webSocketEvent); 89 | 90 | // use HTTP Basic Authorization this is optional remove if not needed 91 | webSocket.setAuthorization("user", "Password"); 92 | 93 | // try ever 5000 again if connection has failed 94 | webSocket.setReconnectInterval(5000); 95 | 96 | // start heartbeat (optional) 97 | // ping server every 15000 ms 98 | // expect pong from server within 3000 ms 99 | // consider connection disconnected if pong is not received 2 times 100 | webSocket.enableHeartbeat(15000, 3000, 2); 101 | 102 | } 103 | 104 | void loop() { 105 | webSocket.loop(); 106 | } 107 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientOTA/README.md: -------------------------------------------------------------------------------- 1 | ## Minimal example of WebsocketClientOTA and Python server 2 | 3 | Take this as small example, how achieve OTA update on ESP8266 and ESP32. 4 | 5 | Python server was wrote from train so take it only as bare example. 6 | It's working, but it's not mean to run in production. 7 | 8 | 9 | ### Usage: 10 | 11 | Start server: 12 | ```bash 13 | cd python_ota_server 14 | python3 -m venv .venv 15 | source .venv/bin/activate 16 | pip3 install -r requirements.txt 17 | python3 main.py 18 | ``` 19 | 20 | Flash ESP with example sketch and start it. 21 | 22 | Change version inside example sketch to higher and compile it and save it to bin file. 23 | 24 | Rename it to `mydevice-1.0.1-esp8266.bin` and place it inside new folder firmware (server create it). 25 | 26 | When the ESP connect to server, it check if version flashed is equal to fw in firmware folder. If higher FW version is present, 27 | start the flash process. -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientOTA/WebSocketClientOTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientOTA.ino 3 | * 4 | * Created on: 25.10.2021 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #if defined(ESP8266) 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | ESP8266WiFiMulti WiFiMulti; 19 | #elif defined(ESP32) 20 | #include 21 | #include 22 | #include "ESPmDNS.h" 23 | #include 24 | 25 | WiFiMulti WiFiMulti; 26 | #else 27 | #error Unsupported device 28 | #endif 29 | 30 | #include 31 | #include 32 | 33 | 34 | WebSocketsClient webSocket; 35 | 36 | #define USE_SERIAL Serial 37 | 38 | // Variables: 39 | // Settable: 40 | const char *version = "1.0.0"; 41 | const char *name = "mydevice"; 42 | 43 | // Others: 44 | #ifdef ESP8266 45 | const char *chip = "esp8266"; 46 | #endif 47 | #ifdef ESP32 48 | const char *chip = "esp32"; 49 | #endif 50 | 51 | uint32_t maxSketchSpace = 0; 52 | int SketchSize = 0; 53 | bool ws_conn = false; 54 | 55 | 56 | void greetings_(){ 57 | StaticJsonDocument<200> doc; 58 | doc["type"] = "greetings"; 59 | doc["mac"] = WiFi.macAddress().c_str(); 60 | doc["ip"] = WiFi.localIP().toString().c_str(); 61 | doc["version"] = version; 62 | doc["name"] = name; 63 | doc["chip"] = chip; 64 | 65 | char data[200]; 66 | serializeJson(doc, data); 67 | webSocket.sendTXT(data); 68 | } 69 | 70 | void register_(){ 71 | StaticJsonDocument<200> doc; 72 | doc["type"] = "register"; 73 | doc["mac"] = WiFi.macAddress().c_str(); 74 | 75 | char data[200]; 76 | serializeJson(doc, data); 77 | webSocket.sendTXT(data); 78 | ws_conn = true; 79 | } 80 | 81 | typedef void (*CALLBACK_FUNCTION)(JsonDocument &msg); 82 | 83 | typedef struct { 84 | char type[50]; 85 | CALLBACK_FUNCTION func; 86 | } RESPONSES_STRUCT; 87 | 88 | void OTA_RESPONSES(JsonDocument &msg){ 89 | USE_SERIAL.print(F("[WSc] OTA mode: ")); 90 | String val = msg["value"]; 91 | if(val == "go") { 92 | USE_SERIAL.print(F("go\n")); 93 | SketchSize = int(msg["size"]); 94 | maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; 95 | USE_SERIAL.printf("[WSc] Max sketch size: %u\n", maxSketchSpace); 96 | USE_SERIAL.printf("[WSc] Sketch size: %d\n", SketchSize); 97 | USE_SERIAL.setDebugOutput(true); 98 | if (!Update.begin(maxSketchSpace)) { //start with max available size 99 | Update.printError(Serial); 100 | ESP.restart(); 101 | } 102 | } else if (val == "ok") { 103 | USE_SERIAL.print(F("OK\n")); 104 | register_(); 105 | } else { 106 | USE_SERIAL.print(F("unknown value : ")); 107 | USE_SERIAL.print(val); 108 | USE_SERIAL.print(F("\n")); 109 | } 110 | } 111 | 112 | void STA_RESPONSES(JsonDocument &msg){ 113 | // Do something with message 114 | } 115 | 116 | // Count of responses handled by RESPONSES_STRUCT 117 | // increase increase if another response handler is added 118 | const int nrOfResponses = 2; 119 | 120 | RESPONSES_STRUCT responses[nrOfResponses] = { 121 | {"ota", OTA_RESPONSES}, 122 | {"state", STA_RESPONSES}, 123 | }; 124 | 125 | void text(uint8_t * payload, size_t length){ 126 | // Convert message to something usable 127 | char msgch[length]; 128 | for (unsigned int i = 0; i < length; i++) 129 | { 130 | USE_SERIAL.print((char)payload[i]); 131 | msgch[i] = ((char)payload[i]); 132 | } 133 | msgch[length] = '\0'; 134 | 135 | // Parse Json 136 | StaticJsonDocument<200> doc_in; 137 | DeserializationError error = deserializeJson(doc_in, msgch); 138 | 139 | if (error) { 140 | USE_SERIAL.print(F("deserializeJson() failed: ")); 141 | USE_SERIAL.println(error.c_str()); 142 | return; 143 | } 144 | 145 | // Handle each TYPE of message 146 | int b = 0; 147 | 148 | String t = doc_in["type"]; 149 | for( b=0 ; b 0; t--) { 230 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 231 | USE_SERIAL.flush(); 232 | delay(1000); 233 | } 234 | 235 | WiFiMulti.addAP("SSID", "PASS"); 236 | 237 | //WiFi.disconnect(); 238 | while(WiFiMulti.run() != WL_CONNECTED) { 239 | delay(100); 240 | } 241 | 242 | // server address, port and URL 243 | webSocket.begin("10.0.1.5", 8081, "/"); 244 | 245 | // event handler 246 | webSocket.onEvent(webSocketEvent); 247 | 248 | // use HTTP Basic Authorization this is optional remove if not needed 249 | // webSocket.setAuthorization("USER", "PASS"); 250 | 251 | // try ever 5000 again if connection has failed 252 | webSocket.setReconnectInterval(5000); 253 | 254 | // start heartbeat (optional) 255 | // ping server every 15000 ms 256 | // expect pong from server within 3000 ms 257 | // consider connection disconnected if pong is not received 2 times 258 | webSocket.enableHeartbeat(15000, 3000, 2); 259 | 260 | } 261 | 262 | void loop() { 263 | webSocket.loop(); 264 | } 265 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientOTA/python_ota_server/main.py: -------------------------------------------------------------------------------- 1 | """Minimal example of Python websocket server 2 | handling OTA updates for ESP32 amd ESP8266 3 | 4 | Check and upload of firmware works. 5 | Register and state function are jus for example. 6 | """ 7 | # pylint: disable=W0703,E1101 8 | import asyncio 9 | import copy 10 | import json 11 | import logging 12 | import subprocess 13 | import threading 14 | import time 15 | from os import listdir 16 | from os.path import join as join_pth 17 | from pathlib import Path 18 | 19 | import websockets 20 | from packaging import version 21 | 22 | # Logger settings 23 | logging.basicConfig(filename="ws_server.log") 24 | Logger = logging.getLogger('WS-OTA') 25 | Logger.addHandler(logging.StreamHandler()) 26 | Logger.setLevel(logging.INFO) 27 | 28 | # Path to directory with FW 29 | fw_path = join_pth(Path().absolute(), "firmware") 30 | 31 | 32 | def create_path(path: str) -> None: 33 | """Check if path exist or create it""" 34 | Path(path).mkdir(parents=True, exist_ok=True) 35 | 36 | 37 | def shell(command): 38 | """Handle execution of shell commands""" 39 | with subprocess.Popen(command, shell=True, 40 | stdout=subprocess.PIPE, 41 | universal_newlines=True 42 | ) as process: 43 | for stdout_line in iter(process.stdout.readline, ""): 44 | Logger.debug(stdout_line) 45 | process.stdout.close() 46 | return_code = process.wait() 47 | Logger.debug("Shell returned: %s", return_code) 48 | 49 | return process.returncode 50 | return None 51 | 52 | 53 | async def binary_send(websocket, fw_file): 54 | """Read firmware file, divide it to chunks and send them""" 55 | with open(fw_file, "rb") as binaryfile: 56 | 57 | while True: 58 | chunk = binaryfile.read(4096) 59 | if not chunk: 60 | break 61 | try: 62 | await websocket.send(chunk) 63 | except Exception as exception: 64 | Logger.exception(exception) 65 | return False 66 | asyncio.sleep(0.2) 67 | 68 | 69 | def version_checker(name, vdev, vapp): 70 | """Parse and compare FW version""" 71 | 72 | if version.parse(vdev) < version.parse(vapp): 73 | Logger.info("Client(%s) version %s is smaller than %s: Go for update", name, vdev, vapp) 74 | return True 75 | Logger.info("Client(%s) version %s is greater or equal to %s: Not updating", name, vdev, vapp) 76 | return False 77 | 78 | 79 | class WsOtaHandler (threading.Thread): 80 | """Thread handling ota update 81 | 82 | Running ota directly from message would kill WS 83 | as message bus would timeout. 84 | """ 85 | def __init__(self, name, message, websocket): 86 | threading.Thread.__init__(self, daemon=True) 87 | self.name = name 88 | self.msg = message 89 | self.websocket = websocket 90 | 91 | def run(self, ): 92 | try: 93 | asyncio.run(self.start_()) 94 | except Exception as exception: 95 | Logger.exception(exception) 96 | finally: 97 | pass 98 | 99 | async def start_(self): 100 | """Start _ota se asyncio future""" 101 | msg_task = asyncio.ensure_future( 102 | self._ota()) 103 | 104 | done, pending = await asyncio.wait( 105 | [msg_task], 106 | return_when=asyncio.FIRST_COMPLETED, 107 | ) 108 | Logger.info("WS Ota Handler done: %s", done) 109 | for task in pending: 110 | task.cancel() 111 | 112 | async def _ota(self): 113 | """Check for new fw and update or pass""" 114 | device_name = self.msg['name'] 115 | device_chip = self.msg['chip'] 116 | device_version = self.msg['version'] 117 | fw_version = '' 118 | fw_name = '' 119 | fw_device = '' 120 | 121 | for filename in listdir(fw_path): 122 | fw_info = filename.split("-") 123 | fw_device = fw_info[0] 124 | if fw_device == device_name: 125 | fw_version = fw_info[1] 126 | fw_name = filename 127 | break 128 | 129 | if not fw_version: 130 | Logger.info("Client(%s): No fw found!", device_name) 131 | msg = '{"type": "ota", "value":"ok"}' 132 | await self.websocket.send(msg) 133 | return 134 | 135 | if not version_checker(device_name, device_version, fw_version): 136 | return 137 | 138 | fw_file = join_pth(fw_path, fw_name) 139 | if device_chip == 'esp8266' and not fw_file.endswith('.gz'): 140 | # We can compress fw to make it smaller for upload 141 | fw_cpress = fw_file 142 | fw_file = fw_cpress + ".gz" 143 | cpress = f"gzip -9 {fw_cpress}" 144 | cstate = shell(cpress) 145 | if cstate: 146 | Logger.error("Cannot compress firmware: %s", fw_name) 147 | return 148 | 149 | # Get size of fw 150 | size = Path(fw_file).stat().st_size 151 | 152 | # Request ota mode 153 | msg = '{"type": "ota", "value":"go", "size":' + str(size) + '}' 154 | await self.websocket.send(msg) 155 | 156 | # send file by chunks trough websocket 157 | await binary_send(self.websocket, fw_file) 158 | 159 | 160 | async def _register(websocket, message): 161 | mac = message.get('mac') 162 | name = message.get('name') 163 | Logger.info("Client(%s) mac: %s", name, mac) 164 | # Some code 165 | 166 | response = {'type': 'registry', 'state': 'ok'} 167 | await websocket.send(json.dumps(response)) 168 | 169 | 170 | async def _state(websocket, message): 171 | mac = message.get('mac') 172 | name = message.get('name') 173 | Logger.info("Client(%s) mac: %s", name, mac) 174 | # Some code 175 | 176 | response = {'type': 'state', 'state': 'ok'} 177 | await websocket.send(json.dumps(response)) 178 | 179 | 180 | async def _unhandled(websocket, msg): 181 | Logger.info("Unhandled message from device: %s", str(msg)) 182 | response = {'type': 'response', 'state': 'nok'} 183 | await websocket.send(json.dumps(response)) 184 | 185 | 186 | async def _greetings(websocket, message): 187 | WsOtaHandler('thread_ota', copy.deepcopy(message), websocket).start() 188 | 189 | 190 | async def message_received(websocket, message) -> None: 191 | """Handle incoming messages 192 | 193 | Check if message contain json and run waned function 194 | """ 195 | switcher = {"greetings": _greetings, 196 | "register": _register, 197 | "state": _state 198 | } 199 | 200 | if message[0:1] == "{": 201 | try: 202 | msg_json = json.loads(message) 203 | except Exception as exception: 204 | Logger.error(exception) 205 | return 206 | 207 | type_ = msg_json.get('type') 208 | name = msg_json.get('name') 209 | func = switcher.get(type_, _unhandled) 210 | Logger.debug("Client(%s)said: %s", name, type_) 211 | 212 | try: 213 | await func(websocket, msg_json) 214 | except Exception as exception: 215 | Logger.error(exception) 216 | 217 | 218 | # pylint: disable=W0613 219 | async def ws_server(websocket, path) -> None: 220 | """Run in cycle and wait for new messages""" 221 | async for message in websocket: 222 | await message_received(websocket, message) 223 | 224 | 225 | async def main(): 226 | """Server starter 227 | 228 | Normal user can bind only port numbers greater than 1024 229 | """ 230 | async with websockets.serve(ws_server, "10.0.1.5", 8081): 231 | await asyncio.Future() # run forever 232 | 233 | 234 | create_path(fw_path) 235 | asyncio.run(main()) 236 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientOTA/python_ota_server/requirements.txt: -------------------------------------------------------------------------------- 1 | packaging 2 | websockets -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientSSL/WebSocketClientSSL.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSSL.ino 3 | * 4 | * Created on: 10.12.2015 5 | * 6 | * note SSL is only possible with the ESP8266 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | ESP8266WiFiMulti WiFiMulti; 20 | WebSocketsClient webSocket; 21 | 22 | 23 | #define USE_SERIAL Serial1 24 | 25 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 26 | 27 | 28 | switch(type) { 29 | case WStype_DISCONNECTED: 30 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 31 | break; 32 | case WStype_CONNECTED: 33 | { 34 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 35 | 36 | // send message to server when Connected 37 | webSocket.sendTXT("Connected"); 38 | } 39 | break; 40 | case WStype_TEXT: 41 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 42 | 43 | // send message to server 44 | // webSocket.sendTXT("message here"); 45 | break; 46 | case WStype_BIN: 47 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 48 | hexdump(payload, length); 49 | 50 | // send data to server 51 | // webSocket.sendBIN(payload, length); 52 | break; 53 | } 54 | 55 | } 56 | 57 | void setup() { 58 | // USE_SERIAL.begin(921600); 59 | USE_SERIAL.begin(115200); 60 | 61 | //Serial.setDebugOutput(true); 62 | USE_SERIAL.setDebugOutput(true); 63 | 64 | USE_SERIAL.println(); 65 | USE_SERIAL.println(); 66 | USE_SERIAL.println(); 67 | 68 | for(uint8_t t = 4; t > 0; t--) { 69 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 70 | USE_SERIAL.flush(); 71 | delay(1000); 72 | } 73 | 74 | WiFiMulti.addAP("SSID", "passpasspass"); 75 | 76 | //WiFi.disconnect(); 77 | while(WiFiMulti.run() != WL_CONNECTED) { 78 | delay(100); 79 | } 80 | 81 | webSocket.beginSSL("192.168.0.123", 81); 82 | webSocket.onEvent(webSocketEvent); 83 | 84 | } 85 | 86 | void loop() { 87 | webSocket.loop(); 88 | } 89 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientSSLWithCA/WebSocketClientSSLWithCA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSSLWithCA.ino 3 | * 4 | * Created on: 27.10.2019 5 | * 6 | * note SSL is only possible with the ESP8266 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | ESP8266WiFiMulti WiFiMulti; 18 | WebSocketsClient webSocket; 19 | 20 | #define USE_SERIAL Serial1 21 | 22 | 23 | // Can be obtained with: 24 | // openssl s_client -showcerts -connect echo.websocket.org:443 0; t--) { 82 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 83 | USE_SERIAL.flush(); 84 | delay(1000); 85 | } 86 | 87 | WiFiMulti.addAP("SSID", "passpasspass"); 88 | 89 | while(WiFiMulti.run() != WL_CONNECTED) { 90 | delay(100); 91 | } 92 | 93 | //When using BearSSL, client certificate and private key can be set: 94 | //webSocket.setSSLClientCertKey(clientCert, clientPrivateKey); 95 | //clientCert and clientPrivateKey can be of types (const char *, const char *) , or of types (BearSSL::X509List, BearSSL::PrivateKey) 96 | 97 | webSocket.beginSslWithCA("echo.websocket.org", 443, "/", ENDPOINT_CA_CERT); 98 | webSocket.onEvent(webSocketEvent); 99 | } 100 | 101 | void loop() { 102 | webSocket.loop(); 103 | } 104 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientSocketIO/WebSocketClientSocketIO.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSocketIO.ino 3 | * 4 | * Created on: 06.06.2016 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | ESP8266WiFiMulti WiFiMulti; 21 | SocketIOclient socketIO; 22 | 23 | #define USE_SERIAL Serial1 24 | 25 | void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { 26 | switch(type) { 27 | case sIOtype_DISCONNECT: 28 | USE_SERIAL.printf("[IOc] Disconnected!\n"); 29 | break; 30 | case sIOtype_CONNECT: 31 | USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload); 32 | 33 | // join default namespace (no auto join in Socket.IO V3) 34 | socketIO.send(sIOtype_CONNECT, "/"); 35 | break; 36 | case sIOtype_EVENT: 37 | USE_SERIAL.printf("[IOc] get event: %s\n", payload); 38 | break; 39 | case sIOtype_ACK: 40 | USE_SERIAL.printf("[IOc] get ack: %u\n", length); 41 | hexdump(payload, length); 42 | break; 43 | case sIOtype_ERROR: 44 | USE_SERIAL.printf("[IOc] get error: %u\n", length); 45 | hexdump(payload, length); 46 | break; 47 | case sIOtype_BINARY_EVENT: 48 | USE_SERIAL.printf("[IOc] get binary: %u\n", length); 49 | hexdump(payload, length); 50 | break; 51 | case sIOtype_BINARY_ACK: 52 | USE_SERIAL.printf("[IOc] get binary ack: %u\n", length); 53 | hexdump(payload, length); 54 | break; 55 | } 56 | } 57 | 58 | void setup() { 59 | // USE_SERIAL.begin(921600); 60 | USE_SERIAL.begin(115200); 61 | 62 | //Serial.setDebugOutput(true); 63 | USE_SERIAL.setDebugOutput(true); 64 | 65 | USE_SERIAL.println(); 66 | USE_SERIAL.println(); 67 | USE_SERIAL.println(); 68 | 69 | for(uint8_t t = 4; t > 0; t--) { 70 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 71 | USE_SERIAL.flush(); 72 | delay(1000); 73 | } 74 | 75 | // disable AP 76 | if(WiFi.getMode() & WIFI_AP) { 77 | WiFi.softAPdisconnect(true); 78 | } 79 | 80 | WiFiMulti.addAP("SSID", "passpasspass"); 81 | 82 | //WiFi.disconnect(); 83 | while(WiFiMulti.run() != WL_CONNECTED) { 84 | delay(100); 85 | } 86 | 87 | String ip = WiFi.localIP().toString(); 88 | USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str()); 89 | 90 | // server address, port and URL 91 | socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4"); 92 | 93 | // event handler 94 | socketIO.onEvent(socketIOEvent); 95 | } 96 | 97 | unsigned long messageTimestamp = 0; 98 | void loop() { 99 | socketIO.loop(); 100 | 101 | uint64_t now = millis(); 102 | 103 | if(now - messageTimestamp > 2000) { 104 | messageTimestamp = now; 105 | 106 | // creat JSON message for Socket.IO (event) 107 | DynamicJsonDocument doc(1024); 108 | JsonArray array = doc.to(); 109 | 110 | // add evnet name 111 | // Hint: socket.on('event_name', .... 112 | array.add("event_name"); 113 | 114 | // add payload (parameters) for the event 115 | JsonObject param1 = array.createNestedObject(); 116 | param1["now"] = (uint32_t) now; 117 | 118 | // JSON to String (serializion) 119 | String output; 120 | serializeJson(doc, output); 121 | 122 | // Send event 123 | socketIO.sendEVENT(output); 124 | 125 | // Print JSON for debugging 126 | USE_SERIAL.println(output); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientSocketIOack/WebSocketClientSocketIOack.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClientSocketIOack.ino 3 | * 4 | * Created on: 20.07.2019 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | ESP8266WiFiMulti WiFiMulti; 21 | SocketIOclient socketIO; 22 | 23 | #define USE_SERIAL Serial 24 | 25 | 26 | void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { 27 | switch(type) { 28 | case sIOtype_DISCONNECT: 29 | USE_SERIAL.printf("[IOc] Disconnected!\n"); 30 | break; 31 | case sIOtype_CONNECT: 32 | USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload); 33 | 34 | // join default namespace (no auto join in Socket.IO V3) 35 | socketIO.send(sIOtype_CONNECT, "/"); 36 | break; 37 | case sIOtype_EVENT: 38 | { 39 | char * sptr = NULL; 40 | int id = strtol((char *)payload, &sptr, 10); 41 | USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id); 42 | if(id) { 43 | payload = (uint8_t *)sptr; 44 | } 45 | DynamicJsonDocument doc(1024); 46 | DeserializationError error = deserializeJson(doc, payload, length); 47 | if(error) { 48 | USE_SERIAL.print(F("deserializeJson() failed: ")); 49 | USE_SERIAL.println(error.c_str()); 50 | return; 51 | } 52 | 53 | String eventName = doc[0]; 54 | USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str()); 55 | 56 | // Message Includes a ID for a ACK (callback) 57 | if(id) { 58 | // creat JSON message for Socket.IO (ack) 59 | DynamicJsonDocument docOut(1024); 60 | JsonArray array = docOut.to(); 61 | 62 | // add payload (parameters) for the ack (callback function) 63 | JsonObject param1 = array.createNestedObject(); 64 | param1["now"] = millis(); 65 | 66 | // JSON to String (serializion) 67 | String output; 68 | output += id; 69 | serializeJson(docOut, output); 70 | 71 | // Send event 72 | socketIO.send(sIOtype_ACK, output); 73 | } 74 | } 75 | break; 76 | case sIOtype_ACK: 77 | USE_SERIAL.printf("[IOc] get ack: %u\n", length); 78 | hexdump(payload, length); 79 | break; 80 | case sIOtype_ERROR: 81 | USE_SERIAL.printf("[IOc] get error: %u\n", length); 82 | hexdump(payload, length); 83 | break; 84 | case sIOtype_BINARY_EVENT: 85 | USE_SERIAL.printf("[IOc] get binary: %u\n", length); 86 | hexdump(payload, length); 87 | break; 88 | case sIOtype_BINARY_ACK: 89 | USE_SERIAL.printf("[IOc] get binary ack: %u\n", length); 90 | hexdump(payload, length); 91 | break; 92 | } 93 | } 94 | 95 | void setup() { 96 | //USE_SERIAL.begin(921600); 97 | USE_SERIAL.begin(115200); 98 | 99 | //Serial.setDebugOutput(true); 100 | USE_SERIAL.setDebugOutput(true); 101 | 102 | USE_SERIAL.println(); 103 | USE_SERIAL.println(); 104 | USE_SERIAL.println(); 105 | 106 | for(uint8_t t = 4; t > 0; t--) { 107 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 108 | USE_SERIAL.flush(); 109 | delay(1000); 110 | } 111 | 112 | // disable AP 113 | if(WiFi.getMode() & WIFI_AP) { 114 | WiFi.softAPdisconnect(true); 115 | } 116 | 117 | WiFiMulti.addAP("SSID", "passpasspass"); 118 | 119 | //WiFi.disconnect(); 120 | while(WiFiMulti.run() != WL_CONNECTED) { 121 | delay(100); 122 | } 123 | 124 | String ip = WiFi.localIP().toString(); 125 | USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str()); 126 | 127 | // server address, port and URL 128 | socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4"); 129 | 130 | // event handler 131 | socketIO.onEvent(socketIOEvent); 132 | } 133 | 134 | unsigned long messageTimestamp = 0; 135 | void loop() { 136 | socketIO.loop(); 137 | 138 | uint64_t now = millis(); 139 | 140 | if(now - messageTimestamp > 2000) { 141 | messageTimestamp = now; 142 | 143 | // creat JSON message for Socket.IO (event) 144 | DynamicJsonDocument doc(1024); 145 | JsonArray array = doc.to(); 146 | 147 | // add evnet name 148 | // Hint: socket.on('event_name', .... 149 | array.add("event_name"); 150 | 151 | // add payload (parameters) for the event 152 | JsonObject param1 = array.createNestedObject(); 153 | param1["now"] = (uint32_t) now; 154 | 155 | // JSON to String (serializion) 156 | String output; 157 | serializeJson(doc, output); 158 | 159 | // Send event 160 | socketIO.sendEVENT(output); 161 | 162 | // Print JSON for debugging 163 | USE_SERIAL.println(output); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientStomp/WebSocketClientStomp.ino: -------------------------------------------------------------------------------- 1 | /* 2 | WebSocketClientStomp.ino 3 | 4 | Example for connecting and maintining a connection with a STOMP websocket connection. 5 | In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html). 6 | 7 | Created on: 25.09.2017 8 | Author: Martin Becker , Contact: becker@informatik.uni-wuerzburg.de 9 | */ 10 | 11 | // PRE 12 | 13 | #define USE_SERIAL Serial 14 | 15 | 16 | // LIBRARIES 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | 25 | // SETTINGS 26 | 27 | const char* wlan_ssid = "yourssid"; 28 | const char* wlan_password = "somepassword"; 29 | 30 | const char* ws_host = "the.host.net"; 31 | const int ws_port = 80; 32 | 33 | // URL for STOMP endpoint. 34 | // For the default config of Spring's STOMP support, the default URL is "/socketentry/websocket". 35 | const char* stompUrl = "/socketentry/websocket"; // don't forget the leading "/" !!! 36 | 37 | 38 | // VARIABLES 39 | 40 | WebSocketsClient webSocket; 41 | 42 | 43 | // FUNCTIONS 44 | 45 | /** 46 | * STOMP messages need to be NULL-terminated (i.e., \0 or \u0000). 47 | * However, when we send a String or a char[] array without specifying 48 | * a length, the size of the message payload is derived by strlen() internally, 49 | * thus dropping any NULL values appended to the "msg"-String. 50 | * 51 | * To solve this, we first convert the String to a NULL terminated char[] array 52 | * via "c_str" and set the length of the payload to include the NULL value. 53 | */ 54 | void sendMessage(String & msg) { 55 | webSocket.sendTXT(msg.c_str(), msg.length() + 1); 56 | } 57 | 58 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 59 | 60 | switch (type) { 61 | case WStype_DISCONNECTED: 62 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 63 | break; 64 | case WStype_CONNECTED: 65 | { 66 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 67 | 68 | String msg = "CONNECT\r\naccept-version:1.1,1.0\r\nheart-beat:10000,10000\r\n\r\n"; 69 | sendMessage(msg); 70 | } 71 | break; 72 | case WStype_TEXT: 73 | { 74 | // ##################### 75 | // handle STOMP protocol 76 | // ##################### 77 | 78 | String text = (char*) payload; 79 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 80 | 81 | if (text.startsWith("CONNECTED")) { 82 | 83 | // subscribe to some channels 84 | 85 | String msg = "SUBSCRIBE\nid:sub-0\ndestination:/user/queue/messages\n\n"; 86 | sendMessage(msg); 87 | delay(1000); 88 | 89 | // and send a message 90 | 91 | msg = "SEND\ndestination:/app/message\n\n{\"user\":\"esp\",\"message\":\"Hello!\"}"; 92 | sendMessage(msg); 93 | delay(1000); 94 | 95 | } else { 96 | 97 | // do something with messages 98 | 99 | } 100 | 101 | break; 102 | } 103 | case WStype_BIN: 104 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 105 | hexdump(payload, length); 106 | 107 | // send data to server 108 | // webSocket.sendBIN(payload, length); 109 | break; 110 | } 111 | 112 | } 113 | 114 | void setup() { 115 | 116 | // setup serial 117 | 118 | // USE_SERIAL.begin(921600); 119 | USE_SERIAL.begin(115200); 120 | 121 | // USE_SERIAL.setDebugOutput(true); 122 | 123 | USE_SERIAL.println(); 124 | 125 | 126 | // connect to WiFi 127 | 128 | USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ..."); 129 | WiFi.mode(WIFI_STA); 130 | WiFi.begin(wlan_ssid, wlan_password); 131 | 132 | while (WiFi.status() != WL_CONNECTED) { 133 | delay(500); 134 | USE_SERIAL.print("."); 135 | } 136 | USE_SERIAL.println(" success."); 137 | USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP()); 138 | 139 | 140 | // connect to websocket 141 | webSocket.begin(ws_host, ws_port, stompUrl); 142 | webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config 143 | // webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny 144 | webSocket.onEvent(webSocketEvent); 145 | } 146 | 147 | void loop() { 148 | webSocket.loop(); 149 | } 150 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketClientStompOverSockJs/WebSocketClientStompOverSockJs.ino: -------------------------------------------------------------------------------- 1 | /* 2 | WebSocketClientStompOverSockJs.ino 3 | 4 | Example for connecting and maintining a connection with a SockJS+STOMP websocket connection. 5 | In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html). 6 | 7 | Created on: 18.07.2017 8 | Author: Martin Becker , Contact: becker@informatik.uni-wuerzburg.de 9 | */ 10 | 11 | // PRE 12 | 13 | #define USE_SERIAL Serial 14 | 15 | 16 | // LIBRARIES 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | 25 | // SETTINGS 26 | 27 | const char* wlan_ssid = "yourssid"; 28 | const char* wlan_password = "somepassword"; 29 | 30 | const char* ws_host = "the.host.net"; 31 | const int ws_port = 80; 32 | 33 | // base URL for SockJS (websocket) connection 34 | // The complete URL will look something like this(cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36): 35 | // ws://://<3digits>//websocket 36 | // For the default config of Spring's SockJS/STOMP support, the default base URL is "/socketentry/". 37 | const char* ws_baseurl = "/socketentry/"; // don't forget leading and trailing "/" !!! 38 | 39 | 40 | // VARIABLES 41 | 42 | WebSocketsClient webSocket; 43 | 44 | 45 | // FUNCTIONS 46 | 47 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 48 | 49 | switch (type) { 50 | case WStype_DISCONNECTED: 51 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 52 | break; 53 | case WStype_CONNECTED: 54 | { 55 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 56 | } 57 | break; 58 | case WStype_TEXT: 59 | { 60 | // ##################### 61 | // handle SockJs+STOMP protocol 62 | // ##################### 63 | 64 | String text = (char*) payload; 65 | 66 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 67 | 68 | if (payload[0] == 'h') { 69 | 70 | USE_SERIAL.println("Heartbeat!"); 71 | 72 | } else if (payload[0] == 'o') { 73 | 74 | // on open connection 75 | char *msg = "[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]"; 76 | webSocket.sendTXT(msg); 77 | 78 | } else if (text.startsWith("a[\"CONNECTED")) { 79 | 80 | // subscribe to some channels 81 | 82 | char *msg = "[\"SUBSCRIBE\\nid:sub-0\\ndestination:/user/queue/messages\\n\\n\\u0000\"]"; 83 | webSocket.sendTXT(msg); 84 | delay(1000); 85 | 86 | // and send a message 87 | 88 | msg = "[\"SEND\\ndestination:/app/message\\n\\n{\\\"user\\\":\\\"esp\\\",\\\"message\\\":\\\"Hello!\\\"}\\u0000\"]"; 89 | webSocket.sendTXT(msg); 90 | delay(1000); 91 | } 92 | 93 | break; 94 | } 95 | case WStype_BIN: 96 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 97 | hexdump(payload, length); 98 | 99 | // send data to server 100 | // webSocket.sendBIN(payload, length); 101 | break; 102 | } 103 | 104 | } 105 | 106 | void setup() { 107 | 108 | // setup serial 109 | 110 | // USE_SERIAL.begin(921600); 111 | USE_SERIAL.begin(115200); 112 | 113 | // USE_SERIAL.setDebugOutput(true); 114 | 115 | USE_SERIAL.println(); 116 | 117 | 118 | // connect to WiFi 119 | 120 | USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ..."); 121 | WiFi.mode(WIFI_STA); 122 | WiFi.begin(wlan_ssid, wlan_password); 123 | 124 | while (WiFi.status() != WL_CONNECTED) { 125 | delay(500); 126 | USE_SERIAL.print("."); 127 | } 128 | USE_SERIAL.println(" success."); 129 | USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP()); 130 | 131 | 132 | // ##################### 133 | // create socket url according to SockJS protocol (cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36) 134 | // ##################### 135 | String socketUrl = ws_baseurl; 136 | socketUrl += random(0, 999); 137 | socketUrl += "/"; 138 | socketUrl += random(0, 999999); // should be a random string, but this works (see ) 139 | socketUrl += "/websocket"; 140 | 141 | // connect to websocket 142 | webSocket.begin(ws_host, ws_port, socketUrl); 143 | webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config 144 | // webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny 145 | webSocket.onEvent(webSocketEvent); 146 | } 147 | 148 | void loop() { 149 | webSocket.loop(); 150 | } 151 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServer/WebSocketServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServer.ino 3 | * 4 | * Created on: 22.05.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | ESP8266WiFiMulti WiFiMulti; 16 | 17 | WebSocketsServer webSocket = WebSocketsServer(81); 18 | 19 | #define USE_SERIAL Serial1 20 | 21 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 22 | 23 | switch(type) { 24 | case WStype_DISCONNECTED: 25 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 26 | break; 27 | case WStype_CONNECTED: 28 | { 29 | IPAddress ip = webSocket.remoteIP(num); 30 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 31 | 32 | // send message to client 33 | webSocket.sendTXT(num, "Connected"); 34 | } 35 | break; 36 | case WStype_TEXT: 37 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 38 | 39 | // send message to client 40 | // webSocket.sendTXT(num, "message here"); 41 | 42 | // send data to all connected clients 43 | // webSocket.broadcastTXT("message here"); 44 | break; 45 | case WStype_BIN: 46 | USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); 47 | hexdump(payload, length); 48 | 49 | // send message to client 50 | // webSocket.sendBIN(num, payload, length); 51 | break; 52 | } 53 | 54 | } 55 | 56 | void setup() { 57 | // USE_SERIAL.begin(921600); 58 | USE_SERIAL.begin(115200); 59 | 60 | //Serial.setDebugOutput(true); 61 | USE_SERIAL.setDebugOutput(true); 62 | 63 | USE_SERIAL.println(); 64 | USE_SERIAL.println(); 65 | USE_SERIAL.println(); 66 | 67 | for(uint8_t t = 4; t > 0; t--) { 68 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 69 | USE_SERIAL.flush(); 70 | delay(1000); 71 | } 72 | 73 | WiFiMulti.addAP("SSID", "passpasspass"); 74 | 75 | while(WiFiMulti.run() != WL_CONNECTED) { 76 | delay(100); 77 | } 78 | 79 | webSocket.begin(); 80 | webSocket.onEvent(webSocketEvent); 81 | } 82 | 83 | void loop() { 84 | webSocket.loop(); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerAllFunctionsDemo/WebSocketServerAllFunctionsDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServerAllFunctionsDemo.ino 3 | * 4 | * Created on: 10.05.2018 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define LED_RED 15 18 | #define LED_GREEN 12 19 | #define LED_BLUE 13 20 | 21 | #define USE_SERIAL Serial 22 | 23 | ESP8266WiFiMulti WiFiMulti; 24 | 25 | ESP8266WebServer server(80); 26 | WebSocketsServer webSocket = WebSocketsServer(81); 27 | 28 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 29 | 30 | switch(type) { 31 | case WStype_DISCONNECTED: 32 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 33 | break; 34 | case WStype_CONNECTED: { 35 | IPAddress ip = webSocket.remoteIP(num); 36 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 37 | 38 | // send message to client 39 | webSocket.sendTXT(num, "Connected"); 40 | } 41 | break; 42 | case WStype_TEXT: 43 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 44 | 45 | if(payload[0] == '#') { 46 | // we get RGB data 47 | 48 | // decode rgb data 49 | uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); 50 | 51 | analogWrite(LED_RED, ((rgb >> 16) & 0xFF)); 52 | analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF)); 53 | analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF)); 54 | } 55 | 56 | break; 57 | } 58 | 59 | } 60 | 61 | void setup() { 62 | //USE_SERIAL.begin(921600); 63 | USE_SERIAL.begin(115200); 64 | 65 | //USE_SERIAL.setDebugOutput(true); 66 | 67 | USE_SERIAL.println(); 68 | USE_SERIAL.println(); 69 | USE_SERIAL.println(); 70 | 71 | for(uint8_t t = 4; t > 0; t--) { 72 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 73 | USE_SERIAL.flush(); 74 | delay(1000); 75 | } 76 | 77 | pinMode(LED_RED, OUTPUT); 78 | pinMode(LED_GREEN, OUTPUT); 79 | pinMode(LED_BLUE, OUTPUT); 80 | 81 | digitalWrite(LED_RED, 1); 82 | digitalWrite(LED_GREEN, 1); 83 | digitalWrite(LED_BLUE, 1); 84 | 85 | WiFiMulti.addAP("SSID", "passpasspass"); 86 | 87 | while(WiFiMulti.run() != WL_CONNECTED) { 88 | delay(100); 89 | } 90 | 91 | // start webSocket server 92 | webSocket.begin(); 93 | webSocket.onEvent(webSocketEvent); 94 | 95 | if(MDNS.begin("esp8266")) { 96 | USE_SERIAL.println("MDNS responder started"); 97 | } 98 | 99 | // handle index 100 | server.on("/", []() { 101 | // send index.html 102 | server.send(200, "text/html", "LED Control:

R:
G:
B:
"); 103 | }); 104 | 105 | server.begin(); 106 | 107 | // Add service to MDNS 108 | MDNS.addService("http", "tcp", 80); 109 | MDNS.addService("ws", "tcp", 81); 110 | 111 | digitalWrite(LED_RED, 0); 112 | digitalWrite(LED_GREEN, 0); 113 | digitalWrite(LED_BLUE, 0); 114 | 115 | } 116 | 117 | unsigned long last_10sec = 0; 118 | unsigned int counter = 0; 119 | 120 | void loop() { 121 | unsigned long t = millis(); 122 | webSocket.loop(); 123 | server.handleClient(); 124 | 125 | if((t - last_10sec) > 10 * 1000) { 126 | counter++; 127 | bool ping = (counter % 2); 128 | int i = webSocket.connectedClients(ping); 129 | USE_SERIAL.printf("%d Connected websocket clients ping: %d\n", i, ping); 130 | last_10sec = millis(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerFragmentation/WebSocketServerFragmentation.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServer.ino 3 | * 4 | * Created on: 22.05.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | ESP8266WiFiMulti WiFiMulti; 16 | 17 | WebSocketsServer webSocket = WebSocketsServer(81); 18 | 19 | #define USE_SERIAL Serial 20 | 21 | String fragmentBuffer = ""; 22 | 23 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 24 | 25 | switch(type) { 26 | case WStype_DISCONNECTED: 27 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 28 | break; 29 | case WStype_CONNECTED: { 30 | IPAddress ip = webSocket.remoteIP(num); 31 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 32 | 33 | // send message to client 34 | webSocket.sendTXT(num, "Connected"); 35 | } 36 | break; 37 | case WStype_TEXT: 38 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 39 | break; 40 | case WStype_BIN: 41 | USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); 42 | hexdump(payload, length); 43 | break; 44 | 45 | // Fragmentation / continuation opcode handling 46 | // case WStype_FRAGMENT_BIN_START: 47 | case WStype_FRAGMENT_TEXT_START: 48 | fragmentBuffer = (char*)payload; 49 | USE_SERIAL.printf("[%u] get start start of Textfragment: %s\n", num, payload); 50 | break; 51 | case WStype_FRAGMENT: 52 | fragmentBuffer += (char*)payload; 53 | USE_SERIAL.printf("[%u] get Textfragment : %s\n", num, payload); 54 | break; 55 | case WStype_FRAGMENT_FIN: 56 | fragmentBuffer += (char*)payload; 57 | USE_SERIAL.printf("[%u] get end of Textfragment: %s\n", num, payload); 58 | USE_SERIAL.printf("[%u] full frame: %s\n", num, fragmentBuffer.c_str()); 59 | break; 60 | } 61 | 62 | } 63 | 64 | void setup() { 65 | // USE_SERIAL.begin(921600); 66 | USE_SERIAL.begin(115200); 67 | 68 | //Serial.setDebugOutput(true); 69 | USE_SERIAL.setDebugOutput(true); 70 | 71 | USE_SERIAL.println(); 72 | USE_SERIAL.println(); 73 | USE_SERIAL.println(); 74 | 75 | for(uint8_t t = 4; t > 0; t--) { 76 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 77 | USE_SERIAL.flush(); 78 | delay(1000); 79 | } 80 | 81 | WiFiMulti.addAP("SSID", "passpasspass"); 82 | 83 | while(WiFiMulti.run() != WL_CONNECTED) { 84 | delay(100); 85 | } 86 | 87 | webSocket.begin(); 88 | webSocket.onEvent(webSocketEvent); 89 | } 90 | 91 | void loop() { 92 | webSocket.loop(); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerHooked/WebSocketServerHooked.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServerHooked.ino 3 | * 4 | * Created on: 22.05.2015 5 | * Hooked on: 28.10.2020 6 | * 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | ESP8266WiFiMulti WiFiMulti; 18 | 19 | ESP8266WebServer server(80); 20 | WebSockets4WebServer webSocket; 21 | 22 | #define USE_SERIAL Serial 23 | 24 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 25 | 26 | switch(type) { 27 | case WStype_DISCONNECTED: 28 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 29 | break; 30 | case WStype_CONNECTED: 31 | { 32 | IPAddress ip = webSocket.remoteIP(num); 33 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 34 | 35 | // send message to client 36 | webSocket.sendTXT(num, "Connected"); 37 | } 38 | break; 39 | case WStype_TEXT: 40 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 41 | 42 | // send message to client 43 | // webSocket.sendTXT(num, "message here"); 44 | 45 | // send data to all connected clients 46 | // webSocket.broadcastTXT("message here"); 47 | break; 48 | case WStype_BIN: 49 | USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); 50 | hexdump(payload, length); 51 | 52 | // send message to client 53 | // webSocket.sendBIN(num, payload, length); 54 | break; 55 | } 56 | 57 | } 58 | 59 | void setup() { 60 | // USE_SERIAL.begin(921600); 61 | USE_SERIAL.begin(115200); 62 | 63 | //Serial.setDebugOutput(true); 64 | USE_SERIAL.setDebugOutput(true); 65 | 66 | USE_SERIAL.println(); 67 | USE_SERIAL.println(); 68 | USE_SERIAL.println(); 69 | 70 | for(uint8_t t = 4; t > 0; t--) { 71 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 72 | USE_SERIAL.flush(); 73 | delay(1000); 74 | } 75 | 76 | WiFiMulti.addAP("SSID", "passpasspass"); 77 | 78 | while(WiFiMulti.run() != WL_CONNECTED) { 79 | delay(100); 80 | } 81 | 82 | server.on("/", []() { 83 | server.send(200, "text/plain", "I am a regular webserver on port 80!\r\n"); 84 | server.send(200, "text/plain", "I am also a websocket server on '/ws' on the same port 80\r\n"); 85 | }); 86 | 87 | server.addHook(webSocket.hookForWebserver("/ws", webSocketEvent)); 88 | 89 | server.begin(); 90 | Serial.println("HTTP server started on port 80"); 91 | Serial.println("WebSocket server started on the same port"); 92 | Serial.printf("my network address is either 'arduinoWebsockets.local' (mDNS) or '%s'\n", WiFi.localIP().toString().c_str()); 93 | 94 | if (!MDNS.begin("arduinoWebsockets")) { 95 | Serial.println("Error setting up MDNS responder!"); 96 | } 97 | } 98 | 99 | void loop() { 100 | server.handleClient(); 101 | webSocket.loop(); 102 | MDNS.update(); 103 | } 104 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerHooked/emu: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # linux script to compile&run arduinoWebSockets in a mock environment 4 | 5 | if [ -z "$ESP8266ARDUINO" ]; then 6 | echo "please set ESP8266ARDUINO env-var to where esp8266/arduino sits" 7 | exit 1 8 | fi 9 | 10 | set -e 11 | 12 | where=$(pwd) 13 | 14 | cd $ESP8266ARDUINO/tests/host/ 15 | 16 | make -j FORCE32=0 \ 17 | ULIBDIRS=../../libraries/Hash/:~/dev/proj/arduino/libraries/arduinoWebSockets \ 18 | ${where}/WebSocketServerHooked 19 | 20 | valgrind ./bin/WebSocketServerHooked/WebSocketServerHooked -b "$@" 21 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerHooked/ws-testclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # python websocket client to test with 4 | # emulator: server is at ws://127.0.0.1:9080/ws 5 | # esp8266: server is at ws:///ws 6 | # (uncomment the right line below) 7 | 8 | #uri = "ws://127.0.0.1:9080/ws" 9 | uri = "ws://arduinoWebsockets.local/ws" 10 | 11 | import websocket 12 | try: 13 | import thread 14 | except ImportError: 15 | import _thread as thread 16 | import time 17 | 18 | def on_message(ws, message): 19 | print("message"); 20 | print(message) 21 | 22 | def on_error(ws, error): 23 | print("error") 24 | print(error) 25 | 26 | def on_close(ws): 27 | print("### closed ###") 28 | 29 | def on_open(ws): 30 | print("opened") 31 | def run(*args): 32 | for i in range(3): 33 | time.sleep(1) 34 | ws.send("Hello %d" % i) 35 | time.sleep(1) 36 | ws.close() 37 | print("thread terminating...") 38 | thread.start_new_thread(run, ()) 39 | 40 | 41 | if __name__ == "__main__": 42 | websocket.enableTrace(True) 43 | ws = websocket.WebSocketApp(uri, on_message = on_message, on_error = on_error, on_close = on_close) 44 | ws.on_open = on_open 45 | ws.run_forever() 46 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServerHttpHeaderValidation/WebSocketServerHttpHeaderValidation.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServerHttpHeaderValidation.ino 3 | * 4 | * Created on: 08.06.2016 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | ESP8266WiFiMulti WiFiMulti; 16 | 17 | WebSocketsServer webSocket = WebSocketsServer(81); 18 | 19 | #define USE_SERIAL Serial1 20 | 21 | const unsigned long int validSessionId = 12345; //some arbitrary value to act as a valid sessionId 22 | 23 | /* 24 | * Returns a bool value as an indicator to describe whether a user is allowed to initiate a websocket upgrade 25 | * based on the value of a cookie. This function expects the rawCookieHeaderValue to look like this "sessionId=|" 26 | */ 27 | bool isCookieValid(String rawCookieHeaderValue) { 28 | 29 | if (rawCookieHeaderValue.indexOf("sessionId") != -1) { 30 | String sessionIdStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("sessionId=") + 10, rawCookieHeaderValue.indexOf("|")); 31 | unsigned long int sessionId = strtoul(sessionIdStr.c_str(), NULL, 10); 32 | return sessionId == validSessionId; 33 | } 34 | return false; 35 | } 36 | 37 | /* 38 | * The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader 39 | */ 40 | bool validateHttpHeader(String headerName, String headerValue) { 41 | 42 | //assume a true response for any headers not handled by this validator 43 | bool valid = true; 44 | 45 | if(headerName.equalsIgnoreCase("Cookie")) { 46 | //if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function 47 | valid = isCookieValid(headerValue); 48 | } 49 | 50 | return valid; 51 | } 52 | 53 | void setup() { 54 | // USE_SERIAL.begin(921600); 55 | USE_SERIAL.begin(115200); 56 | 57 | //Serial.setDebugOutput(true); 58 | USE_SERIAL.setDebugOutput(true); 59 | 60 | USE_SERIAL.println(); 61 | USE_SERIAL.println(); 62 | USE_SERIAL.println(); 63 | 64 | for(uint8_t t = 4; t > 0; t--) { 65 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 66 | USE_SERIAL.flush(); 67 | delay(1000); 68 | } 69 | 70 | WiFiMulti.addAP("SSID", "passpasspass"); 71 | 72 | while(WiFiMulti.run() != WL_CONNECTED) { 73 | delay(100); 74 | } 75 | 76 | //connecting clients must supply a valid session cookie at websocket upgrade handshake negotiation time 77 | const char * headerkeys[] = { "Cookie" }; 78 | size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*); 79 | webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount); 80 | webSocket.begin(); 81 | } 82 | 83 | void loop() { 84 | webSocket.loop(); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /examples/esp8266_pico/WebSocketServer_LEDcontrol/WebSocketServer_LEDcontrol.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketServer_LEDcontrol.ino 3 | * 4 | * Created on: 26.11.2015 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define LED_RED 15 18 | #define LED_GREEN 12 19 | #define LED_BLUE 13 20 | 21 | #define USE_SERIAL Serial 22 | 23 | 24 | ESP8266WiFiMulti WiFiMulti; 25 | 26 | ESP8266WebServer server(80); 27 | WebSocketsServer webSocket = WebSocketsServer(81); 28 | 29 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 30 | 31 | switch(type) { 32 | case WStype_DISCONNECTED: 33 | USE_SERIAL.printf("[%u] Disconnected!\n", num); 34 | break; 35 | case WStype_CONNECTED: { 36 | IPAddress ip = webSocket.remoteIP(num); 37 | USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 38 | 39 | // send message to client 40 | webSocket.sendTXT(num, "Connected"); 41 | } 42 | break; 43 | case WStype_TEXT: 44 | USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); 45 | 46 | if(payload[0] == '#') { 47 | // we get RGB data 48 | 49 | // decode rgb data 50 | uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); 51 | 52 | analogWrite(LED_RED, ((rgb >> 16) & 0xFF)); 53 | analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF)); 54 | analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF)); 55 | } 56 | 57 | break; 58 | } 59 | 60 | } 61 | 62 | void setup() { 63 | //USE_SERIAL.begin(921600); 64 | USE_SERIAL.begin(115200); 65 | 66 | //USE_SERIAL.setDebugOutput(true); 67 | 68 | USE_SERIAL.println(); 69 | USE_SERIAL.println(); 70 | USE_SERIAL.println(); 71 | 72 | for(uint8_t t = 4; t > 0; t--) { 73 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 74 | USE_SERIAL.flush(); 75 | delay(1000); 76 | } 77 | 78 | pinMode(LED_RED, OUTPUT); 79 | pinMode(LED_GREEN, OUTPUT); 80 | pinMode(LED_BLUE, OUTPUT); 81 | 82 | digitalWrite(LED_RED, 1); 83 | digitalWrite(LED_GREEN, 1); 84 | digitalWrite(LED_BLUE, 1); 85 | 86 | WiFiMulti.addAP("SSID", "passpasspass"); 87 | 88 | while(WiFiMulti.run() != WL_CONNECTED) { 89 | delay(100); 90 | } 91 | 92 | // start webSocket server 93 | webSocket.begin(); 94 | webSocket.onEvent(webSocketEvent); 95 | 96 | if(MDNS.begin("esp8266")) { 97 | USE_SERIAL.println("MDNS responder started"); 98 | } 99 | 100 | // handle index 101 | server.on("/", []() { 102 | // send index.html 103 | server.send(200, "text/html", "LED Control:

R:
G:
B:
"); 104 | }); 105 | 106 | server.begin(); 107 | 108 | // Add service to MDNS 109 | MDNS.addService("http", "tcp", 80); 110 | MDNS.addService("ws", "tcp", 81); 111 | 112 | digitalWrite(LED_RED, 0); 113 | digitalWrite(LED_GREEN, 0); 114 | digitalWrite(LED_BLUE, 0); 115 | 116 | } 117 | 118 | void loop() { 119 | webSocket.loop(); 120 | server.handleClient(); 121 | } 122 | -------------------------------------------------------------------------------- /examples/particle/ParticleWebSocketClient/application.cpp: -------------------------------------------------------------------------------- 1 | /* To compile using make CLI, create a folder under \firmware\user\applications and copy application.cpp there. 2 | * Then, copy src files under particleWebSocket folder. 3 | */ 4 | 5 | #include "application.h" 6 | #include "particleWebSocket/WebSocketsClient.h" 7 | 8 | WebSocketsClient webSocket; 9 | 10 | void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) 11 | { 12 | switch (type) 13 | { 14 | case WStype_DISCONNECTED: 15 | Serial.printlnf("[WSc] Disconnected!"); 16 | break; 17 | case WStype_CONNECTED: 18 | Serial.printlnf("[WSc] Connected to URL: %s", payload); 19 | webSocket.sendTXT("Connected\r\n"); 20 | break; 21 | case WStype_TEXT: 22 | Serial.printlnf("[WSc] get text: %s", payload); 23 | break; 24 | case WStype_BIN: 25 | Serial.printlnf("[WSc] get binary length: %u", length); 26 | break; 27 | } 28 | } 29 | 30 | void setup() 31 | { 32 | Serial.begin(9600); 33 | 34 | WiFi.setCredentials("[SSID]", "[PASSWORD]", WPA2, WLAN_CIPHER_AES_TKIP); 35 | WiFi.connect(); 36 | 37 | webSocket.begin("192.168.1.153", 85, "/ClientService/?variable=Test1212"); 38 | webSocket.onEvent(webSocketEvent); 39 | } 40 | 41 | void loop() 42 | { 43 | webSocket.sendTXT("Hello world!"); 44 | delay(500); 45 | webSocket.loop(); 46 | } 47 | -------------------------------------------------------------------------------- /examples/seeed-studio/xio-wio-terminal/WebSocketClient/WebSocketClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * WebSocketClient.ino 3 | * 4 | * Created on: 10.08.2024 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | WebSocketsClient webSocket; 14 | WiFiMulti wifiMulti; 15 | 16 | #define USE_SERIAL Serial 17 | 18 | void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { 19 | const uint8_t* src = (const uint8_t*) mem; 20 | USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 21 | for(uint32_t i = 0; i < len; i++) { 22 | if(i % cols == 0) { 23 | USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 24 | } 25 | USE_SERIAL.printf("%02X ", *src); 26 | src++; 27 | } 28 | USE_SERIAL.printf("\n"); 29 | } 30 | 31 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 32 | 33 | switch(type) { 34 | case WStype_DISCONNECTED: 35 | USE_SERIAL.printf("[WSc] Disconnected!\n"); 36 | break; 37 | case WStype_CONNECTED: 38 | USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); 39 | 40 | // send message to server when Connected 41 | webSocket.sendTXT("Connected"); 42 | break; 43 | case WStype_TEXT: 44 | USE_SERIAL.printf("[WSc] get text: %s\n", payload); 45 | 46 | // send message to server 47 | // webSocket.sendTXT("message here"); 48 | break; 49 | case WStype_BIN: 50 | USE_SERIAL.printf("[WSc] get binary length: %u\n", length); 51 | hexdump(payload, length); 52 | 53 | // send data to server 54 | // webSocket.sendBIN(payload, length); 55 | break; 56 | case WStype_ERROR: 57 | case WStype_FRAGMENT_TEXT_START: 58 | case WStype_FRAGMENT_BIN_START: 59 | case WStype_FRAGMENT: 60 | case WStype_PONG: 61 | case WStype_PING: 62 | case WStype_FRAGMENT_FIN: 63 | break; 64 | } 65 | 66 | } 67 | 68 | void setup() { 69 | // USE_SERIAL.begin(921600); 70 | USE_SERIAL.begin(115200); 71 | 72 | USE_SERIAL.println(); 73 | USE_SERIAL.println(); 74 | USE_SERIAL.println(); 75 | 76 | for(uint8_t t = 4; t > 0; t--) { 77 | USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); 78 | USE_SERIAL.flush(); 79 | delay(1000); 80 | } 81 | 82 | wifiMulti.addAP("SSID", "passpasspass"); 83 | 84 | //WiFi.disconnect(); 85 | while(wifiMulti.run() != WL_CONNECTED) { 86 | delay(100); 87 | } 88 | 89 | // server address, port and URL 90 | webSocket.begin("192.168.0.123", 81, "/"); 91 | 92 | // event handler 93 | webSocket.onEvent(webSocketEvent); 94 | 95 | // use HTTP Basic Authorization this is optional remove if not needed 96 | webSocket.setAuthorization("user", "Password"); 97 | 98 | // try ever 5000 again if connection has failed 99 | webSocket.setReconnectInterval(5000); 100 | 101 | } 102 | 103 | void loop() { 104 | webSocket.loop(); 105 | } 106 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | { 4 | "maintainer": true, 5 | "name": "Markus Sattler", 6 | "url": "https://github.com/Links2004" 7 | } 8 | ], 9 | "description": "WebSocket Server and Client for Arduino based on RFC6455", 10 | "export": { 11 | "exclude": [ 12 | "tests" 13 | ] 14 | }, 15 | "frameworks": "arduino", 16 | "keywords": "wifi, http, web, server, client, websocket", 17 | "license": "LGPL-2.1", 18 | "name": "WebSockets", 19 | "platforms": "*", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/Links2004/arduinoWebSockets.git" 23 | }, 24 | "version": "2.6.1" 25 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=WebSockets 2 | version=2.6.1 3 | author=Markus Sattler 4 | maintainer=Markus Sattler 5 | sentence=WebSockets for Arduino (Server + Client) 6 | paragraph=use 2.x.x for ESP and 1.3 for AVR 7 | category=Communication 8 | url=https://github.com/Links2004/arduinoWebSockets 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/SocketIOclient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SocketIOclient.cpp 3 | * 4 | * Created on: May 12, 2018 5 | * Author: links 6 | */ 7 | 8 | #include "WebSockets.h" 9 | #include "WebSocketsClient.h" 10 | #include "SocketIOclient.h" 11 | 12 | SocketIOclient::SocketIOclient() { 13 | } 14 | 15 | SocketIOclient::~SocketIOclient() { 16 | } 17 | 18 | void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { 19 | WebSocketsClient::beginSocketIO(host, port, url, protocol); 20 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 21 | initClient(); 22 | } 23 | 24 | void SocketIOclient::begin(String host, uint16_t port, String url, String protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { 25 | WebSocketsClient::beginSocketIO(host, port, url, protocol); 26 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 27 | initClient(); 28 | } 29 | #if defined(HAS_SSL) 30 | void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { 31 | WebSocketsClient::beginSocketIOSSL(host, port, url, protocol); 32 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 33 | initClient(); 34 | } 35 | 36 | void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { 37 | WebSocketsClient::beginSocketIOSSL(host, port, url, protocol); 38 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 39 | initClient(); 40 | } 41 | #if defined(SSL_BARESSL) 42 | 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) { 43 | WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol); 44 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 45 | initClient(); 46 | } 47 | 48 | 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) { 49 | WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol); 50 | WebSocketsClient::enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); 51 | initClient(); 52 | } 53 | 54 | void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) { 55 | WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey); 56 | } 57 | 58 | void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) { 59 | WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey); 60 | } 61 | 62 | #endif 63 | #endif 64 | 65 | void SocketIOclient::configureEIOping(bool disableHeartbeat) { 66 | _disableHeartbeat = disableHeartbeat; 67 | } 68 | 69 | void SocketIOclient::initClient(void) { 70 | if(_client.cUrl.indexOf("EIO=4") != -1) { 71 | DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n"); 72 | configureEIOping(true); 73 | } 74 | } 75 | 76 | /** 77 | * set callback function 78 | * @param cbEvent SocketIOclientEvent 79 | */ 80 | void SocketIOclient::onEvent(SocketIOclientEvent cbEvent) { 81 | _cbEvent = cbEvent; 82 | } 83 | 84 | bool SocketIOclient::isConnected(void) { 85 | return WebSocketsClient::isConnected(); 86 | } 87 | 88 | void SocketIOclient::setExtraHeaders(const char * extraHeaders) { 89 | return WebSocketsClient::setExtraHeaders(extraHeaders); 90 | } 91 | 92 | void SocketIOclient::setReconnectInterval(unsigned long time) { 93 | return WebSocketsClient::setReconnectInterval(time); 94 | } 95 | 96 | void SocketIOclient::disconnect(void) { 97 | WebSocketsClient::disconnect(); 98 | } 99 | 100 | /** 101 | * send text data to client 102 | * @param num uint8_t client id 103 | * @param type socketIOmessageType_t 104 | * @param payload uint8_t * 105 | * @param length size_t 106 | * @param headerToPayload bool (see sendFrame for more details) 107 | * @return true if ok 108 | */ 109 | bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t length, bool headerToPayload) { 110 | bool ret = false; 111 | if(length == 0) { 112 | length = strlen((const char *)payload); 113 | } 114 | if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) { 115 | if(!headerToPayload) { 116 | // webSocket Header 117 | ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true); 118 | // Engine.IO / Socket.IO Header 119 | if(ret) { 120 | uint8_t buf[3] = { eIOtype_MESSAGE, type, 0x00 }; 121 | ret = WebSocketsClient::write(&_client, buf, 2); 122 | } 123 | if(ret && payload && length > 0) { 124 | ret = WebSocketsClient::write(&_client, payload, length); 125 | } 126 | return ret; 127 | } else { 128 | // TODO implement 129 | } 130 | } 131 | return false; 132 | } 133 | 134 | bool SocketIOclient::send(socketIOmessageType_t type, const uint8_t * payload, size_t length) { 135 | return send(type, (uint8_t *)payload, length); 136 | } 137 | 138 | bool SocketIOclient::send(socketIOmessageType_t type, char * payload, size_t length, bool headerToPayload) { 139 | return send(type, (uint8_t *)payload, length, headerToPayload); 140 | } 141 | 142 | bool SocketIOclient::send(socketIOmessageType_t type, const char * payload, size_t length) { 143 | return send(type, (uint8_t *)payload, length); 144 | } 145 | 146 | bool SocketIOclient::send(socketIOmessageType_t type, String & payload) { 147 | return send(type, (uint8_t *)payload.c_str(), payload.length()); 148 | } 149 | 150 | /** 151 | * send text data to client 152 | * @param num uint8_t client id 153 | * @param payload uint8_t * 154 | * @param length size_t 155 | * @param headerToPayload bool (see sendFrame for more details) 156 | * @return true if ok 157 | */ 158 | bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) { 159 | return send(sIOtype_EVENT, payload, length, headerToPayload); 160 | } 161 | 162 | bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) { 163 | return sendEVENT((uint8_t *)payload, length); 164 | } 165 | 166 | bool SocketIOclient::sendEVENT(char * payload, size_t length, bool headerToPayload) { 167 | return sendEVENT((uint8_t *)payload, length, headerToPayload); 168 | } 169 | 170 | bool SocketIOclient::sendEVENT(const char * payload, size_t length) { 171 | return sendEVENT((uint8_t *)payload, length); 172 | } 173 | 174 | bool SocketIOclient::sendEVENT(String & payload) { 175 | return sendEVENT((uint8_t *)payload.c_str(), payload.length()); 176 | } 177 | 178 | void SocketIOclient::loop(void) { 179 | WebSocketsClient::loop(); 180 | unsigned long t = millis(); 181 | if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) { 182 | _lastHeartbeat = t; 183 | DEBUG_WEBSOCKETS("[wsIOc] send ping\n"); 184 | WebSocketsClient::sendTXT(eIOtype_PING); 185 | } 186 | } 187 | 188 | void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t length) { 189 | switch(type) { 190 | case WStype_DISCONNECTED: 191 | runIOCbEvent(sIOtype_DISCONNECT, NULL, 0); 192 | DEBUG_WEBSOCKETS("[wsIOc] Disconnected!\n"); 193 | break; 194 | case WStype_CONNECTED: { 195 | DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload); 196 | // send message to server when Connected 197 | // Engine.io upgrade confirmation message (required) 198 | WebSocketsClient::sendTXT("2probe"); 199 | WebSocketsClient::sendTXT(eIOtype_UPGRADE); 200 | runIOCbEvent(sIOtype_CONNECT, payload, length); 201 | } break; 202 | case WStype_TEXT: { 203 | if(length < 1) { 204 | break; 205 | } 206 | 207 | engineIOmessageType_t eType = (engineIOmessageType_t)payload[0]; 208 | switch(eType) { 209 | case eIOtype_PING: 210 | payload[0] = eIOtype_PONG; 211 | DEBUG_WEBSOCKETS("[wsIOc] get ping send pong (%s)\n", payload); 212 | WebSocketsClient::sendTXT(payload, length, false); 213 | break; 214 | case eIOtype_PONG: 215 | DEBUG_WEBSOCKETS("[wsIOc] get pong\n"); 216 | break; 217 | case eIOtype_MESSAGE: { 218 | if(length < 2) { 219 | break; 220 | } 221 | socketIOmessageType_t ioType = (socketIOmessageType_t)payload[1]; 222 | uint8_t * data = &payload[2]; 223 | size_t lData = length - 2; 224 | switch(ioType) { 225 | case sIOtype_EVENT: 226 | DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data); 227 | break; 228 | case sIOtype_CONNECT: 229 | DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data); 230 | return; 231 | case sIOtype_DISCONNECT: 232 | case sIOtype_ACK: 233 | case sIOtype_ERROR: 234 | case sIOtype_BINARY_EVENT: 235 | case sIOtype_BINARY_ACK: 236 | default: 237 | DEBUG_WEBSOCKETS("[wsIOc] Socket.IO Message Type %c (%02X) is not implemented\n", ioType, ioType); 238 | DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload); 239 | break; 240 | } 241 | 242 | runIOCbEvent(ioType, data, lData); 243 | } break; 244 | case eIOtype_OPEN: 245 | case eIOtype_CLOSE: 246 | case eIOtype_UPGRADE: 247 | case eIOtype_NOOP: 248 | default: 249 | DEBUG_WEBSOCKETS("[wsIOc] Engine.IO Message Type %c (%02X) is not implemented\n", eType, eType); 250 | DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload); 251 | break; 252 | } 253 | } break; 254 | case WStype_ERROR: 255 | case WStype_BIN: 256 | case WStype_FRAGMENT_TEXT_START: 257 | case WStype_FRAGMENT_BIN_START: 258 | case WStype_FRAGMENT: 259 | case WStype_FRAGMENT_FIN: 260 | case WStype_PING: 261 | case WStype_PONG: 262 | break; 263 | } 264 | } -------------------------------------------------------------------------------- /src/SocketIOclient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SocketIOclient.h 3 | * 4 | * Created on: May 12, 2018 5 | * Author: links 6 | */ 7 | 8 | #ifndef SOCKETIOCLIENT_H_ 9 | #define SOCKETIOCLIENT_H_ 10 | 11 | #include "WebSockets.h" 12 | #include "WebSocketsClient.h" 13 | 14 | #define EIO_HEARTBEAT_INTERVAL 20000 15 | 16 | #define EIO_MAX_HEADER_SIZE (WEBSOCKETS_MAX_HEADER_SIZE + 1) 17 | #define SIO_MAX_HEADER_SIZE (EIO_MAX_HEADER_SIZE + 1) 18 | 19 | typedef enum { 20 | eIOtype_OPEN = '0', ///< Sent from the server when a new transport is opened (recheck) 21 | eIOtype_CLOSE = '1', ///< Request the close of this transport but does not shutdown the connection itself. 22 | eIOtype_PING = '2', ///< Sent by the client. Server should answer with a pong packet containing the same data 23 | eIOtype_PONG = '3', ///< Sent by the server to respond to ping packets. 24 | eIOtype_MESSAGE = '4', ///< actual message, client and server should call their callbacks with the data 25 | eIOtype_UPGRADE = '5', ///< Before engine.io switches a transport, it tests, if server and client can communicate over this transport. If this test succeed, the client sends an upgrade packets which requests the server to flush its cache on the old transport and switch to the new transport. 26 | eIOtype_NOOP = '6', ///< A noop packet. Used primarily to force a poll cycle when an incoming websocket connection is received. 27 | } engineIOmessageType_t; 28 | 29 | typedef enum { 30 | sIOtype_CONNECT = '0', 31 | sIOtype_DISCONNECT = '1', 32 | sIOtype_EVENT = '2', 33 | sIOtype_ACK = '3', 34 | sIOtype_ERROR = '4', 35 | sIOtype_BINARY_EVENT = '5', 36 | sIOtype_BINARY_ACK = '6', 37 | } socketIOmessageType_t; 38 | 39 | class SocketIOclient : protected WebSocketsClient { 40 | public: 41 | #ifdef __AVR__ 42 | typedef void (*SocketIOclientEvent)(socketIOmessageType_t type, uint8_t * payload, size_t length); 43 | #else 44 | typedef std::function SocketIOclientEvent; 45 | #endif 46 | 47 | SocketIOclient(void); 48 | virtual ~SocketIOclient(void); 49 | 50 | 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); 51 | 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); 52 | 53 | #ifdef HAS_SSL 54 | 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); 55 | 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); 56 | #ifndef SSL_AXTLS 57 | 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); 58 | void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL); 59 | #if defined(SSL_BARESSL) 60 | 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); 61 | void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL); 62 | #endif 63 | #endif 64 | #endif 65 | bool isConnected(void); 66 | 67 | void onEvent(SocketIOclientEvent cbEvent); 68 | void disconnect(void); 69 | 70 | bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); 71 | bool sendEVENT(const uint8_t * payload, size_t length = 0); 72 | bool sendEVENT(char * payload, size_t length = 0, bool headerToPayload = false); 73 | bool sendEVENT(const char * payload, size_t length = 0); 74 | bool sendEVENT(String & payload); 75 | 76 | bool send(socketIOmessageType_t type, uint8_t * payload, size_t length = 0, bool headerToPayload = false); 77 | bool send(socketIOmessageType_t type, const uint8_t * payload, size_t length = 0); 78 | bool send(socketIOmessageType_t type, char * payload, size_t length = 0, bool headerToPayload = false); 79 | bool send(socketIOmessageType_t type, const char * payload, size_t length = 0); 80 | bool send(socketIOmessageType_t type, String & payload); 81 | 82 | void setExtraHeaders(const char * extraHeaders = NULL); 83 | void setReconnectInterval(unsigned long time); 84 | 85 | void loop(void); 86 | 87 | void configureEIOping(bool disableHeartbeat = false); 88 | 89 | protected: 90 | bool _disableHeartbeat = false; 91 | uint64_t _lastHeartbeat = 0; 92 | SocketIOclientEvent _cbEvent; 93 | virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { 94 | if(_cbEvent) { 95 | _cbEvent(type, payload, length); 96 | } 97 | } 98 | 99 | void initClient(void); 100 | 101 | // Handeling events from websocket layer 102 | virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { 103 | handleCbEvent(type, payload, length); 104 | } 105 | void handleCbEvent(WStype_t type, uint8_t * payload, size_t length); 106 | }; 107 | 108 | #endif /* SOCKETIOCLIENT_H_ */ 109 | -------------------------------------------------------------------------------- /src/WebSockets4WebServer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WebSocketsServer.cpp 3 | * @date 28.10.2020 4 | * @author Markus Sattler & esp8266/arduino community 5 | * 6 | * Copyright (c) 2020 Markus Sattler. All rights reserved. 7 | * This file is part of the WebSockets for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef __WEBSOCKETS4WEBSERVER_H 26 | #define __WEBSOCKETS4WEBSERVER_H 27 | 28 | #include 29 | #include 30 | 31 | #if((WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)) && WEBSERVER_HAS_HOOK 32 | 33 | class WebSockets4WebServer : public WebSocketsServerCore { 34 | #if defined(ESP8266) 35 | using WebServerClass = ESP8266WebServer; 36 | #else 37 | using WebServerClass = WebServer; 38 | #endif 39 | 40 | public: 41 | WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino") 42 | : WebSocketsServerCore(origin, protocol) { 43 | begin(); 44 | } 45 | 46 | WebServerClass::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) { 47 | onEvent(event); 48 | 49 | return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, WebServerClass::ContentTypeFunction contentType) { 50 | (void)contentType; 51 | 52 | if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) { 53 | return WebServerClass::CLIENT_REQUEST_CAN_CONTINUE; 54 | } 55 | 56 | // allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients()) 57 | WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient); 58 | 59 | // Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient()) 60 | WSclient_t * client = handleNewClient(newTcpClient); 61 | 62 | if(client) { 63 | // give "GET " 64 | String headerLine; 65 | headerLine.reserve(url.length() + 5); 66 | headerLine = "GET "; 67 | headerLine += url; 68 | handleHeader(client, &headerLine); 69 | } 70 | 71 | // tell webserver to not close but forget about this client 72 | return WebServerClass::CLIENT_IS_GIVEN; 73 | }; 74 | } 75 | }; 76 | #else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK 77 | 78 | #ifndef WEBSERVER_HAS_HOOK 79 | #error Your current Framework / Arduino core version does not support Webserver Hook Functions 80 | #else 81 | #error Your Hardware Platform does not support Webserver Hook Functions 82 | #endif 83 | 84 | #endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK 85 | 86 | #endif // __WEBSOCKETS4WEBSERVER_H 87 | -------------------------------------------------------------------------------- /src/WebSocketsClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WebSocketsClient.h 3 | * @date 20.05.2015 4 | * @author Markus Sattler 5 | * 6 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 7 | * This file is part of the WebSockets for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef WEBSOCKETSCLIENT_H_ 26 | #define WEBSOCKETSCLIENT_H_ 27 | 28 | #include "WebSockets.h" 29 | 30 | class WebSocketsClient : protected WebSockets { 31 | public: 32 | #ifdef __AVR__ 33 | typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length); 34 | #else 35 | typedef std::function WebSocketClientEvent; 36 | #endif 37 | 38 | WebSocketsClient(void); 39 | virtual ~WebSocketsClient(void); 40 | 41 | void begin(const char * host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); 42 | void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); 43 | void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); 44 | 45 | #if defined(HAS_SSL) 46 | #ifdef SSL_AXTLS 47 | void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino"); 48 | void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino"); 49 | #else 50 | void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino"); 51 | #if defined(SSL_BARESSL) 52 | void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino"); 53 | void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL); 54 | #endif 55 | void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL); 56 | #endif 57 | void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino"); 58 | #ifdef ESP32 59 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4) 60 | 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"); 61 | #else 62 | void beginSslWithBundle(const char * host, uint16_t port, const char * url = "/", const uint8_t * CA_bundle = NULL, const char * protocol = "arduino"); 63 | #endif 64 | #endif 65 | #endif 66 | 67 | void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); 68 | void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); 69 | 70 | #if defined(HAS_SSL) 71 | void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); 72 | void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); 73 | 74 | void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino"); 75 | #if defined(SSL_BARESSL) 76 | void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino"); 77 | #endif 78 | #endif 79 | 80 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 81 | void loop(void); 82 | #else 83 | // Async interface not need a loop call 84 | void loop(void) __attribute__((deprecated)) {} 85 | #endif 86 | 87 | void onEvent(WebSocketClientEvent cbEvent); 88 | 89 | bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); 90 | bool sendTXT(const uint8_t * payload, size_t length = 0); 91 | bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false); 92 | bool sendTXT(const char * payload, size_t length = 0); 93 | bool sendTXT(String & payload); 94 | bool sendTXT(char payload); 95 | 96 | bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false); 97 | bool sendBIN(const uint8_t * payload, size_t length); 98 | 99 | bool sendPing(uint8_t * payload = NULL, size_t length = 0); 100 | bool sendPing(String & payload); 101 | 102 | void disconnect(void); 103 | 104 | void setAuthorization(const char * user, const char * password); 105 | void setAuthorization(const char * auth); 106 | 107 | void setExtraHeaders(const char * extraHeaders = NULL); 108 | 109 | void setReconnectInterval(unsigned long time); 110 | 111 | void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); 112 | void disableHeartbeat(); 113 | 114 | bool isConnected(void); 115 | 116 | protected: 117 | String _host; 118 | uint16_t _port; 119 | 120 | #if defined(HAS_SSL) 121 | #ifdef SSL_AXTLS 122 | String _fingerprint; 123 | const char * _CA_cert; 124 | const uint8_t * _CA_bundle; 125 | #if defined(ESP32) 126 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4) 127 | size_t _CA_bundle_size; 128 | #endif 129 | #endif 130 | #define SSL_FINGERPRINT_IS_SET (_fingerprint.length()) 131 | #define SSL_FINGERPRINT_NULL "" 132 | #else 133 | const uint8_t * _fingerprint; 134 | #if defined(SSL_BARESSL) 135 | BearSSL::X509List * _CA_cert; 136 | BearSSL::X509List * _client_cert; 137 | BearSSL::PrivateKey * _client_key; 138 | #endif 139 | #define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL) 140 | #define SSL_FINGERPRINT_NULL NULL 141 | #endif 142 | 143 | #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_SAMD_SEED) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_WIFI_NINA) 144 | const char * _CA_cert; 145 | const uint8_t * _CA_bundle; 146 | #endif 147 | 148 | #endif 149 | WSclient_t _client; 150 | 151 | WebSocketClientEvent _cbEvent; 152 | 153 | unsigned long _lastConnectionFail; 154 | unsigned long _reconnectInterval; 155 | unsigned long _lastHeaderSent; 156 | 157 | void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); 158 | 159 | void clientDisconnect(WSclient_t * client); 160 | bool clientIsConnected(WSclient_t * client); 161 | 162 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 163 | void handleClientData(void); 164 | #endif 165 | 166 | void sendHeader(WSclient_t * client); 167 | void handleHeader(WSclient_t * client, String * headerLine); 168 | 169 | void connectedCb(); 170 | void connectFailedCb(); 171 | 172 | void handleHBPing(); // send ping in specified intervals 173 | 174 | #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) 175 | void asyncConnect(); 176 | #endif 177 | 178 | /** 179 | * called for sending a Event to the app 180 | * @param type WStype_t 181 | * @param payload uint8_t * 182 | * @param length size_t 183 | */ 184 | virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { 185 | if(_cbEvent) { 186 | _cbEvent(type, payload, length); 187 | } 188 | } 189 | }; 190 | 191 | #endif /* WEBSOCKETSCLIENT_H_ */ 192 | -------------------------------------------------------------------------------- /src/WebSocketsServer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WebSocketsServer.h 3 | * @date 20.05.2015 4 | * @author Markus Sattler 5 | * 6 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 7 | * This file is part of the WebSockets for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef WEBSOCKETSSERVER_H_ 26 | #define WEBSOCKETSSERVER_H_ 27 | 28 | #include "WebSockets.h" 29 | 30 | #ifndef WEBSOCKETS_SERVER_CLIENT_MAX 31 | #define WEBSOCKETS_SERVER_CLIENT_MAX (5) 32 | #endif 33 | 34 | class WebSocketsServerCore : protected WebSockets { 35 | public: 36 | WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino"); 37 | virtual ~WebSocketsServerCore(void); 38 | 39 | void begin(void); 40 | void close(void); 41 | 42 | #ifdef __AVR__ 43 | typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); 44 | typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue); 45 | #else 46 | typedef std::function WebSocketServerEvent; 47 | typedef std::function WebSocketServerHttpHeaderValFunc; 48 | #endif 49 | 50 | void onEvent(WebSocketServerEvent cbEvent); 51 | void onValidateHttpHeader( 52 | WebSocketServerHttpHeaderValFunc validationFunc, 53 | const char * mandatoryHttpHeaders[], 54 | size_t mandatoryHttpHeaderCount); 55 | 56 | bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false); 57 | bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0); 58 | bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false); 59 | bool sendTXT(uint8_t num, const char * payload, size_t length = 0); 60 | bool sendTXT(uint8_t num, String & payload); 61 | 62 | bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); 63 | bool broadcastTXT(const uint8_t * payload, size_t length = 0); 64 | bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false); 65 | bool broadcastTXT(const char * payload, size_t length = 0); 66 | bool broadcastTXT(String & payload); 67 | 68 | bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false); 69 | bool sendBIN(uint8_t num, const uint8_t * payload, size_t length); 70 | 71 | bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false); 72 | bool broadcastBIN(const uint8_t * payload, size_t length); 73 | 74 | bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0); 75 | bool sendPing(uint8_t num, String & payload); 76 | 77 | bool broadcastPing(uint8_t * payload = NULL, size_t length = 0); 78 | bool broadcastPing(String & payload); 79 | 80 | void disconnect(void); 81 | void disconnect(uint8_t num); 82 | 83 | void setAuthorization(const char * user, const char * password); 84 | void setAuthorization(const char * auth); 85 | 86 | int connectedClients(bool ping = false); 87 | 88 | bool clientIsConnected(uint8_t num); 89 | 90 | void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); 91 | void disableHeartbeat(); 92 | 93 | #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040) 94 | IPAddress remoteIP(uint8_t num); 95 | #endif 96 | 97 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 98 | void loop(void); // handle client data only 99 | #endif 100 | 101 | WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); 102 | 103 | protected: 104 | String _origin; 105 | String _protocol; 106 | String _base64Authorization; ///< Base64 encoded Auth request 107 | String * _mandatoryHttpHeaders; 108 | size_t _mandatoryHttpHeaderCount; 109 | 110 | WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; 111 | 112 | WebSocketServerEvent _cbEvent; 113 | WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc; 114 | 115 | bool _runnning; 116 | 117 | uint32_t _pingInterval; 118 | uint32_t _pongTimeout; 119 | uint8_t _disconnectTimeoutCount; 120 | 121 | void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); 122 | 123 | void clientDisconnect(WSclient_t * client); 124 | bool clientIsConnected(WSclient_t * client); 125 | 126 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 127 | void handleClientData(void); 128 | #endif 129 | 130 | void handleHeader(WSclient_t * client, String * headerLine); 131 | 132 | void handleHBPing(WSclient_t * client); // send ping in specified intervals 133 | 134 | /** 135 | * called if a non Websocket connection is coming in. 136 | * Note: can be override 137 | * @param client WSclient_t * ptr to the client struct 138 | */ 139 | virtual void handleNonWebsocketConnection(WSclient_t * client) { 140 | DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num); 141 | client->tcp->write( 142 | "HTTP/1.1 400 Bad Request\r\n" 143 | "Server: arduino-WebSocket-Server\r\n" 144 | "Content-Type: text/plain\r\n" 145 | "Content-Length: 32\r\n" 146 | "Connection: close\r\n" 147 | "Sec-WebSocket-Version: 13\r\n" 148 | "\r\n" 149 | "This is a Websocket server only!"); 150 | clientDisconnect(client); 151 | } 152 | 153 | /** 154 | * called if a non Authorization connection is coming in. 155 | * Note: can be override 156 | * @param client WSclient_t * ptr to the client struct 157 | */ 158 | virtual void handleAuthorizationFailed(WSclient_t * client) { 159 | client->tcp->write( 160 | "HTTP/1.1 401 Unauthorized\r\n" 161 | "Server: arduino-WebSocket-Server\r\n" 162 | "Content-Type: text/plain\r\n" 163 | "Content-Length: 45\r\n" 164 | "Connection: close\r\n" 165 | "Sec-WebSocket-Version: 13\r\n" 166 | "WWW-Authenticate: Basic realm=\"WebSocket Server\"" 167 | "\r\n" 168 | "This Websocket server requires Authorization!"); 169 | clientDisconnect(client); 170 | } 171 | 172 | /** 173 | * called for sending a Event to the app 174 | * @param num uint8_t 175 | * @param type WStype_t 176 | * @param payload uint8_t * 177 | * @param length size_t 178 | */ 179 | virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 180 | if(_cbEvent) { 181 | _cbEvent(num, type, payload, length); 182 | } 183 | } 184 | 185 | /* 186 | * Called at client socket connect handshake negotiation time for each http header that is not 187 | * a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*) 188 | * If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the 189 | * socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected 190 | * This mechanism can be used to enable custom authentication schemes e.g. test the value 191 | * of a session cookie to determine if a user is logged on / authenticated 192 | */ 193 | virtual bool execHttpHeaderValidation(String headerName, String headerValue) { 194 | if(_httpHeaderValidationFunc) { 195 | // return the value of the custom http header validation function 196 | return _httpHeaderValidationFunc(headerName, headerValue); 197 | } 198 | // no custom http header validation so just assume all is good 199 | return true; 200 | } 201 | 202 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 203 | WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient); 204 | #endif 205 | 206 | /** 207 | * drop native tcp connection (client->tcp) 208 | */ 209 | void dropNativeClient(WSclient_t * client); 210 | 211 | private: 212 | /* 213 | * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection 214 | * @param headerName String ///< the name of the header being checked 215 | */ 216 | bool hasMandatoryHeader(String headerName); 217 | }; 218 | 219 | class WebSocketsServer : public WebSocketsServerCore { 220 | public: 221 | WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino"); 222 | virtual ~WebSocketsServer(void); 223 | 224 | void begin(void); 225 | void close(void); 226 | 227 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 228 | void loop(void); // handle incoming client and client data 229 | #else 230 | // Async interface not need a loop call 231 | void loop(void) __attribute__((deprecated)) {} 232 | #endif 233 | 234 | protected: 235 | #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) 236 | void handleNewClients(void); 237 | #endif 238 | 239 | uint16_t _port; 240 | WEBSOCKETS_NETWORK_SERVER_CLASS * _server; 241 | }; 242 | 243 | #endif /* WEBSOCKETSSERVER_H_ */ 244 | -------------------------------------------------------------------------------- /src/WebSocketsVersion.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WebSocketsVersion.h 3 | * @date 06.09.2024 4 | * @author Markus Sattler 5 | * 6 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 7 | * This file is part of the WebSockets for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef WEBSOCKETSVERSION_H_ 26 | #define WEBSOCKETSVERSION_H_ 27 | 28 | #define WEBSOCKETS_VERSION "2.6.1" 29 | 30 | #define WEBSOCKETS_VERSION_MAJOR 2 31 | #define WEBSOCKETS_VERSION_MINOR 6 32 | #define WEBSOCKETS_VERSION_PATCH 1 33 | 34 | #define WEBSOCKETS_VERSION_INT 2006001 35 | 36 | #endif /* WEBSOCKETSVERSION_H_ */ 37 | -------------------------------------------------------------------------------- /src/libb64/AUTHORS: -------------------------------------------------------------------------------- 1 | libb64: Base64 Encoding/Decoding Routines 2 | ====================================== 3 | 4 | Authors: 5 | ------- 6 | 7 | Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com 8 | -------------------------------------------------------------------------------- /src/libb64/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright-Only Dedication (based on United States law) 2 | or Public Domain Certification 3 | 4 | The person or persons who have associated work with this document (the 5 | "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of 6 | his knowledge, the work of authorship identified is in the public domain of the 7 | country from which the work is published, or (b) hereby dedicates whatever 8 | copyright the dedicators holds in the work of authorship identified below (the 9 | "Work") to the public domain. A certifier, moreover, dedicates any copyright 10 | interest he may have in the associated work, and for these purposes, is 11 | described as a "dedicator" below. 12 | 13 | A certifier has taken reasonable steps to verify the copyright status of this 14 | work. Certifier recognizes that his good faith efforts may not shield him from 15 | liability if in fact the work certified is not in the public domain. 16 | 17 | Dedicator makes this dedication for the benefit of the public at large and to 18 | the detriment of the Dedicator's heirs and successors. Dedicator intends this 19 | dedication to be an overt act of relinquishment in perpetuity of all present 20 | and future rights under copyright law, whether vested or contingent, in the 21 | Work. Dedicator understands that such relinquishment of all rights includes 22 | the relinquishment of all rights to enforce (by lawsuit or otherwise) those 23 | copyrights in the Work. 24 | 25 | Dedicator recognizes that, once placed in the public domain, the Work may be 26 | freely reproduced, distributed, transmitted, used, modified, built upon, or 27 | otherwise exploited by anyone for any purpose, commercial or non-commercial, 28 | and in any way, including by methods that have not yet been invented or 29 | conceived. -------------------------------------------------------------------------------- /src/libb64/cdecode.c: -------------------------------------------------------------------------------- 1 | /* 2 | cdecoder.c - c source to a base64 decoding algorithm implementation 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifdef ESP8266 9 | #include 10 | #endif 11 | 12 | #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0) 13 | #define CORE_HAS_LIBB64 14 | #endif 15 | 16 | #ifndef CORE_HAS_LIBB64 17 | #include "cdecode_inc.h" 18 | 19 | int base64_decode_value(char value_in) 20 | { 21 | static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; 22 | static const char decoding_size = sizeof(decoding); 23 | value_in -= 43; 24 | if (value_in < 0 || value_in > decoding_size) return -1; 25 | return decoding[(int)value_in]; 26 | } 27 | 28 | void base64_init_decodestate(base64_decodestate* state_in) 29 | { 30 | state_in->step = step_a; 31 | state_in->plainchar = 0; 32 | } 33 | 34 | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) 35 | { 36 | const char* codechar = code_in; 37 | char* plainchar = plaintext_out; 38 | char fragment; 39 | 40 | *plainchar = state_in->plainchar; 41 | 42 | switch (state_in->step) 43 | { 44 | while (1) 45 | { 46 | case step_a: 47 | do { 48 | if (codechar == code_in+length_in) 49 | { 50 | state_in->step = step_a; 51 | state_in->plainchar = *plainchar; 52 | return plainchar - plaintext_out; 53 | } 54 | fragment = (char)base64_decode_value(*codechar++); 55 | } while (fragment < 0); 56 | *plainchar = (fragment & 0x03f) << 2; 57 | case step_b: 58 | do { 59 | if (codechar == code_in+length_in) 60 | { 61 | state_in->step = step_b; 62 | state_in->plainchar = *plainchar; 63 | return plainchar - plaintext_out; 64 | } 65 | fragment = (char)base64_decode_value(*codechar++); 66 | } while (fragment < 0); 67 | *plainchar++ |= (fragment & 0x030) >> 4; 68 | *plainchar = (fragment & 0x00f) << 4; 69 | case step_c: 70 | do { 71 | if (codechar == code_in+length_in) 72 | { 73 | state_in->step = step_c; 74 | state_in->plainchar = *plainchar; 75 | return plainchar - plaintext_out; 76 | } 77 | fragment = (char)base64_decode_value(*codechar++); 78 | } while (fragment < 0); 79 | *plainchar++ |= (fragment & 0x03c) >> 2; 80 | *plainchar = (fragment & 0x003) << 6; 81 | case step_d: 82 | do { 83 | if (codechar == code_in+length_in) 84 | { 85 | state_in->step = step_d; 86 | state_in->plainchar = *plainchar; 87 | return plainchar - plaintext_out; 88 | } 89 | fragment = (char)base64_decode_value(*codechar++); 90 | } while (fragment < 0); 91 | *plainchar++ |= (fragment & 0x03f); 92 | } 93 | } 94 | /* control should not reach here */ 95 | return plainchar - plaintext_out; 96 | } 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /src/libb64/cdecode_inc.h: -------------------------------------------------------------------------------- 1 | /* 2 | cdecode.h - c header for a base64 decoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CDECODE_H 9 | #define BASE64_CDECODE_H 10 | 11 | typedef enum 12 | { 13 | step_a, step_b, step_c, step_d 14 | } base64_decodestep; 15 | 16 | typedef struct 17 | { 18 | base64_decodestep step; 19 | char plainchar; 20 | } base64_decodestate; 21 | 22 | void base64_init_decodestate(base64_decodestate* state_in); 23 | 24 | int base64_decode_value(char value_in); 25 | 26 | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); 27 | 28 | #endif /* BASE64_CDECODE_H */ 29 | -------------------------------------------------------------------------------- /src/libb64/cencode.c: -------------------------------------------------------------------------------- 1 | /* 2 | cencoder.c - c source to a base64 encoding algorithm implementation 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifdef ESP8266 9 | #include 10 | #endif 11 | 12 | #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(WIO_TERMINAL) || defined(SEEED_XIAO_M0) 13 | #define CORE_HAS_LIBB64 14 | #endif 15 | 16 | #ifndef CORE_HAS_LIBB64 17 | #include "cencode_inc.h" 18 | 19 | const int CHARS_PER_LINE = 72; 20 | 21 | void base64_init_encodestate(base64_encodestate* state_in) 22 | { 23 | state_in->step = step_A; 24 | state_in->result = 0; 25 | state_in->stepcount = 0; 26 | } 27 | 28 | char base64_encode_value(char value_in) 29 | { 30 | static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 31 | if (value_in > 63) return '='; 32 | return encoding[(int)value_in]; 33 | } 34 | 35 | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) 36 | { 37 | const char* plainchar = plaintext_in; 38 | const char* const plaintextend = plaintext_in + length_in; 39 | char* codechar = code_out; 40 | char result; 41 | char fragment; 42 | 43 | result = state_in->result; 44 | 45 | switch (state_in->step) 46 | { 47 | while (1) 48 | { 49 | case step_A: 50 | if (plainchar == plaintextend) 51 | { 52 | state_in->result = result; 53 | state_in->step = step_A; 54 | return codechar - code_out; 55 | } 56 | fragment = *plainchar++; 57 | result = (fragment & 0x0fc) >> 2; 58 | *codechar++ = base64_encode_value(result); 59 | result = (fragment & 0x003) << 4; 60 | case step_B: 61 | if (plainchar == plaintextend) 62 | { 63 | state_in->result = result; 64 | state_in->step = step_B; 65 | return codechar - code_out; 66 | } 67 | fragment = *plainchar++; 68 | result |= (fragment & 0x0f0) >> 4; 69 | *codechar++ = base64_encode_value(result); 70 | result = (fragment & 0x00f) << 2; 71 | case step_C: 72 | if (plainchar == plaintextend) 73 | { 74 | state_in->result = result; 75 | state_in->step = step_C; 76 | return codechar - code_out; 77 | } 78 | fragment = *plainchar++; 79 | result |= (fragment & 0x0c0) >> 6; 80 | *codechar++ = base64_encode_value(result); 81 | result = (fragment & 0x03f) >> 0; 82 | *codechar++ = base64_encode_value(result); 83 | 84 | ++(state_in->stepcount); 85 | if (state_in->stepcount == CHARS_PER_LINE/4) 86 | { 87 | *codechar++ = '\n'; 88 | state_in->stepcount = 0; 89 | } 90 | } 91 | } 92 | /* control should not reach here */ 93 | return codechar - code_out; 94 | } 95 | 96 | int base64_encode_blockend(char* code_out, base64_encodestate* state_in) 97 | { 98 | char* codechar = code_out; 99 | 100 | switch (state_in->step) 101 | { 102 | case step_B: 103 | *codechar++ = base64_encode_value(state_in->result); 104 | *codechar++ = '='; 105 | *codechar++ = '='; 106 | break; 107 | case step_C: 108 | *codechar++ = base64_encode_value(state_in->result); 109 | *codechar++ = '='; 110 | break; 111 | case step_A: 112 | break; 113 | } 114 | *codechar++ = 0x00; 115 | 116 | return codechar - code_out; 117 | } 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/libb64/cencode_inc.h: -------------------------------------------------------------------------------- 1 | /* 2 | cencode.h - c header for a base64 encoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CENCODE_H 9 | #define BASE64_CENCODE_H 10 | 11 | typedef enum 12 | { 13 | step_A, step_B, step_C 14 | } base64_encodestep; 15 | 16 | typedef struct 17 | { 18 | base64_encodestep step; 19 | char result; 20 | int stepcount; 21 | } base64_encodestate; 22 | 23 | void base64_init_encodestate(base64_encodestate* state_in); 24 | 25 | char base64_encode_value(char value_in); 26 | 27 | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); 28 | 29 | int base64_encode_blockend(char* code_out, base64_encodestate* state_in); 30 | 31 | #endif /* BASE64_CENCODE_H */ 32 | -------------------------------------------------------------------------------- /src/libsha1/libsha1.c: -------------------------------------------------------------------------------- 1 | /* from valgrind tests */ 2 | 3 | /* ================ sha1.c ================ */ 4 | /* 5 | SHA-1 in C 6 | By Steve Reid 7 | 100% Public Domain 8 | 9 | Test Vectors (from FIPS PUB 180-1) 10 | "abc" 11 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 12 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 13 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 14 | A million repetitions of "a" 15 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 16 | */ 17 | 18 | /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ 19 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 20 | 21 | #if !defined(ESP8266) && !defined(ESP32) 22 | 23 | #define SHA1HANDSOFF 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "libsha1.h" 30 | 31 | 32 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 33 | 34 | /* blk0() and blk() perform the initial expand. */ 35 | /* I got the idea of expanding during the round function from SSLeay */ 36 | #if BYTE_ORDER == LITTLE_ENDIAN 37 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ 38 | |(rol(block->l[i],8)&0x00FF00FF)) 39 | #elif BYTE_ORDER == BIG_ENDIAN 40 | #define blk0(i) block->l[i] 41 | #else 42 | #error "Endianness not defined!" 43 | #endif 44 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 45 | ^block->l[(i+2)&15]^block->l[i&15],1)) 46 | 47 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 48 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 49 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 50 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 51 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 52 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 53 | 54 | 55 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 56 | 57 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) 58 | { 59 | uint32_t a, b, c, d, e; 60 | typedef union { 61 | unsigned char c[64]; 62 | uint32_t l[16]; 63 | } CHAR64LONG16; 64 | #ifdef SHA1HANDSOFF 65 | CHAR64LONG16 block[1]; /* use array to appear as a pointer */ 66 | memcpy(block, buffer, 64); 67 | #else 68 | /* The following had better never be used because it causes the 69 | * pointer-to-const buffer to be cast into a pointer to non-const. 70 | * And the result is written through. I threw a "const" in, hoping 71 | * this will cause a diagnostic. 72 | */ 73 | CHAR64LONG16* block = (const CHAR64LONG16*)buffer; 74 | #endif 75 | /* Copy context->state[] to working vars */ 76 | a = state[0]; 77 | b = state[1]; 78 | c = state[2]; 79 | d = state[3]; 80 | e = state[4]; 81 | /* 4 rounds of 20 operations each. Loop unrolled. */ 82 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); 83 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); 84 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); 85 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); 86 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); 87 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); 88 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); 89 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); 90 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); 91 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); 92 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); 93 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); 94 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); 95 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); 96 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); 97 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); 98 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); 99 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); 100 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); 101 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); 102 | /* Add the working vars back into context.state[] */ 103 | state[0] += a; 104 | state[1] += b; 105 | state[2] += c; 106 | state[3] += d; 107 | state[4] += e; 108 | /* Wipe variables */ 109 | a = b = c = d = e = 0; 110 | #ifdef SHA1HANDSOFF 111 | memset(block, '\0', sizeof(block)); 112 | #endif 113 | } 114 | 115 | 116 | /* SHA1Init - Initialize new context */ 117 | 118 | void SHA1Init(SHA1_CTX* context) 119 | { 120 | /* SHA1 initialization constants */ 121 | context->state[0] = 0x67452301; 122 | context->state[1] = 0xEFCDAB89; 123 | context->state[2] = 0x98BADCFE; 124 | context->state[3] = 0x10325476; 125 | context->state[4] = 0xC3D2E1F0; 126 | context->count[0] = context->count[1] = 0; 127 | } 128 | 129 | 130 | /* Run your data through this. */ 131 | 132 | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len) 133 | { 134 | uint32_t i, j; 135 | 136 | j = context->count[0]; 137 | if ((context->count[0] += len << 3) < j) 138 | context->count[1]++; 139 | context->count[1] += (len>>29); 140 | j = (j >> 3) & 63; 141 | if ((j + len) > 63) { 142 | memcpy(&context->buffer[j], data, (i = 64-j)); 143 | SHA1Transform(context->state, context->buffer); 144 | for ( ; i + 63 < len; i += 64) { 145 | SHA1Transform(context->state, &data[i]); 146 | } 147 | j = 0; 148 | } 149 | else i = 0; 150 | memcpy(&context->buffer[j], &data[i], len - i); 151 | } 152 | 153 | 154 | /* Add padding and return the message digest. */ 155 | 156 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context) 157 | { 158 | unsigned i; 159 | unsigned char finalcount[8]; 160 | unsigned char c; 161 | 162 | #if 0 /* untested "improvement" by DHR */ 163 | /* Convert context->count to a sequence of bytes 164 | * in finalcount. Second element first, but 165 | * big-endian order within element. 166 | * But we do it all backwards. 167 | */ 168 | unsigned char *fcp = &finalcount[8]; 169 | 170 | for (i = 0; i < 2; i++) 171 | { 172 | uint32_t t = context->count[i]; 173 | int j; 174 | 175 | for (j = 0; j < 4; t >>= 8, j++) 176 | *--fcp = (unsigned char) t; 177 | } 178 | #else 179 | for (i = 0; i < 8; i++) { 180 | finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] 181 | >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ 182 | } 183 | #endif 184 | c = 0200; 185 | SHA1Update(context, &c, 1); 186 | while ((context->count[0] & 504) != 448) { 187 | c = 0000; 188 | SHA1Update(context, &c, 1); 189 | } 190 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 191 | for (i = 0; i < 20; i++) { 192 | digest[i] = (unsigned char) 193 | ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); 194 | } 195 | /* Wipe variables */ 196 | memset(context, '\0', sizeof(*context)); 197 | memset(&finalcount, '\0', sizeof(finalcount)); 198 | } 199 | /* ================ end of sha1.c ================ */ 200 | 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /src/libsha1/libsha1.h: -------------------------------------------------------------------------------- 1 | /* ================ sha1.h ================ */ 2 | /* 3 | SHA-1 in C 4 | By Steve Reid 5 | 100% Public Domain 6 | */ 7 | 8 | #if !defined(ESP8266) && !defined(ESP32) 9 | 10 | typedef struct { 11 | uint32_t state[5]; 12 | uint32_t count[2]; 13 | unsigned char buffer[64]; 14 | } SHA1_CTX; 15 | 16 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); 17 | void SHA1Init(SHA1_CTX* context); 18 | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); 19 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /tests/webSocket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 40 | 41 | 42 | 43 | LED Control:
44 |
45 | R:
46 | G:
47 | B:
48 | 49 | -------------------------------------------------------------------------------- /tests/webSocketServer/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var WebSocketServer = require('websocket').server; 3 | var http = require('http'); 4 | 5 | var server = http.createServer(function(request, response) { 6 | console.log((new Date()) + ' Received request for ' + request.url); 7 | response.writeHead(404); 8 | response.end(); 9 | }); 10 | server.listen(8011, function() { 11 | console.log((new Date()) + ' Server is listening on port 8011'); 12 | }); 13 | 14 | wsServer = new WebSocketServer({ 15 | httpServer: server, 16 | // You should not use autoAcceptConnections for production 17 | // applications, as it defeats all standard cross-origin protection 18 | // facilities built into the protocol and the browser. You should 19 | // *always* verify the connection's origin and decide whether or not 20 | // to accept it. 21 | autoAcceptConnections: false 22 | }); 23 | 24 | function originIsAllowed(origin) { 25 | // put logic here to detect whether the specified origin is allowed. 26 | return true; 27 | } 28 | 29 | wsServer.on('request', function(request) { 30 | 31 | if (!originIsAllowed(request.origin)) { 32 | // Make sure we only accept requests from an allowed origin 33 | request.reject(); 34 | console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.'); 35 | return; 36 | } 37 | 38 | var connection = request.accept('arduino', request.origin); 39 | console.log((new Date()) + ' Connection accepted.'); 40 | 41 | connection.on('message', function(message) { 42 | if (message.type === 'utf8') { 43 | console.log('Received Message: ' + message.utf8Data); 44 | // connection.sendUTF(message.utf8Data); 45 | } 46 | else if (message.type === 'binary') { 47 | console.log('Received Binary Message of ' + message.binaryData.length + ' bytes'); 48 | //connection.sendBytes(message.binaryData); 49 | } 50 | }); 51 | 52 | connection.on('close', function(reasonCode, description) { 53 | console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); 54 | }); 55 | 56 | connection.sendUTF("Hallo Client!"); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/webSocketServer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webSocketServer", 3 | "version": "1.0.0", 4 | "description": "WebSocketServer for testing", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Links2004/arduinoWebSockets" 12 | }, 13 | "keywords": [ 14 | "esp8266", 15 | "websocket", 16 | "arduino" 17 | ], 18 | "author": "Markus Sattler", 19 | "license": "LGPLv2", 20 | "bugs": { 21 | "url": "https://github.com/Links2004/arduinoWebSockets/issues" 22 | }, 23 | "homepage": "https://github.com/Links2004/arduinoWebSockets", 24 | "dependencies": { 25 | "websocket": "^1.0.18" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /travis/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | function build_sketches() 5 | { 6 | local arduino=$1 7 | local srcpath=$2 8 | local platform=$3 9 | local sketches=$(find $srcpath -name *.ino) 10 | for sketch in $sketches; do 11 | local sketchdir=$(dirname $sketch) 12 | if [[ -f "$sketchdir/.$platform.skip" ]]; then 13 | echo -e "\n\n ------------ Skipping $sketch ------------ \n\n"; 14 | continue 15 | fi 16 | echo -e "\n\n ------------ Building $sketch ------------ \n\n"; 17 | $arduino --verify $sketch; 18 | local result=$? 19 | if [ $result -ne 0 ]; then 20 | echo "Build failed ($sketch) build verbose..." 21 | $arduino --verify --verbose --preserve-temp-files $sketch 22 | result=$? 23 | fi 24 | if [ $result -ne 0 ]; then 25 | echo "Build failed ($1) $sketch" 26 | return $result 27 | fi 28 | done 29 | } 30 | 31 | function build_sketch_cli() 32 | { 33 | local sketch=$1 34 | local board=$2 35 | arduino-cli --log --log-level info compile -b "$board" "$sketch" 36 | result=$? 37 | if [ $result -ne 0 ]; then 38 | echo "Build failed ($sketch) build verbose..." 39 | arduino-cli --log --log-level debug compile -b "$board" "$sketch" 40 | result=$? 41 | fi 42 | if [ $result -ne 0 ]; then 43 | echo "Build failed ($1) $sketch" 44 | return $result 45 | fi 46 | } 47 | 48 | function build_sketch() 49 | { 50 | local arduino=$1 51 | local sketch=$2 52 | $arduino --verify --verbose $sketch; 53 | local result=$? 54 | if [ $result -ne 0 ]; then 55 | echo "Build failed ($sketch) build verbose..." 56 | $arduino --verify --verbose --preserve-temp-files $sketch 57 | result=$? 58 | fi 59 | if [ $result -ne 0 ]; then 60 | echo "Build failed ($1) $sketch" 61 | return $result 62 | fi 63 | } 64 | 65 | function get_sketches_json() 66 | { 67 | local arduino=$1 68 | local srcpath=$2 69 | local platform=$3 70 | local sketches=($(find $srcpath -name *.ino)) 71 | echo -en "[" 72 | for sketch in "${sketches[@]}" ; do 73 | local sketchdir=$(dirname $sketch) 74 | if [[ -f "$sketchdir/.$platform.skip" ]]; then 75 | continue 76 | fi 77 | echo -en "\"$sketch\"" 78 | if [[ $sketch != ${sketches[-1]} ]] ; then 79 | echo -en "," 80 | fi 81 | 82 | done 83 | echo -en "]" 84 | } 85 | 86 | function get_sketches_json_matrix() 87 | { 88 | local arduino=$1 89 | local srcpath=$2 90 | local platform=$3 91 | local cliversion=$4 92 | local board=$5 93 | local sketches=($(find $srcpath -name *.ino)) 94 | for sketch in "${sketches[@]}" ; do 95 | local sketchdir=$(dirname $sketch) 96 | local sketchname=$(basename $sketch) 97 | if [[ -f "$sketchdir/.$platform.skip" ]]; then 98 | continue 99 | fi 100 | echo -en "{\"name\":\"$sketchname\",\"board\":\"$board\",\"cliversion\":\"$cliversion\",\"cpu\":\"$platform\",\"sketch\":\"$sketch\"}" 101 | if [[ $sketch != ${sketches[-1]} ]] ; then 102 | echo -en "," 103 | fi 104 | done 105 | } 106 | 107 | function get_core_cli() { 108 | 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" 109 | arduino-cli core update-index 110 | arduino-cli core install esp8266:esp8266 111 | arduino-cli core install esp32:esp32 112 | arduino-cli core install rp2040:rp2040 113 | } 114 | 115 | function get_core() 116 | { 117 | echo Setup core for $1 118 | 119 | mkdir -p $HOME/arduino_ide/packages/hardware 120 | cd $HOME/arduino_ide/packages/hardware 121 | 122 | if [ "$1" = "esp8266" ] ; then 123 | mkdir esp8266com 124 | cd esp8266com 125 | git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266 126 | cd esp8266/ 127 | git submodule update --init 128 | rm -rf .git 129 | cd tools 130 | python get.py 131 | fi 132 | 133 | if [ "$1" = "esp32" ] ; then 134 | mkdir espressif 135 | cd espressif 136 | git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32 137 | cd esp32/ 138 | rm -rf .git 139 | cd tools 140 | python get.py 141 | fi 142 | 143 | } 144 | 145 | function clone_library() { 146 | local url=$1 147 | echo clone $(basename $url) 148 | mkdir -p $HOME/Arduino/libraries 149 | cd $HOME/Arduino/libraries 150 | git clone --depth 1 $url 151 | rm -rf */.git 152 | rm -rf */.github 153 | rm -rf */examples 154 | } 155 | 156 | function hash_library_names() { 157 | cd $HOME/Arduino/libraries 158 | ls | sha1sum -z | cut -c1-5 159 | } -------------------------------------------------------------------------------- /travis/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import json 4 | import configparser 5 | import argparse 6 | import re 7 | import os 8 | import datetime 9 | 10 | travis_dir = os.path.dirname(os.path.abspath(__file__)) 11 | base_dir = os.path.abspath(travis_dir + "/../") 12 | 13 | def write_header_file(version): 14 | hvs = version.split('.') 15 | intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2]) 16 | now = datetime.datetime.now() 17 | 18 | text = f'''/** 19 | * @file WebSocketsVersion.h 20 | * @date {now.strftime("%d.%m.%Y")} 21 | * @author Markus Sattler 22 | * 23 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 24 | * This file is part of the WebSockets for Arduino. 25 | * 26 | * This library is free software; you can redistribute it and/or 27 | * modify it under the terms of the GNU Lesser General Public 28 | * License as published by the Free Software Foundation; either 29 | * version 2.1 of the License, or (at your option) any later version. 30 | * 31 | * This library is distributed in the hope that it will be useful, 32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 | * Lesser General Public License for more details. 35 | * 36 | * You should have received a copy of the GNU Lesser General Public 37 | * License along with this library; if not, write to the Free Software 38 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 39 | * 40 | */ 41 | 42 | #ifndef WEBSOCKETSVERSION_H_ 43 | #define WEBSOCKETSVERSION_H_ 44 | 45 | #define WEBSOCKETS_VERSION "{version}" 46 | 47 | #define WEBSOCKETS_VERSION_MAJOR {hvs[0]} 48 | #define WEBSOCKETS_VERSION_MINOR {hvs[1]} 49 | #define WEBSOCKETS_VERSION_PATCH {hvs[2]} 50 | 51 | #define WEBSOCKETS_VERSION_INT {intversion} 52 | 53 | #endif /* WEBSOCKETSVERSION_H_ */ 54 | ''' 55 | with open(f'{base_dir}/src/WebSocketsVersion.h', 'w') as f: 56 | f.write(text) 57 | 58 | 59 | def get_library_properties_version(): 60 | library_properties = {} 61 | with open(f'{base_dir}/library.properties', 'r') as f: 62 | library_properties = configparser.ConfigParser() 63 | library_properties.read_string('[root]\n' + f.read()) 64 | return library_properties['root']['version'] 65 | 66 | 67 | def get_library_json_version(): 68 | library_json = {} 69 | with open(f'{base_dir}/library.json', 'r') as f: 70 | library_json = json.load(f) 71 | return library_json['version'] 72 | 73 | 74 | def get_header_versions(): 75 | data = {} 76 | define = re.compile('^#define WEBSOCKETS_VERSION_?(.*) "?([0-9\.]*)"?$') 77 | with open(f'{base_dir}/src/WebSocketsVersion.h', 'r') as f: 78 | for line in f: 79 | m = define.match(line) 80 | if m: 81 | name = m[1] 82 | if name == "": 83 | name = "VERSION" 84 | data[name] = m[2] 85 | return data 86 | 87 | 88 | parser = argparse.ArgumentParser(description='Checks and update Version files') 89 | parser.add_argument( 90 | '--update', action='store_true', default=False) 91 | parser.add_argument( 92 | '--check', action='store_true', default=True) 93 | 94 | args = parser.parse_args() 95 | 96 | if args.update: 97 | library_properties_version = get_library_properties_version() 98 | 99 | with open(f'{base_dir}/library.json', 'r') as f: 100 | library_json = json.load(f) 101 | 102 | library_json['version'] = library_properties_version 103 | 104 | with open(f'{base_dir}/library.json', 'w') as f: 105 | json.dump(library_json, f, indent=4, sort_keys=True) 106 | 107 | write_header_file(library_properties_version) 108 | 109 | 110 | library_json_version = get_library_json_version() 111 | library_properties_version = get_library_properties_version() 112 | header_version = get_header_versions() 113 | 114 | print("WebSocketsVersion.h", header_version) 115 | print(f"library.json: {library_json_version}") 116 | print(f"library.properties: {library_properties_version}") 117 | 118 | if args.check: 119 | if library_json_version != library_properties_version or header_version['VERSION'] != library_properties_version: 120 | raise Exception('versions did not match!') 121 | 122 | hvs = header_version['VERSION'].split('.') 123 | if header_version['MAJOR'] != hvs[0]: 124 | raise Exception('header MAJOR version wrong!') 125 | if header_version['MINOR'] != hvs[1]: 126 | raise Exception('header MINOR version wrong!') 127 | if header_version['PATCH'] != hvs[2]: 128 | raise Exception('header PATCH version wrong!') 129 | 130 | intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2]) 131 | if int(header_version['INT']) != intversion: 132 | raise Exception('header INT version wrong!') 133 | --------------------------------------------------------------------------------