Compare commits

..

34 Commits

Author SHA1 Message Date
bb900a77b6 GITHUB_STATE --> GITHUB_OUTPUT 2023-05-01 14:53:30 +02:00
7eda34f345 add RP2040 as supported and bump version 2023-05-01 14:51:36 +02:00
22dff6598f make OTA work with ArduinoJson 6.x 2023-05-01 14:48:18 +02:00
a4f13a1410 clang-format 2023-05-01 14:36:26 +02:00
4115a87c16 set-output command is deprecated 2023-05-01 14:36:07 +02:00
82c357c036 fix OTA example build and build tests for esp8266 examples 2023-05-01 14:30:20 +02:00
d9a5c629f0 Port to Raspberry Pi Pico W core
Add support for the onboard WiFi chip on the Raspberry Pi Pico W
(RP2040 based ) board using the arduino-pico Arduino core at
https://github.com/earlephilhower/arduino-pico

The PicoW WiFi stack is a mashup of the ESP8266 and ESP32 cores, so
only minimal changes were required.  Defines a new NETWORK_TYPE for
the PicoW.

ESP8266 examples renames to ESP8266_PICO because they all work unmodified
(except for OTA which is handled differently on the Pico)
2023-05-01 08:50:01 +02:00
323592f622 Add possibility to change WEBSOCKETS_TCP_TIMEOUT 2022-08-22 14:28:19 +02:00
f1ffaede0b Fix Typo 2022-08-22 14:22:00 +02:00
94a531c464 Use async sleep, increase chunk size 2022-08-22 14:22:00 +02:00
ccdba4ed8a Fix response type prefix (LoadProhibitedCause) 2022-08-22 14:22:00 +02:00
2b0e8f6fe9 Fix async run 2022-08-22 14:22:00 +02:00
dd8675c6a9 don't update cSessionId on unwanted Set-Cookie 2022-06-24 10:57:33 +02:00
2110ad0a10 more debug 2022-06-24 10:54:26 +02:00
04249a9b62 more debug 2022-06-24 10:54:26 +02:00
1fb67c8868 esp8266 build, change config options 2022-06-24 10:54:26 +02:00
3073c156b1 Fix compiler warning "function may return address of local variable" 2022-06-24 10:26:43 +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
37 changed files with 860 additions and 110 deletions

View File

@ -33,21 +33,20 @@ jobs:
run: | run: |
source $GITHUB_WORKSPACE/travis/common.sh source $GITHUB_WORKSPACE/travis/common.sh
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE
echo -en "::set-output name=matrix::"
echo -en "["
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.6.13 esp8266com:esp8266:generic:xtal=80 echo -en "matrix=" >> $GITHUB_OUTPUT
echo -en "," echo -en "[" >> $GITHUB_OUTPUT
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.6.13 esp8266com:esp8266:generic:xtal=80,dbg=Serial1 get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266_pico 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 >> $GITHUB_OUTPUT
echo -en "," echo -en "," >> $GITHUB_OUTPUT
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.8.13 esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80 get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266_pico 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 >> $GITHUB_OUTPUT
echo -en "," echo -en "," >> $GITHUB_OUTPUT
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 1.8.13 espressif:esp32:esp32:FlashFreq=80 get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 1.8.19 espressif:esp32:esp32:FlashFreq=80 >> $GITHUB_OUTPUT
echo -en "]" echo -en "]" >> $GITHUB_OUTPUT
echo >> $GITHUB_OUTPUT
outputs: outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }} matrix: ${{ steps.set-matrix.outputs.matrix }}
@ -56,7 +55,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
IDE_VERSION: [1.8.13, 1.6.13] IDE_VERSION: [1.8.19]
env: env:
IDE_VERSION: ${{ matrix.IDE_VERSION }} IDE_VERSION: ${{ matrix.IDE_VERSION }}
@ -66,7 +65,7 @@ jobs:
- name: Get Date - name: Get Date
id: get-date id: get-date
run: | run: |
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")" echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
shell: bash shell: bash
- uses: actions/cache@v2 - uses: actions/cache@v2
@ -99,7 +98,7 @@ jobs:
get_core esp8266 get_core esp8266
- name: download esp32 - name: download esp32
if: steps.cache_all.outputs.cache-hit != 'true' && matrix.IDE_VERSION != '1.6.13' if: steps.cache_all.outputs.cache-hit != 'true'
run: | run: |
source $GITHUB_WORKSPACE/travis/common.sh source $GITHUB_WORKSPACE/travis/common.sh
get_core esp32 get_core esp32
@ -128,7 +127,7 @@ jobs:
- name: Get Date - name: Get Date
id: get-date id: get-date
run: | run: |
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")" echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
shell: bash shell: bash
- uses: actions/cache@v2 - uses: actions/cache@v2
@ -164,15 +163,18 @@ jobs:
- name: config IDE - name: config IDE
run: | run: |
set +x
export DISPLAY=:1.0 export DISPLAY=:1.0
export PATH="$HOME/arduino_ide:$PATH" export PATH="$HOME/arduino_ide:$PATH"
arduino --board $BOARD --save-prefs 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 sketchbook.path
arduino --pref update.check=false arduino --get-pref
- name: build example - name: build example
timeout-minutes: 20 timeout-minutes: 20
run: | run: |
set -ex
export DISPLAY=:1.0 export DISPLAY=:1.0
export PATH="$HOME/arduino_ide:$PATH" export PATH="$HOME/arduino_ide:$PATH"
source $GITHUB_WORKSPACE/travis/common.sh source $GITHUB_WORKSPACE/travis/common.sh

