mirror of
https://github.com/Links2004/arduinoWebSockets.git
synced 2025-06-25 23:11:36 +02:00
Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
1fa9a1321c | |||
8fd9c5eff1 | |||
57976f7b51 | |||
5881a99a30 | |||
52b3aa8ea4 | |||
28c0cf3094 | |||
ab9af162b2 | |||
8d76469e90 | |||
61ea44942e | |||
28ed615145 | |||
108090e8cf | |||
46b2ae1c97 | |||
27f86a10ad | |||
860ac9da69 | |||
c897f60567 | |||
b242882ac5 | |||
f8da05aa87 | |||
72aae52655 | |||
a14b6b73b4 | |||
ed685e551f | |||
7c3b1b7408 | |||
738e43fda4 | |||
f55bf8d4ed | |||
a484da47ed | |||
4355199120 | |||
0a4fcd44c2 | |||
3a2b757155 | |||
900d81e534 | |||
0ecef8c552 | |||
410489f7c5 | |||
ec22d67c12 | |||
39e6a8e709 | |||
784b7f9cb8 | |||
fd83d6ad45 | |||
0e729cd896 | |||
2f21590e55 | |||
c98baafda7 | |||
983b9801fb | |||
e70262dab9 | |||
4a05eab627 | |||
822618f606 | |||
1b4f186fa6 | |||
c68e015322 | |||
dc30a2b7bf | |||
6bee53a8bd | |||
ebb87cdc8a | |||
e7ab913693 | |||
52547ec47c | |||
74411bf729 | |||
f0cc36dede |
188
.github/workflows/main.yml
vendored
Normal file
188
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 5'
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
release:
|
||||||
|
types: [ published, created, edited ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
check_version_files:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: check version
|
||||||
|
run: |
|
||||||
|
$GITHUB_WORKSPACE/travis/version.py --check
|
||||||
|
|
||||||
|
prepare_example_json:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: generate examples
|
||||||
|
id: set-matrix
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
echo -en "::set-output name=matrix::"
|
||||||
|
echo -en "["
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.8.19 esp8266com: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
|
||||||
|
echo -en ","
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.8.19 esp8266com: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
|
||||||
|
echo -en ","
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 1.8.19 espressif:esp32:esp32:FlashFreq=80
|
||||||
|
|
||||||
|
echo -en "]"
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
|
||||||
|
prepare_ide:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
IDE_VERSION: [1.8.19]
|
||||||
|
env:
|
||||||
|
IDE_VERSION: ${{ matrix.IDE_VERSION }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get Date
|
||||||
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ matrix.IDE_VERSION }}
|
||||||
|
|
||||||
|
- name: download IDE
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz -q
|
||||||
|
tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
|
mv arduino-$IDE_VERSION $HOME/arduino_ide
|
||||||
|
|
||||||
|
- name: download ArduinoJson
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip -q
|
||||||
|
unzip 6.x.zip
|
||||||
|
mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||||
|
|
||||||
|
- name: download esp8266
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
get_core esp8266
|
||||||
|
|
||||||
|
- name: download esp32
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
get_core esp32
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: [prepare_ide, prepare_example_json]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include: ${{ fromJson(needs.prepare_example_json.outputs.matrix) }}
|
||||||
|
env:
|
||||||
|
CPU: ${{ matrix.cpu }}
|
||||||
|
BOARD: ${{ matrix.board }}
|
||||||
|
IDE_VERSION: ${{ matrix.ideversion }}
|
||||||
|
SKETCH: ${{ matrix.sketch }}
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: install libgtk2.0-0
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y libgtk2.0-0
|
||||||
|
|
||||||
|
- name: Get Date
|
||||||
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ matrix.ideversion }}
|
||||||
|
|
||||||
|
- name: install python serial
|
||||||
|
if: matrix.cpu == 'esp32'
|
||||||
|
run: |
|
||||||
|
sudo pip3 install pyserial
|
||||||
|
sudo pip install pyserial
|
||||||
|
# sudo apt install python-is-python3
|
||||||
|
|
||||||
|
- name: start DISPLAY
|
||||||
|
run: |
|
||||||
|
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
- name: test IDE
|
||||||
|
run: |
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
which arduino
|
||||||
|
|
||||||
|
- name: copy code
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries/
|
||||||
|
cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
|
|
||||||
|
- name: config IDE
|
||||||
|
run: |
|
||||||
|
set +x
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
arduino --board $BOARD --save-prefs
|
||||||
|
arduino --pref update.check=false --pref build.verbose=false --pref cache.enable=true --pref compiler.cache_core=true --pref compiler.warning_level=default --save-prefs
|
||||||
|
arduino --get-pref sketchbook.path
|
||||||
|
arduino --get-pref
|
||||||
|
|
||||||
|
- name: build example
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: |
|
||||||
|
set -ex
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
build_sketch arduino $SKETCH
|
||||||
|
|
||||||
|
done:
|
||||||
|
needs: [prepare_ide, prepare_example_json, build, check_version_files]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Done
|
||||||
|
run: |
|
||||||
|
echo DONE
|
@ -1,4 +1,4 @@
|
|||||||
WebSocket Server and Client for Arduino [](https://travis-ci.com/Links2004/arduinoWebSockets)
|
WebSocket Server and Client for Arduino [](https://github.com/Links2004/arduinoWebSockets/actions?query=workflow%3ACI+branch%3Amaster)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
a WebSocket Server and Client for Arduino based on RFC6455.
|
a WebSocket Server and Client for Arduino based on RFC6455.
|
||||||
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSocketIOack.ino
|
||||||
|
*
|
||||||
|
* Created on: 20.07.2019
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
#include <SocketIOclient.h>
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
SocketIOclient socketIO;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
|
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
|
break;
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
{
|
||||||
|
char * sptr = NULL;
|
||||||
|
int id = strtol((char *)payload, &sptr, 10);
|
||||||
|
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
|
||||||
|
if(id) {
|
||||||
|
payload = (uint8_t *)sptr;
|
||||||
|
}
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
DeserializationError error = deserializeJson(doc, payload, length);
|
||||||
|
if(error) {
|
||||||
|
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||||
|
USE_SERIAL.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String eventName = doc[0];
|
||||||
|
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
||||||
|
|
||||||
|
// Message Includes a ID for a ACK (callback)
|
||||||
|
if(id) {
|
||||||
|
// creat JSON message for Socket.IO (ack)
|
||||||
|
DynamicJsonDocument docOut(1024);
|
||||||
|
JsonArray array = docOut.to<JsonArray>();
|
||||||
|
|
||||||
|
// add payload (parameters) for the ack (callback function)
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = millis();
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
output += id;
|
||||||
|
serializeJson(docOut, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.send(sIOtype_ACK, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case sIOtype_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
//USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = WiFi.localIP().toString();
|
||||||
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
socketIO.onEvent(socketIOEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long messageTimestamp = 0;
|
||||||
|
void loop() {
|
||||||
|
socketIO.loop();
|
||||||
|
|
||||||
|
uint64_t now = millis();
|
||||||
|
|
||||||
|
if(now - messageTimestamp > 2000) {
|
||||||
|
messageTimestamp = now;
|
||||||
|
|
||||||
|
// creat JSON message for Socket.IO (event)
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
|
// add evnet name
|
||||||
|
// Hint: socket.on('event_name', ....
|
||||||
|
array.add("event_name");
|
||||||
|
|
||||||
|
// add payload (parameters) for the event
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = (uint32_t) now;
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
|
// Print JSON for debugging
|
||||||
|
USE_SERIAL.println(output);
|
||||||
|
}
|
||||||
|
}
|
27
examples/esp8266/WebSocketClientOTA/README.md
Normal file
27
examples/esp8266/WebSocketClientOTA/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
## Minimal example of WebsocketClientOTA and Python server
|
||||||
|
|
||||||
|
Take this as small example, how achieve OTA update on ESP8266 and ESP32.
|
||||||
|
|
||||||
|
Python server was wrote from train so take it only as bare example.
|
||||||
|
It's working, but it's not mean to run in production.
|
||||||
|
|
||||||
|
|
||||||
|
### Usage:
|
||||||
|
|
||||||
|
Start server:
|
||||||
|
```bash
|
||||||
|
cd python_ota_server
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Flash ESP with example sketch and start it.
|
||||||
|
|
||||||
|
Change version inside example sketch to higher and compile it and save it to bin file.
|
||||||
|
|
||||||
|
Rename it to `mydevice-1.0.1-esp8266.bin` and place it inside new folder firmware (server create it).
|
||||||
|
|
||||||
|
When the ESP connect to server, it check if version flashed is equal to fw in firmware folder. If higher FW version is present,
|
||||||
|
start the flash process.
|
263
examples/esp8266/WebSocketClientOTA/WebSocketClientOTA.ino
Normal file
263
examples/esp8266/WebSocketClientOTA/WebSocketClientOTA.ino
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientOTA.ino
|
||||||
|
*
|
||||||
|
* Created on: 25.10.2021
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <Updater.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
#include "WiFi.h"
|
||||||
|
#include "ESPmDNS.h"
|
||||||
|
#include <Update.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
// Variables:
|
||||||
|
// Settable:
|
||||||
|
const char *version = "1.0.0";
|
||||||
|
const char *name = "mydevice";
|
||||||
|
|
||||||
|
// Others:
|
||||||
|
#ifdef ESP8266
|
||||||
|
const char *chip = "esp8266";
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
const char *chip = "esp32";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t maxSketchSpace = 0;
|
||||||
|
int SketchSize = 0;
|
||||||
|
bool ws_conn = false;
|
||||||
|
|
||||||
|
String IpAddress2String(const IPAddress& ipAddress)
|
||||||
|
{
|
||||||
|
return String(ipAddress[0]) + String(".") +
|
||||||
|
String(ipAddress[1]) + String(".") +
|
||||||
|
String(ipAddress[2]) + String(".") +
|
||||||
|
String(ipAddress[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void greetings_(){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
doc["type"] = "greetings";
|
||||||
|
doc["mac"] = WiFi.macAddress();
|
||||||
|
doc["ip"] = IpAddress2String(WiFi.localIP());
|
||||||
|
doc["version"] = version;
|
||||||
|
doc["name"] = name;
|
||||||
|
doc["chip"] = chip;
|
||||||
|
|
||||||
|
char data[200];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
webSocket.sendTXT(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_(){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
doc["type"] = "register";
|
||||||
|
doc["mac"] = WiFi.macAddress();
|
||||||
|
|
||||||
|
char data[200];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
webSocket.sendTXT(data);
|
||||||
|
ws_conn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*CALLBACK_FUNCTION)(JsonDocument &msg);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char type[50];
|
||||||
|
CALLBACK_FUNCTION func;
|
||||||
|
} RESPONSES_STRUCT;
|
||||||
|
|
||||||
|
void OTA(JsonDocument &msg){
|
||||||
|
USE_SERIAL.print(F("[WSc] OTA mode: "));
|
||||||
|
const char* go = "go";
|
||||||
|
const char* ok = "ok";
|
||||||
|
if(strncmp( msg["value"], go, strlen(go)) == 0 ) {
|
||||||
|
USE_SERIAL.print(F("go\n"));
|
||||||
|
SketchSize = int(msg["size"]);
|
||||||
|
maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
USE_SERIAL.printf("[WSc] Max sketch size: %u\n", maxSketchSpace);
|
||||||
|
USE_SERIAL.printf("[WSc] Sketch size: %d\n", SketchSize);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
if (!Update.begin(maxSketchSpace)) { //start with max available size
|
||||||
|
Update.printError(Serial);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
} else if (strncmp( msg["value"], ok, strlen(ok)) == 0) {
|
||||||
|
USE_SERIAL.print(F("OK\n"));
|
||||||
|
register_();
|
||||||
|
} else {
|
||||||
|
USE_SERIAL.print(F("unknown value : "));
|
||||||
|
USE_SERIAL.print(msg["value"].as<char>());
|
||||||
|
USE_SERIAL.print(F("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void STATE(JsonDocument &msg){
|
||||||
|
// Do something with message
|
||||||
|
}
|
||||||
|
|
||||||
|
RESPONSES_STRUCT responses[] = {
|
||||||
|
{"ota", OTA},
|
||||||
|
{"state", STATE},
|
||||||
|
};
|
||||||
|
|
||||||
|
void text(uint8_t * payload, size_t length){
|
||||||
|
// Convert mesage to something usable
|
||||||
|
char msgch[length];
|
||||||
|
for (unsigned int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
USE_SERIAL.print((char)payload[i]);
|
||||||
|
msgch[i] = ((char)payload[i]);
|
||||||
|
}
|
||||||
|
msgch[length] = '\0';
|
||||||
|
|
||||||
|
// Parse Json
|
||||||
|
StaticJsonDocument<200> doc_in;
|
||||||
|
DeserializationError error = deserializeJson(doc_in, msgch);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||||
|
USE_SERIAL.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle each TYPE of message
|
||||||
|
int b = 0;
|
||||||
|
|
||||||
|
for( b=0 ; strlen(responses[b].type) ; b++ )
|
||||||
|
{
|
||||||
|
if( strncmp(doc_in["type"], responses[b].type, strlen(responses[b].type)) == 0 ) {
|
||||||
|
responses[b].func(doc_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
// webSocket.sendTXT("Connected");
|
||||||
|
greetings_();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
text(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
// hexdump(payload, length);
|
||||||
|
if (Update.write(payload, length) != length) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
SketchSize -= length;
|
||||||
|
USE_SERIAL.printf("[WSc] Sketch size left: %u\n", SketchSize);
|
||||||
|
if (SketchSize < 1){
|
||||||
|
if (Update.end(true)) { //true to set the size to the current progress
|
||||||
|
USE_SERIAL.printf("Update Success: \nRebooting...\n");
|
||||||
|
delay(5);
|
||||||
|
yield();
|
||||||
|
ESP.restart();
|
||||||
|
} else {
|
||||||
|
Update.printError(USE_SERIAL);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
USE_SERIAL.setDebugOutput(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_PING:
|
||||||
|
// pong will be send automatically
|
||||||
|
USE_SERIAL.printf("[WSc] get ping\n");
|
||||||
|
break;
|
||||||
|
case WStype_PONG:
|
||||||
|
// answer to a ping we send
|
||||||
|
USE_SERIAL.printf("[WSc] get pong\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.print(F("\nMAC: "));
|
||||||
|
USE_SERIAL.println(WiFi.macAddress());
|
||||||
|
USE_SERIAL.print(F("\nDevice: "));
|
||||||
|
USE_SERIAL.println(name);
|
||||||
|
USE_SERIAL.printf("\nVersion: %s\n", version);
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "PASS");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("10.0.1.5", 8081, "/");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional remove if not needed
|
||||||
|
// webSocket.setAuthorization("USER", "PASS");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
|
||||||
|
// start heartbeat (optional)
|
||||||
|
// ping server every 15000 ms
|
||||||
|
// expect pong from server within 3000 ms
|
||||||
|
// consider connection disconnected if pong is not received 2 times
|
||||||
|
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
235
examples/esp8266/WebSocketClientOTA/python_ota_server/main.py
Normal file
235
examples/esp8266/WebSocketClientOTA/python_ota_server/main.py
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
"""Minimal example of Python websocket server
|
||||||
|
handling OTA updates for ESP32 amd ESP8266
|
||||||
|
|
||||||
|
Check and upload of firmware works.
|
||||||
|
Register and state function are jus for example.
|
||||||
|
"""
|
||||||
|
# pylint: disable=W0703,E1101
|
||||||
|
import asyncio
|
||||||
|
import copy
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from os import listdir
|
||||||
|
from os.path import join as join_pth
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import websockets
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
|
# Logger settings
|
||||||
|
logging.basicConfig(filename="ws_server.log")
|
||||||
|
Logger = logging.getLogger('WS-OTA')
|
||||||
|
Logger.addHandler(logging.StreamHandler())
|
||||||
|
Logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Path to directory with FW
|
||||||
|
fw_path = join_pth(Path().absolute(), "firmware")
|
||||||
|
|
||||||
|
|
||||||
|
def create_path(path: str) -> None:
|
||||||
|
"""Check if path exist or create it"""
|
||||||
|
Path(path).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def shell(command):
|
||||||
|
"""Handle execution of shell commands"""
|
||||||
|
with subprocess.Popen(command, shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
universal_newlines=True
|
||||||
|
) as process:
|
||||||
|
for stdout_line in iter(process.stdout.readline, ""):
|
||||||
|
Logger.debug(stdout_line)
|
||||||
|
process.stdout.close()
|
||||||
|
return_code = process.wait()
|
||||||
|
Logger.debug("Shell returned: %s", return_code)
|
||||||
|
|
||||||
|
return process.returncode
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def binary_send(websocket, fw_file):
|
||||||
|
"""Read firmware file, divide it to chunks and send them"""
|
||||||
|
with open(fw_file, "rb") as binaryfile:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
chunk = binaryfile.read(2048)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
await websocket.send(chunk)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.exception(exception)
|
||||||
|
return False
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
def version_checker(name, vdev, vapp):
|
||||||
|
"""Parse and compare FW version"""
|
||||||
|
|
||||||
|
if version.parse(vdev) < version.parse(vapp):
|
||||||
|
Logger.info("Client(%s) version %s is smaller than %s: Go for update", name, vdev, vapp)
|
||||||
|
return True
|
||||||
|
Logger.info("Client(%s) version %s is greater or equal to %s: Not updating", name, vdev, vapp)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class WsOtaHandler (threading.Thread):
|
||||||
|
"""Thread handling ota update
|
||||||
|
|
||||||
|
Runing ota directly from message would kill WS
|
||||||
|
as message bus would timeout.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, message, websocket):
|
||||||
|
threading.Thread.__init__(self, daemon=True)
|
||||||
|
self.name = name
|
||||||
|
self.msg = message
|
||||||
|
self.websocket = websocket
|
||||||
|
|
||||||
|
def run(self, ):
|
||||||
|
try:
|
||||||
|
asyncio.run(self.start_)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.exception(exception)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def start_(self):
|
||||||
|
"""Start _ota se asyncio future"""
|
||||||
|
msg_task = asyncio.ensure_future(
|
||||||
|
self._ota())
|
||||||
|
|
||||||
|
done, pending = await asyncio.wait(
|
||||||
|
[msg_task],
|
||||||
|
return_when=asyncio.FIRST_COMPLETED,
|
||||||
|
)
|
||||||
|
Logger.info("WS Ota Handler done: %s", done)
|
||||||
|
for task in pending:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
async def _ota(self):
|
||||||
|
"""Check for new fw and update or pass"""
|
||||||
|
device_name = self.msg['name']
|
||||||
|
device_chip = self.msg['chip']
|
||||||
|
device_version = self.msg['version']
|
||||||
|
fw_version = ''
|
||||||
|
fw_name = ''
|
||||||
|
fw_device = ''
|
||||||
|
|
||||||
|
for filename in listdir(fw_path):
|
||||||
|
fw_info = filename.split("-")
|
||||||
|
fw_device = fw_info[0]
|
||||||
|
if fw_device == device_name:
|
||||||
|
fw_version = fw_info[1]
|
||||||
|
fw_name = filename
|
||||||
|
break
|
||||||
|
|
||||||
|
if not fw_version:
|
||||||
|
Logger.info("Client(%s): No fw found!", device_name)
|
||||||
|
msg = '{"type": "ota", "value":"ok"}'
|
||||||
|
await self.websocket.send(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not version_checker(device_name, device_version, fw_version):
|
||||||
|
return
|
||||||
|
|
||||||
|
fw_file = join_pth(fw_path, fw_name)
|
||||||
|
if device_chip == 'esp8266' and not fw_file.endswith('.gz'):
|
||||||
|
# We can compress fw to make it smaller for upload
|
||||||
|
fw_cpress = fw_file
|
||||||
|
fw_file = fw_cpress + ".gz"
|
||||||
|
cpress = f"gzip -9 {fw_cpress}"
|
||||||
|
cstate = shell(cpress)
|
||||||
|
if cstate:
|
||||||
|
Logger.error("Cannot compress firmware: %s", fw_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get size of fw
|
||||||
|
size = Path(fw_file).stat().st_size
|
||||||
|
|
||||||
|
# Request ota mode
|
||||||
|
msg = '{"type": "ota", "value":"go", "size":' + str(size) + '}'
|
||||||
|
await self.websocket.send(msg)
|
||||||
|
|
||||||
|
# send file by chunks trough websocket
|
||||||
|
await binary_send(self.websocket, fw_file)
|
||||||
|
|
||||||
|
|
||||||
|
async def _register(websocket, message):
|
||||||
|
mac = message.get('mac')
|
||||||
|
name = message.get('name')
|
||||||
|
Logger.info("Client(%s) mac: %s", name, mac)
|
||||||
|
# Some code
|
||||||
|
|
||||||
|
response = {'response_type': 'registry', 'state': 'ok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _state(websocket, message):
|
||||||
|
mac = message.get('mac')
|
||||||
|
name = message.get('name')
|
||||||
|
Logger.info("Client(%s) mac: %s", name, mac)
|
||||||
|
# Some code
|
||||||
|
|
||||||
|
response = {'response_type': 'state', 'state': 'ok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _unhandleld(websocket, msg):
|
||||||
|
Logger.info("Unhandled message from device: %s", str(msg))
|
||||||
|
response = {'response_type': 'response', 'state': 'nok'}
|
||||||
|
await websocket.send(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
async def _greetings(websocket, message):
|
||||||
|
WsOtaHandler('thread_ota', copy.deepcopy(message), websocket).start()
|
||||||
|
|
||||||
|
|
||||||
|
async def message_received(websocket, message) -> None:
|
||||||
|
"""Handle incoming messages
|
||||||
|
|
||||||
|
Check if message contain json and run waned function
|
||||||
|
"""
|
||||||
|
switcher = {"greetings": _greetings,
|
||||||
|
"register": _register,
|
||||||
|
"state": _state
|
||||||
|
}
|
||||||
|
|
||||||
|
if message[0:1] == "{":
|
||||||
|
try:
|
||||||
|
msg_json = json.loads(message)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.error(exception)
|
||||||
|
return
|
||||||
|
|
||||||
|
type_ = msg_json.get('type')
|
||||||
|
name = msg_json.get('name')
|
||||||
|
func = switcher.get(type_, _unhandleld)
|
||||||
|
Logger.debug("Client(%s)said: %s", name, type_)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await func(websocket, msg_json)
|
||||||
|
except Exception as exception:
|
||||||
|
Logger.error(exception)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=W0613
|
||||||
|
async def ws_server(websocket, path) -> None:
|
||||||
|
"""Run in cycle and wait for new messages"""
|
||||||
|
async for message in websocket:
|
||||||
|
await message_received(websocket, message)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Server starter
|
||||||
|
|
||||||
|
Normal user can bind only port nubers greater than 1024
|
||||||
|
"""
|
||||||
|
async with websockets.serve(ws_server, "10.0.1.5", 8081):
|
||||||
|
await asyncio.Future() # run forever
|
||||||
|
|
||||||
|
|
||||||
|
create_path(fw_path)
|
||||||
|
asyncio.run(main())
|
@ -0,0 +1,2 @@
|
|||||||
|
packaging
|
||||||
|
websockets
|
@ -88,7 +88,7 @@ void setup() {
|
|||||||
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
// server address, port and URL
|
// server address, port and URL
|
||||||
socketIO.begin("10.11.100.100", 8880);
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
// event handler
|
// event handler
|
||||||
socketIO.onEvent(socketIOEvent);
|
socketIO.onEvent(socketIOEvent);
|
||||||
@ -106,7 +106,7 @@ void loop() {
|
|||||||
// creat JSON message for Socket.IO (event)
|
// creat JSON message for Socket.IO (event)
|
||||||
DynamicJsonDocument doc(1024);
|
DynamicJsonDocument doc(1024);
|
||||||
JsonArray array = doc.to<JsonArray>();
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
// add evnet name
|
// add evnet name
|
||||||
// Hint: socket.on('event_name', ....
|
// Hint: socket.on('event_name', ....
|
||||||
array.add("event_name");
|
array.add("event_name");
|
||||||
@ -119,7 +119,7 @@ void loop() {
|
|||||||
String output;
|
String output;
|
||||||
serializeJson(doc, output);
|
serializeJson(doc, output);
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
socketIO.sendEVENT(output);
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
// Print JSON for debugging
|
// Print JSON for debugging
|
||||||
|
@ -49,7 +49,7 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
|
|||||||
USE_SERIAL.println(error.c_str());
|
USE_SERIAL.println(error.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String eventName = doc[0];
|
String eventName = doc[0];
|
||||||
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
|
|||||||
// creat JSON message for Socket.IO (ack)
|
// creat JSON message for Socket.IO (ack)
|
||||||
DynamicJsonDocument docOut(1024);
|
DynamicJsonDocument docOut(1024);
|
||||||
JsonArray array = docOut.to<JsonArray>();
|
JsonArray array = docOut.to<JsonArray>();
|
||||||
|
|
||||||
// add payload (parameters) for the ack (callback function)
|
// add payload (parameters) for the ack (callback function)
|
||||||
JsonObject param1 = array.createNestedObject();
|
JsonObject param1 = array.createNestedObject();
|
||||||
param1["now"] = millis();
|
param1["now"] = millis();
|
||||||
@ -68,7 +68,7 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
|
|||||||
output += id;
|
output += id;
|
||||||
serializeJson(docOut, output);
|
serializeJson(docOut, output);
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
socketIO.send(sIOtype_ACK, output);
|
socketIO.send(sIOtype_ACK, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ void setup() {
|
|||||||
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
// server address, port and URL
|
// server address, port and URL
|
||||||
socketIO.begin("10.11.100.100", 8880);
|
socketIO.begin("10.11.100.100", 8880, "/socket.io/?EIO=4");
|
||||||
|
|
||||||
// event handler
|
// event handler
|
||||||
socketIO.onEvent(socketIOEvent);
|
socketIO.onEvent(socketIOEvent);
|
||||||
@ -143,7 +143,7 @@ void loop() {
|
|||||||
// creat JSON message for Socket.IO (event)
|
// creat JSON message for Socket.IO (event)
|
||||||
DynamicJsonDocument doc(1024);
|
DynamicJsonDocument doc(1024);
|
||||||
JsonArray array = doc.to<JsonArray>();
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
// add evnet name
|
// add evnet name
|
||||||
// Hint: socket.on('event_name', ....
|
// Hint: socket.on('event_name', ....
|
||||||
array.add("event_name");
|
array.add("event_name");
|
||||||
@ -156,7 +156,7 @@ void loop() {
|
|||||||
String output;
|
String output;
|
||||||
serializeJson(doc, output);
|
serializeJson(doc, output);
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
socketIO.sendEVENT(output);
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
// Print JSON for debugging
|
// Print JSON for debugging
|
||||||
|
26
library.json
26
library.json
@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "WebSockets",
|
|
||||||
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
|
||||||
"keywords": "wifi, http, web, server, client, websocket",
|
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
"maintainer": true,
|
||||||
"name": "Markus Sattler",
|
"name": "Markus Sattler",
|
||||||
"url": "https://github.com/Links2004",
|
"url": "https://github.com/Links2004"
|
||||||
"maintainer": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"repository": {
|
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
|
||||||
},
|
|
||||||
"version": "2.3.1",
|
|
||||||
"license": "LGPL-2.1",
|
|
||||||
"export": {
|
"export": {
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"tests"
|
"tests"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": "atmelavr, espressif8266, espressif32"
|
"keywords": "wifi, http, web, server, client, websocket",
|
||||||
}
|
"license": "LGPL-2.1",
|
||||||
|
"name": "WebSockets",
|
||||||
|
"platforms": "atmelavr, espressif8266, espressif32",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
||||||
|
},
|
||||||
|
"version": "2.3.7"
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
name=WebSockets
|
name=WebSockets
|
||||||
version=2.3.1
|
version=2.3.7
|
||||||
author=Markus Sattler
|
author=Markus Sattler
|
||||||
maintainer=Markus Sattler
|
maintainer=Markus Sattler
|
||||||
sentence=WebSockets for Arduino (Server + Client)
|
sentence=WebSockets for Arduino (Server + Client)
|
||||||
|
@ -18,31 +18,37 @@ SocketIOclient::~SocketIOclient() {
|
|||||||
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
|
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
|
||||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) {
|
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) {
|
||||||
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
#if !defined(SSL_AXTLS)
|
#if defined(SSL_BARESSL)
|
||||||
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||||
@ -55,6 +61,18 @@ void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void SocketIOclient::configureEIOping(bool disableHeartbeat) {
|
||||||
|
_disableHeartbeat = disableHeartbeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::initClient(void) {
|
||||||
|
if(_client.cUrl.indexOf("EIO=4") != -1) {
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n");
|
||||||
|
configureEIOping(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set callback function
|
* set callback function
|
||||||
* @param cbEvent SocketIOclientEvent
|
* @param cbEvent SocketIOclientEvent
|
||||||
@ -67,6 +85,14 @@ bool SocketIOclient::isConnected(void) {
|
|||||||
return WebSocketsClient::isConnected();
|
return WebSocketsClient::isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setExtraHeaders(const char * extraHeaders) {
|
||||||
|
return WebSocketsClient::setExtraHeaders(extraHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setReconnectInterval(unsigned long time) {
|
||||||
|
return WebSocketsClient::setReconnectInterval(time);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send text data to client
|
* send text data to client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
@ -148,8 +174,8 @@ bool SocketIOclient::sendEVENT(String & payload) {
|
|||||||
void SocketIOclient::loop(void) {
|
void SocketIOclient::loop(void) {
|
||||||
WebSocketsClient::loop();
|
WebSocketsClient::loop();
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) {
|
if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) {
|
||||||
_lastConnectionFail = t;
|
_lastHeartbeat = t;
|
||||||
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
||||||
WebSocketsClient::sendTXT(eIOtype_PING);
|
WebSocketsClient::sendTXT(eIOtype_PING);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define SOCKETIOCLIENT_H_
|
#define SOCKETIOCLIENT_H_
|
||||||
|
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
#include "WebSocketsClient.h"
|
||||||
|
|
||||||
#define EIO_HEARTBEAT_INTERVAL 20000
|
#define EIO_HEARTBEAT_INTERVAL 20000
|
||||||
|
|
||||||
@ -75,9 +76,15 @@ class SocketIOclient : protected WebSocketsClient {
|
|||||||
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
||||||
bool send(socketIOmessageType_t type, String & payload);
|
bool send(socketIOmessageType_t type, String & payload);
|
||||||
|
|
||||||
|
void setExtraHeaders(const char * extraHeaders = NULL);
|
||||||
|
void setReconnectInterval(unsigned long time);
|
||||||
|
|
||||||
void loop(void);
|
void loop(void);
|
||||||
|
|
||||||
|
void configureEIOping(bool disableHeartbeat = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool _disableHeartbeat = false;
|
||||||
uint64_t _lastHeartbeat = 0;
|
uint64_t _lastHeartbeat = 0;
|
||||||
SocketIOclientEvent _cbEvent;
|
SocketIOclientEvent _cbEvent;
|
||||||
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
@ -86,6 +93,8 @@ class SocketIOclient : protected WebSocketsClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initClient(void);
|
||||||
|
|
||||||
// Handeling events from websocket layer
|
// Handeling events from websocket layer
|
||||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
handleCbEvent(type, payload, length);
|
handleCbEvent(type, payload, length);
|
||||||
|
@ -42,7 +42,11 @@ extern "C" {
|
|||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
|
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||||
|
#if(ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(1, 0, 6))
|
||||||
|
#include "sha/sha_parallel_engine.h"
|
||||||
|
#else
|
||||||
#include <esp32/sha.h>
|
#include <esp32/sha.h>
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <hwcrypto/sha.h>
|
#include <hwcrypto/sha.h>
|
||||||
#endif
|
#endif
|
||||||
@ -468,7 +472,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
payload[header->payloadLen] = 0x00;
|
payload[header->payloadLen] = 0x00;
|
||||||
|
|
||||||
if(header->mask) {
|
if(header->mask) {
|
||||||
//decode XOR
|
// decode XOR
|
||||||
for(size_t i = 0; i < header->payloadLen; i++) {
|
for(size_t i = 0; i < header->payloadLen; i++) {
|
||||||
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
||||||
}
|
}
|
||||||
@ -522,7 +526,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
// reset input
|
// reset input
|
||||||
client->cWsRXsize = 0;
|
client->cWsRXsize = 0;
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
//register callback for next message
|
// register callback for next message
|
||||||
handleWebsocketWaitFor(client, 2);
|
handleWebsocketWaitFor(client, 2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -640,9 +644,9 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
t = millis();
|
t = millis();
|
||||||
out += len;
|
out += len;
|
||||||
n -= len;
|
n -= len;
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
} else {
|
} else {
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
}
|
}
|
||||||
if(n > 0) {
|
if(n > 0) {
|
||||||
WEBSOCKETS_YIELD();
|
WEBSOCKETS_YIELD();
|
||||||
@ -694,7 +698,7 @@ size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
|
|||||||
out += len;
|
out += len;
|
||||||
n -= len;
|
n -= len;
|
||||||
total += len;
|
total += len;
|
||||||
//DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
// DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n);
|
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n);
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "WebSocketsVersion.h"
|
||||||
|
|
||||||
#ifndef NODEBUG_WEBSOCKETS
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
#ifdef DEBUG_ESP_PORT
|
#ifdef DEBUG_ESP_PORT
|
||||||
#define DEBUG_WEBSOCKETS(...) \
|
#define DEBUG_WEBSOCKETS(...) \
|
||||||
@ -84,7 +86,7 @@
|
|||||||
#define WEBSOCKETS_YIELD_MORE()
|
#define WEBSOCKETS_YIELD_MORE()
|
||||||
#else
|
#else
|
||||||
|
|
||||||
//atmega328p has only 2KB ram!
|
// atmega328p has only 2KB ram!
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
||||||
// moves all Header strings to Flash
|
// moves all Header strings to Flash
|
||||||
#define WEBSOCKETS_SAVE_RAM
|
#define WEBSOCKETS_SAVE_RAM
|
||||||
@ -259,34 +261,44 @@ typedef struct {
|
|||||||
} WSMessageHeader_t;
|
} WSMessageHeader_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num; ///< connection number
|
void init(uint8_t num,
|
||||||
|
uint32_t pingInterval,
|
||||||
|
uint32_t pongTimeout,
|
||||||
|
uint8_t disconnectTimeoutCount) {
|
||||||
|
this->num = num;
|
||||||
|
this->pingInterval = pingInterval;
|
||||||
|
this->pongTimeout = pongTimeout;
|
||||||
|
this->disconnectTimeoutCount = disconnectTimeoutCount;
|
||||||
|
}
|
||||||
|
|
||||||
WSclientsStatus_t status;
|
uint8_t num = 0; ///< connection number
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcp;
|
WSclientsStatus_t status = WSC_NOT_CONNECTED;
|
||||||
|
|
||||||
bool isSocketIO; ///< client for socket.io server
|
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr;
|
||||||
|
|
||||||
|
bool isSocketIO = false; ///< client for socket.io server
|
||||||
|
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
bool isSSL; ///< run in ssl mode
|
bool isSSL = false; ///< run in ssl mode
|
||||||
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String cUrl; ///< http url
|
String cUrl; ///< http url
|
||||||
uint16_t cCode; ///< http code
|
uint16_t cCode = 0; ///< http code
|
||||||
|
|
||||||
bool cIsClient = false; ///< will be used for masking
|
bool cIsClient = false; ///< will be used for masking
|
||||||
bool cIsUpgrade; ///< Connection == Upgrade
|
bool cIsUpgrade = false; ///< Connection == Upgrade
|
||||||
bool cIsWebsocket; ///< Upgrade == websocket
|
bool cIsWebsocket = false; ///< Upgrade == websocket
|
||||||
|
|
||||||
String cSessionId; ///< client Set-Cookie (session id)
|
String cSessionId; ///< client Set-Cookie (session id)
|
||||||
String cKey; ///< client Sec-WebSocket-Key
|
String cKey; ///< client Sec-WebSocket-Key
|
||||||
String cAccept; ///< client Sec-WebSocket-Accept
|
String cAccept; ///< client Sec-WebSocket-Accept
|
||||||
String cProtocol; ///< client Sec-WebSocket-Protocol
|
String cProtocol; ///< client Sec-WebSocket-Protocol
|
||||||
String cExtensions; ///< client Sec-WebSocket-Extensions
|
String cExtensions; ///< client Sec-WebSocket-Extensions
|
||||||
uint16_t cVersion; ///< client Sec-WebSocket-Version
|
uint16_t cVersion = 0; ///< client Sec-WebSocket-Version
|
||||||
|
|
||||||
uint8_t cWsRXsize; ///< State of the RX
|
uint8_t cWsRXsize = 0; ///< State of the RX
|
||||||
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
||||||
WSMessageHeader_t cWsHeaderDecode;
|
WSMessageHeader_t cWsHeaderDecode;
|
||||||
|
|
||||||
@ -295,15 +307,15 @@ typedef struct {
|
|||||||
|
|
||||||
String extraHeaders;
|
String extraHeaders;
|
||||||
|
|
||||||
bool cHttpHeadersValid; ///< non-websocket http header validity indicator
|
bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator
|
||||||
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
||||||
|
|
||||||
bool pongReceived;
|
bool pongReceived = false;
|
||||||
uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active"
|
uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active"
|
||||||
uint32_t lastPing; // millis when last pong has been received
|
uint32_t lastPing = 0; // millis when last pong has been received
|
||||||
uint32_t pongTimeout; // interval in millis after which pong is considered to timeout
|
uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout
|
||||||
uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
||||||
uint8_t pongTimeoutCount; // current pong timeout count
|
uint8_t pongTimeoutCount = 0; // current pong timeout count
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
String cHttpLine; ///< HTTP header lines
|
String cHttpLine; ///< HTTP header lines
|
||||||
|
@ -41,6 +41,8 @@ class WebSockets4WebServer : public WebSocketsServerCore {
|
|||||||
onEvent(event);
|
onEvent(event);
|
||||||
|
|
||||||
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
|
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
|
||||||
|
(void)contentType;
|
||||||
|
|
||||||
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
|
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
|
||||||
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
|
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,8 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
|
|||||||
|
|
||||||
_lastConnectionFail = 0;
|
_lastConnectionFail = 0;
|
||||||
_lastHeaderSent = 0;
|
_lastHeaderSent = 0;
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
||||||
@ -227,8 +229,11 @@ void WebSocketsClient::loop(void) {
|
|||||||
#else
|
#else
|
||||||
#error setCACert not implemented
|
#error setCACert not implemented
|
||||||
#endif
|
#endif
|
||||||
#if defined(SSL_BARESSL)
|
#if defined(ESP32)
|
||||||
} else if(_fingerprint) {
|
} else if(!SSL_FINGERPRINT_IS_SET) {
|
||||||
|
_client.ssl->setInsecure();
|
||||||
|
#elif defined(SSL_BARESSL)
|
||||||
|
} else if(SSL_FINGERPRINT_IS_SET) {
|
||||||
_client.ssl->setFingerprint(_fingerprint);
|
_client.ssl->setFingerprint(_fingerprint);
|
||||||
} else {
|
} else {
|
||||||
_client.ssl->setInsecure();
|
_client.ssl->setInsecure();
|
||||||
@ -779,9 +784,11 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
if(client->isSocketIO) {
|
if(client->isSocketIO) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// falls through
|
||||||
case 403: ///< Forbidden
|
case 403: ///< Forbidden
|
||||||
// todo handle login
|
// todo handle login
|
||||||
default: ///< Server dont unterstand requrst
|
// falls through
|
||||||
|
default: ///< Server dont unterstand requrst
|
||||||
ok = false;
|
ok = false;
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
@ -863,14 +870,14 @@ void WebSocketsClient::connectedCb() {
|
|||||||
|
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
#if defined(SSL_AXTLS) || defined(ESP32)
|
#if defined(SSL_AXTLS) || defined(ESP32)
|
||||||
if(_client.isSSL && _fingerprint.length()) {
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
||||||
WebSockets::clientDisconnect(&_client, 1000);
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(_client.isSSL && _fingerprint) {
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
#endif
|
#endif
|
||||||
} else if(_client.isSSL && !_CA_cert) {
|
} else if(_client.isSSL && !_CA_cert) {
|
||||||
#if defined(SSL_BARESSL)
|
#if defined(SSL_BARESSL)
|
||||||
@ -943,6 +950,9 @@ void WebSocketsClient::handleHBPing() {
|
|||||||
if(sendPing()) {
|
if(sendPing()) {
|
||||||
_client.lastPing = millis();
|
_client.lastPing = millis();
|
||||||
_client.pongReceived = false;
|
_client.pongReceived = false;
|
||||||
|
} else {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n");
|
||||||
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,12 +112,14 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
#ifdef SSL_AXTLS
|
#ifdef SSL_AXTLS
|
||||||
String _fingerprint;
|
String _fingerprint;
|
||||||
const char * _CA_cert;
|
const char * _CA_cert;
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint.length())
|
||||||
#define SSL_FINGERPRINT_NULL ""
|
#define SSL_FINGERPRINT_NULL ""
|
||||||
#else
|
#else
|
||||||
const uint8_t * _fingerprint;
|
const uint8_t * _fingerprint;
|
||||||
BearSSL::X509List * _CA_cert;
|
BearSSL::X509List * _CA_cert;
|
||||||
BearSSL::X509List * _client_cert;
|
BearSSL::X509List * _client_cert;
|
||||||
BearSSL::PrivateKey * _client_key;
|
BearSSL::PrivateKey * _client_key;
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL)
|
||||||
#define SSL_FINGERPRINT_NULL NULL
|
#define SSL_FINGERPRINT_NULL NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -152,11 +154,11 @@ class WebSocketsClient : protected WebSockets {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(type, payload, length);
|
_cbEvent(type, payload, length);
|
||||||
|
@ -38,8 +38,6 @@ WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String &
|
|||||||
_httpHeaderValidationFunc = NULL;
|
_httpHeaderValidationFunc = NULL;
|
||||||
_mandatoryHttpHeaders = NULL;
|
_mandatoryHttpHeaders = NULL;
|
||||||
_mandatoryHttpHeaderCount = 0;
|
_mandatoryHttpHeaderCount = 0;
|
||||||
|
|
||||||
memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol)
|
WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol)
|
||||||
@ -73,47 +71,13 @@ WebSocketsServer::~WebSocketsServer() {
|
|||||||
* called to initialize the Websocket server
|
* called to initialize the Websocket server
|
||||||
*/
|
*/
|
||||||
void WebSocketsServerCore::begin(void) {
|
void WebSocketsServerCore::begin(void) {
|
||||||
WSclient_t * client;
|
// adjust clients storage:
|
||||||
|
// _clients[i]'s constructor are already called,
|
||||||
// init client storage
|
// all its members are initialized to their default value,
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
// except the ones explicitly detailed in WSclient_t() constructor.
|
||||||
client = &_clients[i];
|
// Then we need to initialize some members to non-trivial values:
|
||||||
|
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client->num = i;
|
_clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount);
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
client->tcp = NULL;
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
|
||||||
client->isSSL = false;
|
|
||||||
client->ssl = NULL;
|
|
||||||
#endif
|
|
||||||
client->cUrl = "";
|
|
||||||
client->cCode = 0;
|
|
||||||
|
|
||||||
client->cIsClient = false;
|
|
||||||
client->cIsUpgrade = false;
|
|
||||||
client->cIsWebsocket = false;
|
|
||||||
|
|
||||||
client->cSessionId = "";
|
|
||||||
client->cKey = "";
|
|
||||||
client->cAccept = "";
|
|
||||||
client->cProtocol = "";
|
|
||||||
client->cExtensions = "";
|
|
||||||
client->cVersion = 0;
|
|
||||||
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
|
|
||||||
client->base64Authorization = "";
|
|
||||||
client->plainAuthorization = "";
|
|
||||||
|
|
||||||
client->extraHeaders = "";
|
|
||||||
|
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->cHttpLine = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
client->pingInterval = _pingInterval;
|
|
||||||
client->pongTimeout = _pongTimeout;
|
|
||||||
client->disconnectTimeoutCount = _disconnectTimeoutCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -127,11 +91,19 @@ void WebSocketsServerCore::begin(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_runnning = true;
|
_runnning = true;
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsServerCore::close(void) {
|
void WebSocketsServerCore::close(void) {
|
||||||
_runnning = false;
|
_runnning = false;
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
|
// restore _clients[] to their initial state
|
||||||
|
// before next call to ::begin()
|
||||||
|
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
|
_clients[i] = WSclient_t();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -544,6 +516,9 @@ void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcod
|
|||||||
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
|
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
|
||||||
*/
|
*/
|
||||||
void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
||||||
|
if(!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(client->tcp) {
|
if(client->tcp) {
|
||||||
if(client->tcp->connected()) {
|
if(client->tcp->connected()) {
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
|
||||||
@ -647,6 +622,10 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
|
|||||||
#else
|
#else
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
||||||
#endif
|
#endif
|
||||||
|
// no client! => create dummy!
|
||||||
|
WSclient_t dummy = WSclient_t();
|
||||||
|
client = &dummy;
|
||||||
|
client->tcp = tcpClient;
|
||||||
dropNativeClient(client);
|
dropNativeClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,7 +666,7 @@ void WebSocketsServerCore::handleClientData(void) {
|
|||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
int len = client->tcp->available();
|
int len = client->tcp->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
//DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
// DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
||||||
switch(client->status) {
|
switch(client->status) {
|
||||||
case WSC_HEADER: {
|
case WSC_HEADER: {
|
||||||
String headerLine = client->tcp->readStringUntil('\n');
|
String headerLine = client->tcp->readStringUntil('\n');
|
||||||
@ -741,7 +720,7 @@ void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine
|
|||||||
// cut URL out
|
// cut URL out
|
||||||
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
||||||
|
|
||||||
//reset non-websocket http header validation state for this client
|
// reset non-websocket http header validation state for this client
|
||||||
client->cHttpHeadersValid = true;
|
client->cHttpHeadersValid = true;
|
||||||
client->cMandatoryHeadersCount = 0;
|
client->cMandatoryHeadersCount = 0;
|
||||||
|
|
||||||
@ -942,7 +921,7 @@ void WebSocketsServer::begin(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsServer::close(void) {
|
void WebSocketsServer::close(void) {
|
||||||
WebSocketsServer::close();
|
WebSocketsServerCore::close();
|
||||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
_server->close();
|
_server->close();
|
||||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
@ -98,6 +98,8 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
void loop(void); // handle client data only
|
void loop(void); // handle client data only
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
String _origin;
|
String _origin;
|
||||||
String _protocol;
|
String _protocol;
|
||||||
@ -116,8 +118,6 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
uint32_t _pongTimeout;
|
uint32_t _pongTimeout;
|
||||||
uint8_t _disconnectTimeoutCount;
|
uint8_t _disconnectTimeoutCount;
|
||||||
|
|
||||||
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
|
||||||
|
|
||||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
void clientDisconnect(WSclient_t * client);
|
||||||
@ -132,10 +132,10 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Websocket connection is coming in.
|
* called if a non Websocket connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
||||||
client->tcp->write(
|
client->tcp->write(
|
||||||
@ -151,10 +151,10 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Authorization connection is coming in.
|
* called if a non Authorization connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
||||||
client->tcp->write(
|
client->tcp->write(
|
||||||
"HTTP/1.1 401 Unauthorized\r\n"
|
"HTTP/1.1 401 Unauthorized\r\n"
|
||||||
@ -170,12 +170,12 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param num uint8_t
|
* @param num uint8_t
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(num, type, payload, length);
|
_cbEvent(num, type, payload, length);
|
||||||
@ -183,19 +183,19 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called at client socket connect handshake negotiation time for each http header that is not
|
* Called at client socket connect handshake negotiation time for each http header that is not
|
||||||
* a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
|
* a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
|
||||||
* If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
|
* If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
|
||||||
* socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
|
* socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
|
||||||
* This mechanism can be used to enable custom authentication schemes e.g. test the value
|
* This mechanism can be used to enable custom authentication schemes e.g. test the value
|
||||||
* of a session cookie to determine if a user is logged on / authenticated
|
* of a session cookie to determine if a user is logged on / authenticated
|
||||||
*/
|
*/
|
||||||
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
||||||
if(_httpHeaderValidationFunc) {
|
if(_httpHeaderValidationFunc) {
|
||||||
//return the value of the custom http header validation function
|
// return the value of the custom http header validation function
|
||||||
return _httpHeaderValidationFunc(headerName, headerValue);
|
return _httpHeaderValidationFunc(headerName, headerValue);
|
||||||
}
|
}
|
||||||
//no custom http header validation so just assume all is good
|
// no custom http header validation so just assume all is good
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,14 +205,14 @@ class WebSocketsServerCore : protected WebSockets {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* drop native tcp connection (client->tcp)
|
* drop native tcp connection (client->tcp)
|
||||||
*/
|
*/
|
||||||
void dropNativeClient(WSclient_t * client);
|
void dropNativeClient(WSclient_t * client);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||||
* @param headerName String ///< the name of the header being checked
|
* @param headerName String ///< the name of the header being checked
|
||||||
*/
|
*/
|
||||||
bool hasMandatoryHeader(String headerName);
|
bool hasMandatoryHeader(String headerName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
36
src/WebSocketsVersion.h
Normal file
36
src/WebSocketsVersion.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date 05.04.2022
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "2.3.7"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR 2
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR 3
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH 7
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT 2003007
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
function build_sketches()
|
function build_sketches()
|
||||||
{
|
{
|
||||||
local arduino=$1
|
local arduino=$1
|
||||||
@ -27,6 +29,64 @@ function build_sketches()
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function build_sketch()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local sketch=$2
|
||||||
|
$arduino --verify --verbose $sketch;
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($sketch) build verbose..."
|
||||||
|
$arduino --verify --verbose --preserve-temp-files $sketch
|
||||||
|
result=$?
|
||||||
|
fi
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($1) $sketch"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
echo -en "["
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "\"$sketch\""
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
echo -en "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json_matrix()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local ideversion=$4
|
||||||
|
local board=$5
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "{\"name\":\"$sketchname\",\"board\":\"$board\",\"ideversion\":\"$ideversion\",\"cpu\":\"$platform\",\"sketch\":\"$sketch\"}"
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
function get_core()
|
function get_core()
|
||||||
{
|
{
|
||||||
@ -37,17 +97,38 @@ function get_core()
|
|||||||
if [ "$1" = "esp8266" ] ; then
|
if [ "$1" = "esp8266" ] ; then
|
||||||
mkdir esp8266com
|
mkdir esp8266com
|
||||||
cd esp8266com
|
cd esp8266com
|
||||||
git clone https://github.com/esp8266/Arduino.git esp8266
|
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266
|
||||||
cd esp8266/tools
|
cd esp8266/
|
||||||
|
git submodule update --init
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
python get.py
|
python get.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" = "esp32" ] ; then
|
if [ "$1" = "esp32" ] ; then
|
||||||
mkdir espressif
|
mkdir espressif
|
||||||
cd espressif
|
cd espressif
|
||||||
git clone https://github.com/espressif/arduino-esp32.git esp32
|
git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32
|
||||||
cd esp32/tools
|
cd esp32/
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
python get.py
|
python get.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clone_library() {
|
||||||
|
local url=$1
|
||||||
|
echo clone $(basename $url)
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
git clone --depth 1 $url
|
||||||
|
rm -rf */.git
|
||||||
|
rm -rf */.github
|
||||||
|
rm -rf */examples
|
||||||
|
}
|
||||||
|
|
||||||
|
function hash_library_names() {
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
ls | sha1sum -z | cut -c1-5
|
||||||
|
}
|
132
travis/version.py
Executable file
132
travis/version.py
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import configparser
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
travis_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
base_dir = os.path.abspath(travis_dir + "/../")
|
||||||
|
|
||||||
|
def write_header_file(version):
|
||||||
|
hvs = version.split('.')
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
text = f'''/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date {now.strftime("%d.%m.%Y")}
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "{version}"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR {hvs[0]}
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR {hvs[1]}
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH {hvs[2]}
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT {intversion}
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
||||||
|
'''
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'w') as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_properties_version():
|
||||||
|
library_properties = {}
|
||||||
|
with open(f'{base_dir}/library.properties', 'r') as f:
|
||||||
|
library_properties = configparser.ConfigParser()
|
||||||
|
library_properties.read_string('[root]\n' + f.read())
|
||||||
|
return library_properties['root']['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_json_version():
|
||||||
|
library_json = {}
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
return library_json['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_header_versions():
|
||||||
|
data = {}
|
||||||
|
define = re.compile('^#define WEBSOCKETS_VERSION_?(.*) "?([0-9\.]*)"?$')
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
m = define.match(line)
|
||||||
|
if m:
|
||||||
|
name = m[1]
|
||||||
|
if name == "":
|
||||||
|
name = "VERSION"
|
||||||
|
data[name] = m[2]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Checks and update Version files')
|
||||||
|
parser.add_argument(
|
||||||
|
'--update', action='store_true', default=False)
|
||||||
|
parser.add_argument(
|
||||||
|
'--check', action='store_true', default=True)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.update:
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
|
||||||
|
library_json['version'] = library_properties_version
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'w') as f:
|
||||||
|
json.dump(library_json, f, indent=4, sort_keys=True)
|
||||||
|
|
||||||
|
write_header_file(library_properties_version)
|
||||||
|
|
||||||
|
|
||||||
|
library_json_version = get_library_json_version()
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
header_version = get_header_versions()
|
||||||
|
|
||||||
|
print("WebSocketsVersion.h", header_version)
|
||||||
|
print(f"library.json: {library_json_version}")
|
||||||
|
print(f"library.properties: {library_properties_version}")
|
||||||
|
|
||||||
|
if args.check:
|
||||||
|
if library_json_version != library_properties_version or header_version['VERSION'] != library_properties_version:
|
||||||
|
raise Exception('versions did not match!')
|
||||||
|
|
||||||
|
hvs = header_version['VERSION'].split('.')
|
||||||
|
if header_version['MAJOR'] != hvs[0]:
|
||||||
|
raise Exception('header MAJOR version wrong!')
|
||||||
|
if header_version['MINOR'] != hvs[1]:
|
||||||
|
raise Exception('header MINOR version wrong!')
|
||||||
|
if header_version['PATCH'] != hvs[2]:
|
||||||
|
raise Exception('header PATCH version wrong!')
|
||||||
|
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
if int(header_version['INT']) != intversion:
|
||||||
|
raise Exception('header INT version wrong!')
|
Reference in New Issue
Block a user