Compare commits

...

50 Commits

Author SHA1 Message Date
1fa9a1321c more debug 2022-06-24 10:48:51 +02:00
8fd9c5eff1 more debug 2022-06-24 10:35:37 +02:00
57976f7b51 esp8266 build, change config options 2022-06-24 10:23:50 +02:00
5881a99a30 bump version to 2.3.7 2022-04-05 20:07:59 +02:00
52b3aa8ea4 enable debug for CI 2022-04-05 19:40:57 +02:00
28c0cf3094 fix #728 dropNativeClient null ptr 2022-04-05 19:11:11 +02:00
ab9af162b2 fix code style 2022-04-05 19:10:57 +02:00
8d76469e90 update to Arduino IDE 1.8.19 for testing and dropped testing with 1.6.13 2022-04-05 19:03:19 +02:00
61ea44942e Suppress esp32/sha.h warning 2022-04-05 18:55:48 +02:00
28ed615145 Add minimal example for ESP OTA 2021-12-11 11:40:24 +01:00
108090e8cf Update WebSocketsServer.cpp
Created a dummy client in order to be able to drop the TCP Client.
2021-09-10 22:55:37 +02:00
46b2ae1c97 fix #695, #696 2021-07-14 19:28:25 +02:00
27f86a10ad allow access to setExtraHeaders and setReconnectInterval for SocketIOclient
fix: #690
2021-07-09 17:17:42 +02:00
860ac9da69 Prevent Compiler Warning: --> add // falls through
prevent Compiler warning by adding // falls through to imform compiler.
2021-06-20 09:22:41 +02:00
c897f60567 update arduino IDE from 1.8.13 to 1.8.15 2021-06-17 20:04:28 +02:00
b242882ac5 add git submodule update --init to esp8266 build 2021-06-17 19:56:45 +02:00
f8da05aa87 add Socket.IO example for ESP32 2021-06-17 19:43:15 +02:00
72aae52655 set EIO to version 4 in SocketIO examples
see #682
2021-06-17 19:42:09 +02:00
a14b6b73b4 bump version to 2.3.6 2021-03-08 17:22:23 +01:00
ed685e551f fix _fingerprint is set checks for ESP32
see #633 and #632
2021-03-07 13:46:37 +01:00
7c3b1b7408 install libgtk-3-0 2021-03-06 08:59:21 +01:00
738e43fda4 install libgtk-3-0 2021-03-06 08:56:08 +01:00
f55bf8d4ed bump version to 2.3.5 2021-02-09 18:26:21 +01:00
a484da47ed Merge branch 'eio_4_ping_handling' 2021-01-31 20:32:25 +01:00
4355199120 bump version 2.3.4 2021-01-31 20:31:52 +01:00
0a4fcd44c2 EIO=4 ping handling #611 2021-01-31 20:27:56 +01:00
3a2b757155 EIO=4 ping handling #611 2021-01-31 10:28:15 +01:00
900d81e534 make WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); public 2021-01-19 16:59:03 +01:00
0ecef8c552 Fixing WebSocket Close see #610 2021-01-19 16:58:37 +01:00
410489f7c5 bump version to 2.3.3 2021-01-07 10:27:42 +01:00
ec22d67c12 version.py can now create WebSocketsVersion.h 2021-01-07 10:24:23 +01:00
39e6a8e709 print version in DEBUG mode 2021-01-07 10:14:30 +01:00
784b7f9cb8 no python3.9 on github actions 2021-01-07 10:05:30 +01:00
fd83d6ad45 add WebSocketsVersion.h and some build checks 2021-01-07 09:59:49 +01:00
0e729cd896 cleanup clone_library 2021-01-06 09:39:19 +01:00
2f21590e55 no need for a full clone 2021-01-06 09:18:27 +01:00
c98baafda7 jobs steps array 2021-01-05 21:54:58 +01:00
983b9801fb Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2021-01-05 21:50:56 +01:00
e70262dab9 add done job 2021-01-05 21:50:40 +01:00
4a05eab627 Update README.md
use github actions as Build Status
2021-01-05 21:30:28 +01:00
822618f606 code style fix 2021-01-05 21:18:30 +01:00
1b4f186fa6 use github actions for build 2021-01-05 21:17:09 +01:00
c68e015322 github actions test3 2021-01-05 18:32:11 +01:00
dc30a2b7bf github actions test2 2021-01-05 18:28:59 +01:00
6bee53a8bd github actions test 2021-01-05 18:11:48 +01:00
ebb87cdc8a + constructors for scalars 2020-11-26 19:33:18 +01:00
e7ab913693 fix clearing _Client[] 2020-11-26 19:33:18 +01:00
52547ec47c fix clients init logic 2020-11-26 19:33:18 +01:00
74411bf729 use native contructor and destructor to initialize WSclient_t 2020-11-26 19:33:18 +01:00
f0cc36dede bump version to 2.3.2 2020-11-21 18:13:22 +01:00
23 changed files with 1311 additions and 148 deletions

188
.github/workflows/main.yml vendored Normal file
View 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

View File

@ -1,4 +1,4 @@
WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.com/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.com/Links2004/arduinoWebSockets) WebSocket Server and Client for Arduino [![Build Status](https://github.com/Links2004/arduinoWebSockets/workflows/CI/badge.svg?branch=master)](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.

View File

@ -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);
}
}

View 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.

View 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();
}

View 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())

View File

@ -0,0 +1,2 @@
packaging
websockets

View File

@ -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

View File

@ -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

View File

@ -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"
}

View File

@ -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)

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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);
} }
} }
} }

View File

@ -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);

View File

@ -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)

View File

@ -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
View 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_ */

View File

@ -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
View 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!')