View File

@ -26,6 +26,7 @@ a WebSocket Server and Client for Arduino based on RFC6455.
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/) - ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32) - ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
- ESP31B - ESP31B
- Raspberry Pi Pico W [Arduino for Pico](https://github.com/earlephilhower/arduino-pico)
- Particle with STM32 ARM Cortex M3 - Particle with STM32 ARM Cortex M3
- ATmega328 with Ethernet Shield (ATmega branch) - ATmega328 with Ethernet Shield (ATmega branch)
- ATmega328 with enc28j60 (ATmega branch) - ATmega328 with enc28j60 (ATmega branch)

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,264 @@
/*
* WebSocketClientOTA.ino
*
* Created on: 25.10.2021
*
*/
#include <Arduino.h>
#include <ArduinoJson.h>
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266mDNS.h>
#include <Updater.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
#elif defined(ESP32)
#include <WiFi.h>
#include <WiFiMulti.h>
#include "ESPmDNS.h"
#include <Update.h>
WiFiMulti WiFiMulti;
#else
#error Unsupported device
#endif
#include <WiFiUdp.h>
#include <WebSocketsClient.h>
WebSocketsClient webSocket;
#define USE_SERIAL Serial
// Variables:
// Settable:
const char *version = "1.0.0";
const char *name = "mydevice";
// Others:
#ifdef ESP8266
const char *chip = "esp8266";
#endif
#ifdef ESP32
const char *chip = "esp32";
#endif
uint32_t maxSketchSpace = 0;
int SketchSize = 0;
bool ws_conn = false;
void greetings_(){
StaticJsonDocument<200> doc;
doc["type"] = "greetings";
doc["mac"] = WiFi.macAddress().c_str();
doc["ip"] = WiFi.localIP().toString().c_str();
doc["version"] = version;
doc["name"] = name;
doc["chip"] = chip;
char data[200];
serializeJson(doc, data);
webSocket.sendTXT(data);
}
void register_(){
StaticJsonDocument<200> doc;
doc["type"] = "register";
doc["mac"] = WiFi.macAddress().c_str();
char data[200];
serializeJson(doc, data);
webSocket.sendTXT(data);
ws_conn = true;
}
typedef void (*CALLBACK_FUNCTION)(JsonDocument &msg);
typedef struct {
char type[50];
CALLBACK_FUNCTION func;
} RESPONSES_STRUCT;
void OTA_RESPONSES(JsonDocument &msg){
USE_SERIAL.print(F("[WSc] OTA mode: "));
String val = msg["value"];
if(val == "go") {
USE_SERIAL.print(F("go\n"));
SketchSize = int(msg["size"]);
maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
USE_SERIAL.printf("[WSc] Max sketch size: %u\n", maxSketchSpace);
USE_SERIAL.printf("[WSc] Sketch size: %d\n", SketchSize);
USE_SERIAL.setDebugOutput(true);
if (!Update.begin(maxSketchSpace)) { //start with max available size
Update.printError(Serial);
ESP.restart();
}
} else if (val == "ok") {
USE_SERIAL.print(F("OK\n"));
register_();
} else {
USE_SERIAL.print(F("unknown value : "));
USE_SERIAL.print(val);
USE_SERIAL.print(F("\n"));
}
}
void STA_RESPONSES(JsonDocument &msg){
// Do something with message
}
// Count of responses handled by RESPONSES_STRUCT
// increase increase if another response handler is added
const int nrOfResponses = 2;
RESPONSES_STRUCT responses[nrOfResponses] = {
{"ota", OTA_RESPONSES},
{"state", STA_RESPONSES},
};
void text(uint8_t * payload, size_t length){
// Convert message to something usable
char msgch[length];
for (unsigned int i = 0; i < length; i++)
{
USE_SERIAL.print((char)payload[i]);
msgch[i] = ((char)payload[i]);
}
msgch[length] = '\0';
// Parse Json
StaticJsonDocument<200> doc_in;
DeserializationError error = deserializeJson(doc_in, msgch);
if (error) {
USE_SERIAL.print(F("deserializeJson() failed: "));
USE_SERIAL.println(error.c_str());
return;
}
// Handle each TYPE of message
int b = 0;
String t = doc_in["type"];
for( b=0 ; b<nrOfResponses ; b++ )
{
if(t == responses[b].type) {
responses[b].func(doc_in);
}
}
}
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED: {
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
// send message to server when Connected
// webSocket.sendTXT("Connected");
greetings_();
}
break;
case WStype_TEXT:
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
// send message to server
// webSocket.sendTXT("message here");
text(payload, length);
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
// hexdump(payload, length);
if (Update.write(payload, length) != length) {
Update.printError(Serial);
ESP.restart();
}
yield();
SketchSize -= length;
USE_SERIAL.printf("[WSc] Sketch size left: %u\n", SketchSize);
if (SketchSize < 1){
if (Update.end(true)) { //true to set the size to the current progress
USE_SERIAL.printf("Update Success: \nRebooting...\n");
delay(5);
yield();
ESP.restart();
} else {
Update.printError(USE_SERIAL);
ESP.restart();
}
USE_SERIAL.setDebugOutput(false);
}
// send data to server
// webSocket.sendBIN(payload, length);
break;
case WStype_PING:
// pong will be send automatically
USE_SERIAL.printf("[WSc] get ping\n");
break;
case WStype_PONG:
// answer to a ping we send
USE_SERIAL.printf("[WSc] get pong\n");
break;
}
}
void setup() {
// USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.print(F("\nMAC: "));
USE_SERIAL.println(WiFi.macAddress());
USE_SERIAL.print(F("\nDevice: "));
USE_SERIAL.println(name);
USE_SERIAL.printf("\nVersion: %s\n", version);
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("SSID", "PASS");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
// server address, port and URL
webSocket.begin("10.0.1.5", 8081, "/");
// event handler
webSocket.onEvent(webSocketEvent);
// use HTTP Basic Authorization this is optional remove if not needed
// webSocket.setAuthorization("USER", "PASS");
// try ever 5000 again if connection has failed
webSocket.setReconnectInterval(5000);
// start heartbeat (optional)
// ping server every 15000 ms
// expect pong from server within 3000 ms
// consider connection disconnected if pong is not received 2 times
webSocket.enableHeartbeat(15000, 3000, 2);
}
void loop() {
webSocket.loop();
}

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(4096)
if not chunk:
break
try:
await websocket.send(chunk)
except Exception as exception:
Logger.exception(exception)
return False
asyncio.sleep(0.2)
def version_checker(name, vdev, vapp):
"""Parse and compare FW version"""
if version.parse(vdev) < version.parse(vapp):
Logger.info("Client(%s) version %s is smaller than %s: Go for update", name, vdev, vapp)
return True
Logger.info("Client(%s) version %s is greater or equal to %s: Not updating", name, vdev, vapp)
return False
class WsOtaHandler (threading.Thread):
"""Thread handling ota update
Running ota directly from message would kill WS
as message bus would timeout.
"""
def __init__(self, name, message, websocket):
threading.Thread.__init__(self, daemon=True)
self.name = name
self.msg = message
self.websocket = websocket
def run(self, ):
try:
asyncio.run(self.start_())
except Exception as exception:
Logger.exception(exception)
finally:
pass
async def start_(self):
"""Start _ota se asyncio future"""
msg_task = asyncio.ensure_future(
self._ota())
done, pending = await asyncio.wait(
[msg_task],
return_when=asyncio.FIRST_COMPLETED,
)
Logger.info("WS Ota Handler done: %s", done)
for task in pending:
task.cancel()
async def _ota(self):
"""Check for new fw and update or pass"""
device_name = self.msg['name']
device_chip = self.msg['chip']
device_version = self.msg['version']
fw_version = ''
fw_name = ''
fw_device = ''
for filename in listdir(fw_path):
fw_info = filename.split("-")
fw_device = fw_info[0]
if fw_device == device_name:
fw_version = fw_info[1]
fw_name = filename
break
if not fw_version:
Logger.info("Client(%s): No fw found!", device_name)
msg = '{"type": "ota", "value":"ok"}'
await self.websocket.send(msg)
return
if not version_checker(device_name, device_version, fw_version):
return
fw_file = join_pth(fw_path, fw_name)
if device_chip == 'esp8266' and not fw_file.endswith('.gz'):
# We can compress fw to make it smaller for upload
fw_cpress = fw_file
fw_file = fw_cpress + ".gz"
cpress = f"gzip -9 {fw_cpress}"
cstate = shell(cpress)
if cstate:
Logger.error("Cannot compress firmware: %s", fw_name)
return
# Get size of fw
size = Path(fw_file).stat().st_size
# Request ota mode
msg = '{"type": "ota", "value":"go", "size":' + str(size) + '}'
await self.websocket.send(msg)
# send file by chunks trough websocket
await binary_send(self.websocket, fw_file)
async def _register(websocket, message):
mac = message.get('mac')
name = message.get('name')
Logger.info("Client(%s) mac: %s", name, mac)
# Some code
response = {'type': 'registry', 'state': 'ok'}
await websocket.send(json.dumps(response))
async def _state(websocket, message):
mac = message.get('mac')
name = message.get('name')
Logger.info("Client(%s) mac: %s", name, mac)
# Some code
response = {'type': 'state', 'state': 'ok'}
await websocket.send(json.dumps(response))
async def _unhandled(websocket, msg):
Logger.info("Unhandled message from device: %s", str(msg))
response = {'type': 'response', 'state': 'nok'}
await websocket.send(json.dumps(response))
async def _greetings(websocket, message):
WsOtaHandler('thread_ota', copy.deepcopy(message), websocket).start()
async def message_received(websocket, message) -> None:
"""Handle incoming messages
Check if message contain json and run waned function
"""
switcher = {"greetings": _greetings,
"register": _register,
"state": _state
}
if message[0:1] == "{":
try:
msg_json = json.loads(message)
except Exception as exception:
Logger.error(exception)
return
type_ = msg_json.get('type')
name = msg_json.get('name')
func = switcher.get(type_, _unhandled)
Logger.debug("Client(%s)said: %s", name, type_)
try:
await func(websocket, msg_json)
except Exception as exception:
Logger.error(exception)
# pylint: disable=W0613
async def ws_server(websocket, path) -> None:
"""Run in cycle and wait for new messages"""
async for message in websocket:
await message_received(websocket, message)
async def main():
"""Server starter
Normal user can bind only port numbers greater than 1024
"""
async with websockets.serve(ws_server, "10.0.1.5", 8081):
await asyncio.Future() # run forever
create_path(fw_path)
asyncio.run(main())

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

@ -16,10 +16,10 @@
"keywords": "wifi, http, web, server, client, websocket", "keywords": "wifi, http, web, server, client, websocket",
"license": "LGPL-2.1", "license": "LGPL-2.1",
"name": "WebSockets", "name": "WebSockets",
"platforms": "atmelavr, espressif8266, espressif32", "platforms": "atmelavr, espressif8266, espressif32, raspberrypi",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/Links2004/arduinoWebSockets.git" "url": "https://github.com/Links2004/arduinoWebSockets.git"
}, },
"version": "2.3.5" "version": "2.4.0"
} }

View File

@ -1,5 +1,5 @@
name=WebSockets name=WebSockets
version=2.3.5 version=2.4.0
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

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

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,6 +76,9 @@ 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); void configureEIOping(bool disableHeartbeat = false);

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]);
} }
@ -478,7 +482,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
switch(header->opCode) { switch(header->opCode) {
case WSop_text: case WSop_text:
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
// no break here! // fallthrough
case WSop_binary: case WSop_binary:
case WSop_continuation: case WSop_continuation:
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
@ -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

@ -50,7 +50,7 @@
DEBUG_ESP_PORT.flush(); \ DEBUG_ESP_PORT.flush(); \
} }
#else #else
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ ) // #define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
#endif #endif
#endif #endif
@ -67,7 +67,7 @@
#define WEBSOCKETS_USE_BIG_MEM #define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP ESP.getFreeHeap() #define GET_FREE_HEAP ESP.getFreeHeap()
// moves all Header strings to Flash (~300 Byte) // moves all Header strings to Flash (~300 Byte)
//#define WEBSOCKETS_SAVE_RAM // #define WEBSOCKETS_SAVE_RAM
#if defined(ESP8266) #if defined(ESP8266)
#define WEBSOCKETS_YIELD() delay(0) #define WEBSOCKETS_YIELD() delay(0)
@ -84,9 +84,18 @@
#define GET_FREE_HEAP System.freeMemory() #define GET_FREE_HEAP System.freeMemory()
#define WEBSOCKETS_YIELD() #define WEBSOCKETS_YIELD()
#define WEBSOCKETS_YIELD_MORE() #define WEBSOCKETS_YIELD_MORE()
#elif defined(ARDUINO_ARCH_RP2040)
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
#define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP rp2040.getFreeHeap()
#define WEBSOCKETS_YIELD() yield()
#define WEBSOCKETS_YIELD_MORE() delay(1)
#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
@ -94,7 +103,9 @@
#define WEBSOCKETS_YIELD_MORE() #define WEBSOCKETS_YIELD_MORE()
#endif #endif
#ifndef WEBSOCKETS_TCP_TIMEOUT
#define WEBSOCKETS_TCP_TIMEOUT (5000) #define WEBSOCKETS_TCP_TIMEOUT (5000)
#endif
#define NETWORK_ESP8266_ASYNC (0) #define NETWORK_ESP8266_ASYNC (0)
#define NETWORK_ESP8266 (1) #define NETWORK_ESP8266 (1)
@ -102,6 +113,7 @@
#define NETWORK_ENC28J60 (3) #define NETWORK_ENC28J60 (3)
#define NETWORK_ESP32 (4) #define NETWORK_ESP32 (4)
#define NETWORK_ESP32_ETH (5) #define NETWORK_ESP32_ETH (5)
#define NETWORK_RP2040 (6)
// max size of the WS Message Header // max size of the WS Message Header
#define WEBSOCKETS_MAX_HEADER_SIZE (14) #define WEBSOCKETS_MAX_HEADER_SIZE (14)
@ -110,12 +122,16 @@
// select Network type based // select Network type based
#if defined(ESP8266) || defined(ESP31B) #if defined(ESP8266) || defined(ESP31B)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266 #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC // #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 // #define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
#elif defined(ESP32) #elif defined(ESP32)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32 #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH // #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
#elif defined(ARDUINO_ARCH_RP2040)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_RP2040
#else #else
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 #define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
@ -199,6 +215,15 @@
#define WEBSOCKETS_NETWORK_CLASS WiFiClient #define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer #define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define SSL_BARESSL
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
#else #else
#error "no network type selected!" #error "no network type selected!"
#endif #endif

View File

@ -28,23 +28,29 @@
#include <WebSocketsServer.h> #include <WebSocketsServer.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK #if((WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)) && WEBSERVER_HAS_HOOK
class WebSockets4WebServer : public WebSocketsServerCore { class WebSockets4WebServer : public WebSocketsServerCore {
#if defined(ESP8266)
using WebServerClass = ESP8266WebServer;
#else
using WebServerClass = WebServer;
#endif
public: public:
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino") WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
: WebSocketsServerCore(origin, protocol) { : WebSocketsServerCore(origin, protocol) {
begin(); begin();
} }
ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) { WebServerClass::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
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, WebServerClass::ContentTypeFunction contentType) {
(void)contentType; (void)contentType;
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) { if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; return WebServerClass::CLIENT_REQUEST_CAN_CONTINUE;
} }
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients()) // allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
@ -63,7 +69,7 @@ class WebSockets4WebServer : public WebSocketsServerCore {
} }
// tell webserver to not close but forget about this client // tell webserver to not close but forget about this client
return ESP8266WebServer::CLIENT_IS_GIVEN; return WebServerClass::CLIENT_IS_GIVEN;
}; };
} }
}; };

View File

@ -76,6 +76,8 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
#ifdef ESP8266 #ifdef ESP8266
randomSeed(RANDOM_REG32); randomSeed(RANDOM_REG32);
#elif defined(ARDUINO_ARCH_RP2040)
randomSeed(rp2040.hwrand32());
#else #else
// todo find better seed // todo find better seed
randomSeed(millis()); randomSeed(millis());
@ -224,7 +226,7 @@ void WebSocketsClient::loop(void) {
_client.ssl->setCACert(_CA_cert); _client.ssl->setCACert(_CA_cert);
#elif defined(ESP8266) && defined(SSL_AXTLS) #elif defined(ESP8266) && defined(SSL_AXTLS)
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1); _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
#elif defined(ESP8266) && defined(SSL_BARESSL) #elif(defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)) && defined(SSL_BARESSL)
_client.ssl->setTrustAnchors(_CA_cert); _client.ssl->setTrustAnchors(_CA_cert);
#else #else
#error setCACert not implemented #error setCACert not implemented
@ -426,9 +428,9 @@ bool WebSocketsClient::isConnected(void) {
return (_client.status == WSC_CONNECTED); return (_client.status == WSC_CONNECTED);
} }
//################################################################################# // #################################################################################
//################################################################################# // #################################################################################
//################################################################################# // #################################################################################
/** /**
* *
@ -473,7 +475,7 @@ void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, u
void WebSocketsClient::clientDisconnect(WSclient_t * client) { void WebSocketsClient::clientDisconnect(WSclient_t * client) {
bool event = false; bool event = false;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
if(client->isSSL && client->ssl) { if(client->isSSL && client->ssl) {
if(client->ssl->connected()) { if(client->ssl->connected()) {
client->ssl->flush(); client->ssl->flush();
@ -733,7 +735,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
client->cExtensions = headerValue; client->cExtensions = headerValue;
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
client->cVersion = headerValue.toInt(); client->cVersion = headerValue.toInt();
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) { } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie")) && headerValue.indexOf(" io=") > -1) {
if(headerValue.indexOf(';') > -1) { if(headerValue.indexOf(';') > -1) {
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";")); client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
} else { } else {
@ -784,9 +786,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);
@ -862,7 +866,7 @@ void WebSocketsClient::connectedCb() {
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
_client.tcp->setNoDelay(true); _client.tcp->setNoDelay(true);
#endif #endif

View File

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

@ -85,6 +85,8 @@ void WebSocketsServerCore::begin(void) {
#elif defined(ESP32) #elif defined(ESP32)
#define DR_REG_RNG_BASE 0x3ff75144 #define DR_REG_RNG_BASE 0x3ff75144
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE)); randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
#elif defined(ARDUINO_ARCH_RP2040)
randomSeed(rp2040.hwrand32());
#else #else
// TODO find better seed // TODO find better seed
randomSeed(millis()); randomSeed(millis());
@ -394,7 +396,7 @@ bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
return clientIsConnected(client); return clientIsConnected(client);
} }
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
/** /**
* get an IP for a client * get an IP for a client
* @param num uint8_t client id * @param num uint8_t client id
@ -412,9 +414,9 @@ IPAddress WebSocketsServerCore::remoteIP(uint8_t num) {
} }
#endif #endif
//################################################################################# // #################################################################################
//################################################################################# // #################################################################################
//################################################################################# // #################################################################################
/** /**
* handle new client connection * handle new client connection
@ -439,7 +441,7 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#endif #endif
client->status = WSC_HEADER; client->status = WSC_HEADER;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#ifndef NODEBUG_WEBSOCKETS #ifndef NODEBUG_WEBSOCKETS
IPAddress ip = client->tcp->remoteIP(); IPAddress ip = client->tcp->remoteIP();
#endif #endif
@ -516,9 +518,12 @@ 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) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_RP2040)
client->tcp->flush(); client->tcp->flush();
#endif #endif
client->tcp->stop(); client->tcp->stop();
@ -537,7 +542,7 @@ void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
*/ */
void WebSocketsServerCore::clientDisconnect(WSclient_t * client) { void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
if(client->isSSL && client->ssl) { if(client->isSSL && client->ssl) {
if(client->ssl->connected()) { if(client->ssl->connected()) {
client->ssl->flush(); client->ssl->flush();
@ -611,7 +616,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
if(!client) { if(!client) {
// no free space to handle client // no free space to handle client
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#ifndef NODEBUG_WEBSOCKETS #ifndef NODEBUG_WEBSOCKETS
IPAddress ip = tcpClient->remoteIP(); IPAddress ip = tcpClient->remoteIP();
#endif #endif
@ -619,7 +624,12 @@ 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);
return nullptr;
} }
WEBSOCKETS_YIELD(); WEBSOCKETS_YIELD();
@ -631,7 +641,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
* Handle incoming Connection Request * Handle incoming Connection Request
*/ */
void WebSocketsServer::handleNewClients(void) { void WebSocketsServer::handleNewClients(void) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
while(_server->hasClient()) { while(_server->hasClient()) {
#endif #endif
@ -644,7 +654,7 @@ void WebSocketsServer::handleNewClients(void) {
handleNewClient(tcpClient); handleNewClient(tcpClient);
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
} }
#endif #endif
} }
@ -659,7 +669,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');
@ -713,7 +723,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;
@ -915,7 +925,7 @@ void WebSocketsServer::begin(void) {
void WebSocketsServer::close(void) { void WebSocketsServer::close(void) {
WebSocketsServerCore::close(); WebSocketsServerCore::close();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
_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)
_server->end(); _server->end();

View File

@ -90,7 +90,7 @@ class WebSocketsServerCore : protected WebSockets {
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat(); void disableHeartbeat();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
IPAddress remoteIP(uint8_t num); IPAddress remoteIP(uint8_t num);
#endif #endif
@ -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);
}; };

View File

@ -1,6 +1,6 @@
/** /**
* @file WebSocketsVersion.h * @file WebSocketsVersion.h
* @date 09.02.2021 * @date 01.05.2023
* @author Markus Sattler * @author Markus Sattler
* *
* Copyright (c) 2015 Markus Sattler. All rights reserved. * Copyright (c) 2015 Markus Sattler. All rights reserved.
@ -25,12 +25,12 @@
#ifndef WEBSOCKETSVERSION_H_ #ifndef WEBSOCKETSVERSION_H_
#define WEBSOCKETSVERSION_H_ #define WEBSOCKETSVERSION_H_
#define WEBSOCKETS_VERSION "2.3.5" #define WEBSOCKETS_VERSION "2.4.0"
#define WEBSOCKETS_VERSION_MAJOR 2 #define WEBSOCKETS_VERSION_MAJOR 2
#define WEBSOCKETS_VERSION_MINOR 3 #define WEBSOCKETS_VERSION_MINOR 4
#define WEBSOCKETS_VERSION_PATCH 5 #define WEBSOCKETS_VERSION_PATCH 0
#define WEBSOCKETS_VERSION_INT 2003005 #define WEBSOCKETS_VERSION_INT 2004000
#endif /* WEBSOCKETSVERSION_H_ */ #endif /* WEBSOCKETSVERSION_H_ */

View File

@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h> #include <core_esp8266_features.h>
#endif #endif
#if defined(ESP32) #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#define CORE_HAS_LIBB64 #define CORE_HAS_LIBB64
#endif #endif

View File

@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h> #include <core_esp8266_features.h>
#endif #endif
#if defined(ESP32) #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#define CORE_HAS_LIBB64 #define CORE_HAS_LIBB64
#endif #endif

View File

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
set -x
function build_sketches() function build_sketches()
{ {
local arduino=$1 local arduino=$1
@ -28,10 +30,10 @@ function build_sketches()
} }
function build_sketch() function build_sketch()
{ {
local arduino=$1 local arduino=$1
local sketch=$2 local sketch=$2
$arduino --verify $sketch; $arduino --verify --verbose $sketch;
local result=$? local result=$?
if [ $result -ne 0 ]; then if [ $result -ne 0 ]; then
echo "Build failed ($sketch) build verbose..." echo "Build failed ($sketch) build verbose..."
@ -60,7 +62,7 @@ function get_sketches_json()
if [[ $sketch != ${sketches[-1]} ]] ; then if [[ $sketch != ${sketches[-1]} ]] ; then
echo -en "," echo -en ","
fi fi
done done
echo -en "]" echo -en "]"
} }
@ -97,6 +99,7 @@ function get_core()
cd esp8266com cd esp8266com
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266 git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266
cd esp8266/ cd esp8266/
git submodule update --init
rm -rf .git rm -rf .git
cd tools cd tools
python get.py python get.py
@ -127,5 +130,5 @@ function clone_library() {
function hash_library_names() { function hash_library_names() {
cd $HOME/Arduino/libraries cd $HOME/Arduino/libraries
ls | sha1sum -z | cut -c1-5 ls | sha1sum -z | cut -c1-5
} }