mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 14:12:16 +03:00
Merge branch 'ver4dev' into ver4dev
This commit is contained in:
55
.github/workflows/build_iotm.yml
vendored
Normal file
55
.github/workflows/build_iotm.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
env:
|
||||
BOARDS: '["esp8266_4mb", "esp8266_16mb", "esp32_4mb3f", "esp32c3m_4mb", "esp32s2_4mb", "esp32s3_16mb"]'
|
||||
|
||||
name: Build Firmware
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
generate-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set_matrix.outputs.json }}
|
||||
steps:
|
||||
- name: Prepare matrix JSON Object
|
||||
id: set_matrix
|
||||
uses: nickofthyme/object-remap@v2.0.0
|
||||
with:
|
||||
__case: kebab
|
||||
board: ${{ env.BOARDS }}
|
||||
|
||||
build:
|
||||
needs: [ generate-matrix ]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: 'ver4dev'
|
||||
- name: Run PrepareProject.py -b ${{ matrix.board }}
|
||||
run: python3 ./PrepareProject.py -b ${{ matrix.board }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install platformio
|
||||
- name: Run PlatformIO
|
||||
if: always()
|
||||
run: platformio run
|
||||
- name: Build FS
|
||||
if: always()
|
||||
run: platformio run -t buildfs --disable-auto-clean
|
||||
- name: Rearrange Artifacts
|
||||
run: |
|
||||
mkdir -p artifacts/${{ matrix.board }}
|
||||
find .pio/build/${{ matrix.board }} -name "*.bin" -exec mv {} artifacts/${{ matrix.board }} \;
|
||||
working-directory: ${{ github.workspace }}
|
||||
- name: Attach artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ github.run_number }}
|
||||
path: artifacts/${{ matrix.board }}
|
||||
@@ -41,7 +41,22 @@ def printHelp():
|
||||
PrepareProject.py
|
||||
-p --profile <file.json_in_root_folder>
|
||||
-u --update
|
||||
-h --help''')
|
||||
-h --help
|
||||
-b --board <board_name>''')
|
||||
with open('myProfile.json', "r", encoding='utf-8') as read_file:
|
||||
profJson = json.load(read_file)
|
||||
print ('')
|
||||
print ('Choose a board from the list:')
|
||||
# print(profJson['projectProp']['platformio']['comments_default_envs'])
|
||||
print (' ', end='')
|
||||
cnt = 0
|
||||
for envs in profJson['projectProp']['platformio']['envs']:
|
||||
if cnt == 5:
|
||||
cnt = 0
|
||||
print('')
|
||||
print(' ', end='')
|
||||
print(envs['name'] + ', ', end='')
|
||||
cnt = cnt + 1
|
||||
|
||||
|
||||
def updateModulesInProfile(profJson):
|
||||
@@ -68,10 +83,11 @@ def updateModulesInProfile(profJson):
|
||||
|
||||
update = False # признак необходимости обновить список модулей
|
||||
profile = 'myProfile.json' # имя профиля. Будет заменено из консоли, если указано при старте
|
||||
selectDevice = '' # имя платы для которой хотим собрать, если её указали к командной строке -b <board>
|
||||
|
||||
argv = sys.argv[1:]
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, 'hp:u', ['help', 'profile=', 'update'])
|
||||
opts, args = getopt.getopt(argv, 'hp:ub:', ['help', 'profile=', 'update', 'board='])
|
||||
except getopt.GetoptError:
|
||||
print('Ошибка обработки параметров!')
|
||||
printHelp()
|
||||
@@ -82,10 +98,14 @@ for opt, arg in opts:
|
||||
printHelp()
|
||||
sys.exit()
|
||||
elif opt in ("-p", "--profile"):
|
||||
print('Загрузка профиля из файла:' + arg)
|
||||
profile = arg
|
||||
elif opt in ("-u", "--update"):
|
||||
print('Создание новой конфигурации по исходным файлам!')
|
||||
update = True
|
||||
|
||||
elif opt in ("-b", "--board"):
|
||||
print('Создание профиля для платы:' + arg)
|
||||
selectDevice = arg
|
||||
|
||||
if Path(profile).is_file():
|
||||
# подтягиваем уже существующий профиль
|
||||
@@ -121,9 +141,17 @@ else:
|
||||
with open(profile, "w", encoding='utf-8') as write_file:
|
||||
json.dump(profJson, write_file, ensure_ascii=False, indent=4, sort_keys=False)
|
||||
|
||||
|
||||
# определяем какое устройство используется в профиле
|
||||
deviceName = profJson['projectProp']['platformio']['default_envs']
|
||||
deviceName = ''
|
||||
if selectDevice == '':
|
||||
# определяем какое устройство используется в профиле
|
||||
deviceName = profJson['projectProp']['platformio']['default_envs']
|
||||
else:
|
||||
for envs in profJson['projectProp']['platformio']['envs']:
|
||||
if envs['name'] == selectDevice:
|
||||
deviceName = selectDevice
|
||||
if deviceName == '':
|
||||
deviceName = profJson['projectProp']['platformio']['default_envs']
|
||||
print(f"\x1b[1;31;31m Board ", selectDevice, " not found in ",profile,"!!! Use ",deviceName," \x1b[0m")
|
||||
|
||||
# заполняем папку /data файлами прошивки в зависимости от устройства
|
||||
if deviceName == 'esp8266_1mb_ota' or deviceName == 'esp8285_1mb_ota' or deviceName == 'esp8266_2mb_ota':
|
||||
@@ -134,7 +162,8 @@ else:
|
||||
deviceType = 'esp32*'
|
||||
if not 'esp32' in deviceName:
|
||||
deviceType = 'esp82*'
|
||||
|
||||
if 'bk72' in deviceName:
|
||||
deviceType = 'bk72*'
|
||||
# генерируем файлы проекта на основе подготовленного профиля
|
||||
# заполняем конфигурационный файл прошивки параметрами из профиля
|
||||
with open("data_svelte/settings.json", "r", encoding='utf-8') as read_file:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,7 @@
|
||||
"mqttUser": "rise",
|
||||
"mqttPass": "3hostel3",
|
||||
"serverip": "http://iotmanager.org",
|
||||
"serverlocal": "http://192.168.1.2:5500",
|
||||
"log": 0,
|
||||
"mqttin": 0,
|
||||
"i2c": 0,
|
||||
@@ -21,6 +22,7 @@
|
||||
"pinSDA": 0,
|
||||
"i2cFreq": 100000,
|
||||
"wg": "group1",
|
||||
"debugTraceMsgTlgrm": 1,
|
||||
"udps": 1,
|
||||
"settings_": ""
|
||||
}
|
||||
@@ -325,5 +325,12 @@
|
||||
{
|
||||
"name": "nil",
|
||||
"label": "Без виджета"
|
||||
},
|
||||
{
|
||||
"name": "anydataBar",
|
||||
"label": "давление Bar",
|
||||
"widget": "anydata",
|
||||
"after": "Kg/cm²",
|
||||
"icon": "speedometer"
|
||||
}
|
||||
]
|
||||
@@ -32,6 +32,10 @@
|
||||
#define FIRMWARE_NAME "esp32_4mb"
|
||||
#endif
|
||||
|
||||
#ifdef esp32_4mb3f
|
||||
#define FIRMWARE_NAME "esp32_4mb3f"
|
||||
#endif
|
||||
|
||||
#ifdef esp32cam_4mb
|
||||
#define FIRMWARE_NAME "esp32cam_4mb"
|
||||
#endif
|
||||
@@ -52,6 +56,18 @@
|
||||
#define FIRMWARE_NAME "esp32s3_16mb"
|
||||
#endif
|
||||
|
||||
#ifdef bk7231n
|
||||
#define FIRMWARE_NAME "bk7231n"
|
||||
#endif
|
||||
|
||||
#ifdef esp32c6_4mb
|
||||
#define FIRMWARE_NAME "esp32c6_4mb"
|
||||
#endif
|
||||
|
||||
#ifdef esp32c6_8mb
|
||||
#define FIRMWARE_NAME "esp32c6_8mb"
|
||||
#endif
|
||||
|
||||
// Размер буфера json
|
||||
#define JSON_BUFFER_SIZE 4096 // держим 2 кб не меняем
|
||||
|
||||
@@ -72,8 +88,9 @@ WEB_SOCKETS_FRAME_SIZE создан для того что бы не загру
|
||||
#define STANDARD_WEB_SERVER
|
||||
#define STANDARD_WEB_SOCKETS
|
||||
|
||||
//#ifndef LIBRETINY
|
||||
#define UDP_ENABLED
|
||||
|
||||
//#endif
|
||||
// #define REST_FILE_OPERATIONS
|
||||
|
||||
#define MQTT_RECONNECT_INTERVAL 20000
|
||||
@@ -91,22 +108,26 @@ WEB_SOCKETS_FRAME_SIZE создан для того что бы не загру
|
||||
enum TimerTask_t {
|
||||
WIFI_SCAN,
|
||||
WIFI_MQTT_CONNECTION_CHECK,
|
||||
#ifndef ESP8266
|
||||
WIFI_CONN,
|
||||
#endif
|
||||
TIME,
|
||||
TIME_SYNC,
|
||||
UPTIME,
|
||||
UDP, // UDPP
|
||||
// TIME_SYNC, // не используется
|
||||
// UPTIME, // не используется
|
||||
UDPt, // UDPP
|
||||
TIMES, // периодические секундные проверки
|
||||
PTASK,
|
||||
ST,
|
||||
PiWS,
|
||||
END
|
||||
};
|
||||
|
||||
// задачи которые надо протащить через loop
|
||||
enum NotAsyncActions {
|
||||
do_ZERO,
|
||||
do_MQTTPARAMSCHANGED,
|
||||
do_LAST,
|
||||
};
|
||||
// задачи которые надо протащить через loop // не используется
|
||||
// enum NotAsyncActions {
|
||||
// do_ZERO,
|
||||
// do_MQTTPARAMSCHANGED,
|
||||
// do_LAST,
|
||||
// };
|
||||
|
||||
// состояния обновления
|
||||
enum UpdateStates { UPDATE_COMPLETED, UPDATE_FAILED, PATH_ERROR };
|
||||
@@ -114,7 +135,7 @@ enum UpdateStates { UPDATE_COMPLETED, UPDATE_FAILED, PATH_ERROR };
|
||||
enum distination {
|
||||
TO_MQTT,
|
||||
TO_WS,
|
||||
TO_MQTT_WS,
|
||||
TO_MQTT_WS
|
||||
};
|
||||
|
||||
#define WS_BROADCAST -1
|
||||
// #define WS_BROADCAST -1 // не используется
|
||||
|
||||
34
include/DebugTrace.h
Normal file
34
include/DebugTrace.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
// В папке toolchchain с которым собирались
|
||||
// (Для esp32 например %%USERPROFILE%/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin)
|
||||
// из командной строки Windows (cmd) запустить файл c параметрами:
|
||||
// xtensa-esp32-elf-addr2line.exe -pfiaC -e Путь_к_файлу/firmware.elf Стэк_адресов_из_сообщения
|
||||
// %%USERPROFILE%/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin xtensa-esp32-elf-addr2line.exe -pfiaC -e .pio/build/esp32_4mb3f/firmware.elf Стэк_адресов
|
||||
#include "Global.h"
|
||||
#if defined(ESP32) && !defined(esp32c3m_4mb) && !defined(esp32c6_4mb) && !defined(esp32c6_8mb)
|
||||
#define RESTART_DEBUG_INFO
|
||||
#endif
|
||||
#if defined(RESTART_DEBUG_INFO)
|
||||
#define CONFIG_RESTART_DEBUG_STACK_DEPTH 15
|
||||
typedef struct {
|
||||
size_t heap_total;
|
||||
size_t heap_free;
|
||||
size_t heap_free_min;
|
||||
time_t heap_min_time;
|
||||
uint32_t backtrace[CONFIG_RESTART_DEBUG_STACK_DEPTH];
|
||||
} re_restart_debug_t;
|
||||
__NOINIT_ATTR static int8_t bootloop_panic_count;
|
||||
|
||||
void IRAM_ATTR debugUpdate();
|
||||
#endif // RESTART_DEBUG_INFO
|
||||
|
||||
|
||||
|
||||
extern "C" void __real_esp_panic_handler(void*);
|
||||
void printDebugTrace();
|
||||
void sendDebugTraceAndFreeMemory(bool);
|
||||
|
||||
void startWatchDog();
|
||||
//extern "C" bool verifyRollbackLater();
|
||||
void verifyFirmware();
|
||||
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
#include "Global.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
#if defined (ESP8266) || defined(LIBRETINY)
|
||||
// эта библиотека встроена в ядро
|
||||
#include "ESPAsyncUDP.h"
|
||||
#else
|
||||
#elif defined(ESP32)
|
||||
#include "AsyncUDP.h"
|
||||
#endif
|
||||
#ifndef LIBRETINY
|
||||
extern AsyncUDP asyncUdp;
|
||||
#endif
|
||||
|
||||
extern const String getThisDevice();
|
||||
extern void addThisDeviceToList();
|
||||
|
||||
@@ -6,4 +6,4 @@ extern std::list<IoTItem*> IoTItems; // вектор ссылок базово
|
||||
|
||||
extern void configure(String path);
|
||||
void clearConfigure();
|
||||
extern IoTItem* myIoTItem;
|
||||
// extern IoTItem* myIoTItem; // экономим память, используется в одном месте
|
||||
|
||||
@@ -15,6 +15,18 @@ extern FS* filesystem;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LIBRETINY)
|
||||
#include <FS.h>
|
||||
|
||||
#include "LittleFS.h"
|
||||
|
||||
#define FileFS LittleFS
|
||||
#define FS_NAME "LittleFS_LT"
|
||||
#define FILE_READ "r"
|
||||
#define FILE_WRITE "w"
|
||||
#define FILE_APPEND "a"
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
#if USE_LITTLEFS
|
||||
#include "LittleFS.h"
|
||||
@@ -39,6 +51,7 @@ extern void globalVarsSync();
|
||||
// extern String getParamsJson();
|
||||
|
||||
extern void syncSettingsFlashJson();
|
||||
void resetSettingsFlashByPanic();
|
||||
extern void syncValuesFlashJson();
|
||||
|
||||
extern const String getChipId();
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
#include <PubSubClient.h>
|
||||
#include <list>
|
||||
|
||||
#ifdef LIBRETINY
|
||||
#include <vector>
|
||||
#include <typedef.h>
|
||||
#ifdef STANDARD_WEB_SERVER
|
||||
#include <WebServer.h>
|
||||
#endif
|
||||
#include <HTTPClient.h>
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#include "WiFi.h"
|
||||
#include <HTTPClient.h>
|
||||
@@ -22,6 +31,7 @@
|
||||
|
||||
#ifdef ASYNC_WEB_SERVER
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include "AsyncWebServer.h"
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD_WEB_SERVER
|
||||
@@ -50,7 +60,7 @@
|
||||
#include "utils/StringUtils.h"
|
||||
#include "PeriodicTasks.h"
|
||||
#include "classes/IoTGpio.h"
|
||||
|
||||
#include "classes/IoTDiscovery.h"
|
||||
/*********************************************************************************************************************
|
||||
*****************************************глобальные объекты классов***************************************************
|
||||
**********************************************************************************************************************/
|
||||
@@ -60,6 +70,9 @@ extern IoTItem* rtcItem;
|
||||
extern IoTItem* tlgrmItem;
|
||||
extern IoTBench* benchLoadItem;
|
||||
extern IoTBench* benchTaskItem;
|
||||
extern IoTDiscovery* HADiscovery;
|
||||
extern IoTDiscovery* HOMEdDiscovery;
|
||||
|
||||
|
||||
extern TickerScheduler ts;
|
||||
extern WiFiClient espClient;
|
||||
@@ -77,6 +90,9 @@ extern ESP8266HTTPUpdateServer httpUpdater;
|
||||
#ifdef ESP32
|
||||
extern WebServer HTTP;
|
||||
#endif
|
||||
#ifdef LIBRETINY
|
||||
extern WebServer HTTP;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD_WEB_SOCKETS
|
||||
@@ -108,6 +124,7 @@ extern int mqttPort;
|
||||
extern String mqttPrefix;
|
||||
extern String mqttUser;
|
||||
extern String mqttPass;
|
||||
extern String nameId;
|
||||
|
||||
extern unsigned long mqttUptime;
|
||||
extern unsigned long flashWriteNumber;
|
||||
@@ -146,6 +163,8 @@ extern Time_t _time_local;
|
||||
extern Time_t _time_utc;
|
||||
extern bool _time_isTrust;
|
||||
|
||||
#define WEBSOCKETS_CLIENT_MAX 5
|
||||
extern int8_t ws_clients[WEBSOCKETS_CLIENT_MAX];
|
||||
// extern unsigned long loopPeriod;
|
||||
|
||||
// extern DynamicJsonDocument settingsFlashJsonDoc;
|
||||
|
||||
@@ -29,8 +29,8 @@ bool publishChartFileToMqtt(String path, String id, int maxCount);
|
||||
void publishWidgets();
|
||||
|
||||
void mqttCallback(char* topic, uint8_t* payload, size_t length);
|
||||
void handleMqttStatus(bool send);
|
||||
void handleMqttStatus(bool send, int state);
|
||||
//void handleMqttStatus(bool send);
|
||||
void handleMqttStatus(bool send, int state = -1);
|
||||
|
||||
const String getStateStr(int e);
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ extern bool handleFileRead(String path);
|
||||
extern void handleFileUpload();
|
||||
extern void handleFileDelete();
|
||||
extern void handleFileCreate();
|
||||
extern void handleLocalOTA();
|
||||
extern void handleLocalOTA_Handler();
|
||||
extern void handleFileList();
|
||||
//void printDirectory(File dir, String& out);
|
||||
extern void handleStatus();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// #include "Upgrade.h"
|
||||
#ifdef ESP8266
|
||||
// #include "ESP8266.h"
|
||||
#else
|
||||
#elif ESP32
|
||||
#include <HTTPUpdate.h>
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@ extern bool upgradeFS(String path);
|
||||
extern bool upgradeBuild(String path);
|
||||
extern void restartEsp();
|
||||
|
||||
extern const String getBinPath(String file);
|
||||
extern const String getBinPath();
|
||||
extern void putUserDataToRam();
|
||||
extern void saveUserDataToFlash();
|
||||
extern void saveUpdeteStatus(String key, int val);
|
||||
@@ -19,6 +19,6 @@ void periodicWsSend();
|
||||
|
||||
void sendFileToWsByFrames(const String& filename, const String& header, const String& json, int client_id, size_t frameSize);
|
||||
void sendStringToWs(const String& header, String& payload, int client_id);
|
||||
|
||||
void disconnectWSClient(uint8_t client_id);
|
||||
void sendDeviceList(uint8_t num);
|
||||
int getNumWSClients();
|
||||
36
include/classes/IoTDiscovery.h
Normal file
36
include/classes/IoTDiscovery.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include "Global.h"
|
||||
#include "classes/IoTItem.h"
|
||||
|
||||
class IoTDiscovery : public IoTItem
|
||||
{
|
||||
public:
|
||||
IoTDiscovery(const String ¶meters);
|
||||
~IoTDiscovery();
|
||||
|
||||
// inline bool isDiscoveryHomed() { return HOMEd; }
|
||||
|
||||
// inline bool isDiscoveryHA() { return HA; }
|
||||
|
||||
String HOMEdTopic = "";
|
||||
String HATopic = "";
|
||||
//String ChipId = "";
|
||||
|
||||
virtual void mqttSubscribeDiscovery();
|
||||
|
||||
virtual void publishStatusHOMEd(const String &topic, const String &data);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
boolean publishRetain(const String &topic, const String &data);
|
||||
virtual void getlayoutHA();
|
||||
virtual void deleteFromHOMEd();
|
||||
virtual void getlayoutHOMEd();
|
||||
|
||||
//bool HOMEd = false;
|
||||
//bool HA = false;
|
||||
//String HOMEdTopic;
|
||||
|
||||
};
|
||||
@@ -4,6 +4,7 @@
|
||||
//#include "classes/IoTBench.h"
|
||||
|
||||
class IoTBench;
|
||||
class IoTDiscovery;
|
||||
|
||||
struct IoTValue {
|
||||
float valD = 0;
|
||||
@@ -58,8 +59,10 @@ class IoTItem {
|
||||
//virtual IoTItem* getCAMDriver();
|
||||
virtual IoTItem* getTlgrmDriver();
|
||||
//virtual IoTBench* getBenchmark();
|
||||
virtual IoTBench*getBenchmarkTask();
|
||||
virtual IoTBench*getBenchmarkLoad();
|
||||
virtual IoTBench* getBenchmarkTask();
|
||||
virtual IoTBench* getBenchmarkLoad();
|
||||
virtual IoTDiscovery* getHADiscovery();
|
||||
virtual IoTDiscovery* getHOMEdDiscovery();
|
||||
virtual unsigned long getRtcUnixTime();
|
||||
|
||||
// делаем доступным модулям отправку сообщений в телеграм
|
||||
|
||||
@@ -40,7 +40,7 @@ boolean isDigitDotCommaStr(const String& str);
|
||||
|
||||
String prettyBytes(size_t size);
|
||||
|
||||
String uint64ToString(uint64_t input, uint8_t base = 10);
|
||||
String uint64ToStringIoTM(uint64_t input, uint8_t base = 10);
|
||||
|
||||
void cleanString(String& str);
|
||||
|
||||
|
||||
@@ -4,8 +4,20 @@
|
||||
#include "MqttClient.h"
|
||||
boolean isNetworkActive();
|
||||
uint8_t getNumAPClients();
|
||||
void routerConnect();
|
||||
bool startAPMode();
|
||||
#ifdef ESP8266
|
||||
void routerConnect();
|
||||
boolean RouterFind(std::vector<String> jArray);
|
||||
#else
|
||||
void handleScanResults();
|
||||
void WiFiUtilsItit();
|
||||
void connectToNextNetwork();
|
||||
void checkConnection();
|
||||
void ScanAsync();
|
||||
|
||||
#endif
|
||||
uint8_t RSSIquality();
|
||||
extern void wifiSignalInit();
|
||||
//extern void wifiSignalInit();
|
||||
#ifdef LIBRETINY
|
||||
String httpGetString(HTTPClient &http);
|
||||
#endif
|
||||
63
lib/LT_WebSockets/.clang-format
Normal file
63
lib/LT_WebSockets/.clang-format
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: '-2'
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
AlignConsecutiveDeclarations: 'false'
|
||||
AlignEscapedNewlines: Left
|
||||
AlignTrailingComments: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||
AllowShortBlocksOnASingleLine: 'false'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: 'true'
|
||||
AllowShortLoopsOnASingleLine: 'true'
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: 'true'
|
||||
AlwaysBreakTemplateDeclarations: 'false'
|
||||
BinPackParameters: 'true'
|
||||
BreakAfterJavaFieldAnnotations: 'false'
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: 'false'
|
||||
BreakBeforeTernaryOperators: 'false'
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakStringLiterals: 'false'
|
||||
ColumnLimit: '0'
|
||||
CompactNamespaces: 'true'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
ConstructorInitializerIndentWidth: '4'
|
||||
ContinuationIndentWidth: '4'
|
||||
Cpp11BracedListStyle: 'false'
|
||||
DerivePointerAlignment: 'false'
|
||||
FixNamespaceComments: 'true'
|
||||
IndentCaseLabels: 'true'
|
||||
IndentWidth: '4'
|
||||
IndentWrappedFunctionNames: 'false'
|
||||
JavaScriptQuotes: Single
|
||||
JavaScriptWrapImports: 'false'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
MaxEmptyLinesToKeep: '1'
|
||||
NamespaceIndentation: All
|
||||
ObjCBlockIndentWidth: '4'
|
||||
ObjCSpaceAfterProperty: 'false'
|
||||
ObjCSpaceBeforeProtocolList: 'false'
|
||||
PointerAlignment: Middle
|
||||
SortIncludes: 'false'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpaceAfterCStyleCast: 'false'
|
||||
SpaceAfterTemplateKeyword: 'false'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeParens: Never
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesBeforeTrailingComments: '4'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
TabWidth: '4'
|
||||
UseTab: Never
|
||||
|
||||
...
|
||||
186
lib/LT_WebSockets/.github/workflows/main.yml
vendored
Normal file
186
lib/LT_WebSockets/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
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,dbg=Serial1
|
||||
echo -en ","
|
||||
|
||||
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.8.19 esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80
|
||||
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: |
|
||||
export DISPLAY=:1.0
|
||||
export PATH="$HOME/arduino_ide:$PATH"
|
||||
arduino --board $BOARD --save-prefs
|
||||
arduino --get-pref sketchbook.path
|
||||
arduino --pref update.check=false
|
||||
|
||||
- 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
|
||||
37
lib/LT_WebSockets/.gitignore
vendored
Normal file
37
lib/LT_WebSockets/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
/tests/webSocketServer/node_modules
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
*.swp
|
||||
|
||||
1
lib/LT_WebSockets/.piopm
Normal file
1
lib/LT_WebSockets/.piopm
Normal file
@@ -0,0 +1 @@
|
||||
{"type": "library", "name": "WebSockets", "version": "2.3.7", "spec": {"owner": "links2004", "id": 549, "name": "WebSockets", "requirements": null, "uri": null}}
|
||||
45
lib/LT_WebSockets/.travis.yml
Normal file
45
lib/LT_WebSockets/.travis.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
sudo: false
|
||||
dist:
|
||||
- xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- xvfb
|
||||
language: bash
|
||||
os:
|
||||
- linux
|
||||
env:
|
||||
matrix:
|
||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.13
|
||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.13
|
||||
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13
|
||||
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5
|
||||
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9
|
||||
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.13
|
||||
script:
|
||||
- /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
|
||||
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- mv arduino-$IDE_VERSION $HOME/arduino_ide
|
||||
- export PATH="$HOME/arduino_ide:$PATH"
|
||||
- which arduino
|
||||
- mkdir -p $HOME/Arduino/libraries
|
||||
|
||||
- wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip
|
||||
- unzip 6.x.zip
|
||||
- mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
||||
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
||||
- get_core $CPU
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- arduino --board $BOARD --save-prefs
|
||||
- arduino --get-pref sketchbook.path
|
||||
- arduino --pref update.check=false
|
||||
- build_sketches arduino $HOME/Arduino/libraries/arduinoWebSockets/examples/$CPU $CPU
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
502
lib/LT_WebSockets/LICENSE
Normal file
502
lib/LT_WebSockets/LICENSE
Normal file
@@ -0,0 +1,502 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
102
lib/LT_WebSockets/README.md
Normal file
102
lib/LT_WebSockets/README.md
Normal file
@@ -0,0 +1,102 @@
|
||||
WebSocket Server and Client for Arduino [](https://github.com/Links2004/arduinoWebSockets/actions?query=workflow%3ACI+branch%3Amaster)
|
||||
===========================================
|
||||
|
||||
a WebSocket Server and Client for Arduino based on RFC6455.
|
||||
|
||||
|
||||
##### Supported features of RFC6455 #####
|
||||
- text frame
|
||||
- binary frame
|
||||
- connection close
|
||||
- ping
|
||||
- pong
|
||||
- continuation frame
|
||||
|
||||
##### Limitations #####
|
||||
- max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define
|
||||
- max output length has no limit (the hardware is the limit)
|
||||
- Client send big frames with mask 0x00000000 (on AVR all frames)
|
||||
- continuation frame reassembly need to be handled in the application code
|
||||
|
||||
##### Limitations for Async #####
|
||||
- Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround.
|
||||
- wss / SSL is not possible.
|
||||
|
||||
##### Supported Hardware #####
|
||||
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
|
||||
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
|
||||
- ESP31B
|
||||
- Particle with STM32 ARM Cortex M3
|
||||
- ATmega328 with Ethernet Shield (ATmega branch)
|
||||
- ATmega328 with enc28j60 (ATmega branch)
|
||||
- ATmega2560 with Ethernet Shield (ATmega branch)
|
||||
- ATmega2560 with enc28j60 (ATmega branch)
|
||||
|
||||
###### Note: ######
|
||||
|
||||
version 2.0.0 and up is not compatible with AVR/ATmega, check ATmega branch.
|
||||
|
||||
version 2.3.0 has API changes for the ESP8266 BareSSL (may brakes existing code)
|
||||
|
||||
Arduino for AVR not supports std namespace of c++.
|
||||
|
||||
### wss / SSL ###
|
||||
supported for:
|
||||
- wss client on the ESP8266
|
||||
- wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets
|
||||
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
|
||||
sample Nginx server configuration file to enable this.
|
||||
|
||||
### ESP Async TCP ###
|
||||
|
||||
This libary can run in Async TCP mode on the ESP.
|
||||
|
||||
The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define).
|
||||
|
||||
[ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required.
|
||||
|
||||
|
||||
### High Level Client API ###
|
||||
|
||||
- `begin` : Initiate connection sequence to the websocket host.
|
||||
```c++
|
||||
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
||||
```
|
||||
- `onEvent`: Callback to handle for websocket events
|
||||
|
||||
```c++
|
||||
void onEvent(WebSocketClientEvent cbEvent);
|
||||
```
|
||||
|
||||
- `WebSocketClientEvent`: Handler for websocket events
|
||||
```c++
|
||||
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
|
||||
```
|
||||
Where `WStype_t type` is defined as:
|
||||
```c++
|
||||
typedef enum {
|
||||
WStype_ERROR,
|
||||
WStype_DISCONNECTED,
|
||||
WStype_CONNECTED,
|
||||
WStype_TEXT,
|
||||
WStype_BIN,
|
||||
WStype_FRAGMENT_TEXT_START,
|
||||
WStype_FRAGMENT_BIN_START,
|
||||
WStype_FRAGMENT,
|
||||
WStype_FRAGMENT_FIN,
|
||||
WStype_PING,
|
||||
WStype_PONG,
|
||||
} WStype_t;
|
||||
```
|
||||
|
||||
### Issues ###
|
||||
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
||||
|
||||
[](https://gitter.im/Links2004/arduinoWebSockets?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
### License and credits ###
|
||||
|
||||
The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE)
|
||||
|
||||
[libb64](http://libb64.sourceforge.net/) written by Chris Venter. It is distributed under Public Domain see [LICENSE](https://github.com/Links2004/arduinoWebSockets/blob/master/src/libb64/LICENSE).
|
||||
@@ -0,0 +1,83 @@
|
||||
# ESP8266 nginx SSL reverse proxy configuration file (tested and working on nginx v1.10.0)
|
||||
|
||||
# proxy cache location
|
||||
proxy_cache_path /opt/etc/nginx/cache levels=1:2 keys_zone=ESP8266_cache:10m max_size=10g inactive=5m use_temp_path=off;
|
||||
|
||||
# webserver proxy
|
||||
server {
|
||||
|
||||
# general server parameters
|
||||
listen 50080;
|
||||
server_name myDomain.net;
|
||||
access_log /opt/var/log/nginx/myDomain.net.access.log;
|
||||
|
||||
# SSL configuration
|
||||
ssl on;
|
||||
ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem;
|
||||
ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem;
|
||||
ssl_session_cache builtin:1000 shared:SSL:10m;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location / {
|
||||
|
||||
# proxy caching configuration
|
||||
proxy_cache ESP8266_cache;
|
||||
proxy_cache_revalidate on;
|
||||
proxy_cache_min_uses 1;
|
||||
proxy_cache_use_stale off;
|
||||
proxy_cache_lock on;
|
||||
# proxy_cache_bypass $http_cache_control;
|
||||
# include the sessionId cookie value as part of the cache key - keeps the cache per user
|
||||
# proxy_cache_key $proxy_host$request_uri$cookie_sessionId;
|
||||
|
||||
# header pass through configuration
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# ESP8266 custom headers which identify to the device that it's running through an SSL proxy
|
||||
proxy_set_header X-SSL On;
|
||||
proxy_set_header X-SSL-WebserverPort 50080;
|
||||
proxy_set_header X-SSL-WebsocketPort 50081;
|
||||
|
||||
# extra debug headers
|
||||
add_header X-Proxy-Cache $upstream_cache_status;
|
||||
add_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# actual proxying configuration
|
||||
proxy_ssl_session_reuse on;
|
||||
# target the IP address of the device with proxy_pass
|
||||
proxy_pass http://192.168.0.20;
|
||||
proxy_read_timeout 90;
|
||||
}
|
||||
}
|
||||
|
||||
# websocket proxy
|
||||
server {
|
||||
|
||||
# general server parameters
|
||||
listen 50081;
|
||||
server_name myDomain.net;
|
||||
access_log /opt/var/log/nginx/myDomain.net.wss.access.log;
|
||||
|
||||
# SSL configuration
|
||||
ssl on;
|
||||
ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem;
|
||||
ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem;
|
||||
ssl_session_cache builtin:1000 shared:SSL:10m;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location / {
|
||||
|
||||
# websocket upgrade tunnel configuration
|
||||
proxy_pass http://192.168.0.20:81;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* WebSocketClientAVR.ino
|
||||
*
|
||||
* Created on: 10.12.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
|
||||
// Enter a MAC address for your controller below.
|
||||
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
|
||||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
|
||||
// Set the static IP address to use if the DHCP fails to assign
|
||||
IPAddress ip(192, 168, 0, 177);
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
Serial.println("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
Serial.print("[WSc] Connected to url: ");
|
||||
Serial.println((char *)payload);
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
Serial.print("[WSc] get text: ");
|
||||
Serial.println((char *)payload);
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
Serial.print("[WSc] get binary length: ");
|
||||
Serial.println(length);
|
||||
// hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Open serial communications and wait for port to open:
|
||||
Serial.begin(115200);
|
||||
while (!Serial) {}
|
||||
|
||||
// start the Ethernet connection:
|
||||
if (Ethernet.begin(mac) == 0) {
|
||||
Serial.println("Failed to configure Ethernet using DHCP");
|
||||
// no point in carrying on, so do nothing forevermore:
|
||||
// try to congifure using IP address instead of DHCP:
|
||||
Ethernet.begin(mac, ip);
|
||||
}
|
||||
|
||||
webSocket.begin("192.168.0.123", 8011);
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* WebSocketClient.ino
|
||||
*
|
||||
* Created on: 24.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(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);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket.begin("192.168.0.123", 81, "/");
|
||||
|
||||
// event handler
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
// use HTTP Basic Authorization this is optional remove if not needed
|
||||
webSocket.setAuthorization("user", "Password");
|
||||
|
||||
// try ever 5000 again if connection has failed
|
||||
webSocket.setReconnectInterval(5000);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* WebSocketClientSSL.ino
|
||||
*
|
||||
* Created on: 10.12.2015
|
||||
*
|
||||
* note SSL is only possible with the ESP8266
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(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);
|
||||
}
|
||||
|
||||
webSocket.beginSSL("192.168.0.123", 81);
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* WebSocketClientSocketIOack.ino
|
||||
*
|
||||
* Created on: 20.07.2019
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
#include <SocketIOclient.h>
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
SocketIOclient socketIO;
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
|
||||
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case sIOtype_DISCONNECT:
|
||||
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||
break;
|
||||
case sIOtype_CONNECT:
|
||||
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||
|
||||
// join default namespace (no auto join in Socket.IO V3)
|
||||
socketIO.send(sIOtype_CONNECT, "/");
|
||||
break;
|
||||
case sIOtype_EVENT:
|
||||
{
|
||||
char * sptr = NULL;
|
||||
int id = strtol((char *)payload, &sptr, 10);
|
||||
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
|
||||
if(id) {
|
||||
payload = (uint8_t *)sptr;
|
||||
}
|
||||
DynamicJsonDocument doc(1024);
|
||||
DeserializationError error = deserializeJson(doc, payload, length);
|
||||
if(error) {
|
||||
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||
USE_SERIAL.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
String eventName = doc[0];
|
||||
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
||||
|
||||
// Message Includes a ID for a ACK (callback)
|
||||
if(id) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* WebSocketServer.ino
|
||||
*
|
||||
* Created on: 22.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <WebSocketsServer.h>
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendTXT(num, "message here");
|
||||
|
||||
// send data to all connected clients
|
||||
// webSocket.broadcastTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendBIN(num, payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* WebSocketClient.ino
|
||||
*
|
||||
* Created on: 24.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED: {
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_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.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
//WiFi.disconnect();
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket.begin("192.168.0.123", 81, "/");
|
||||
|
||||
// event handler
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
// use HTTP Basic Authorization this is optional remove if not needed
|
||||
webSocket.setAuthorization("user", "Password");
|
||||
|
||||
// try ever 5000 again if connection has failed
|
||||
webSocket.setReconnectInterval(5000);
|
||||
|
||||
// start heartbeat (optional)
|
||||
// ping server every 15000 ms
|
||||
// expect pong from server within 3000 ms
|
||||
// consider connection disconnected if pong is not received 2 times
|
||||
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,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.
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
"""Minimal example of Python websocket server
|
||||
handling OTA updates for ESP32 amd ESP8266
|
||||
|
||||
Check and upload of firmware works.
|
||||
Register and state function are jus for example.
|
||||
"""
|
||||
# pylint: disable=W0703,E1101
|
||||
import asyncio
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from os import listdir
|
||||
from os.path import join as join_pth
|
||||
from pathlib import Path
|
||||
|
||||
import websockets
|
||||
from packaging import version
|
||||
|
||||
# Logger settings
|
||||
logging.basicConfig(filename="ws_server.log")
|
||||
Logger = logging.getLogger('WS-OTA')
|
||||
Logger.addHandler(logging.StreamHandler())
|
||||
Logger.setLevel(logging.INFO)
|
||||
|
||||
# Path to directory with FW
|
||||
fw_path = join_pth(Path().absolute(), "firmware")
|
||||
|
||||
|
||||
def create_path(path: str) -> None:
|
||||
"""Check if path exist or create it"""
|
||||
Path(path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def shell(command):
|
||||
"""Handle execution of shell commands"""
|
||||
with subprocess.Popen(command, shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
universal_newlines=True
|
||||
) as process:
|
||||
for stdout_line in iter(process.stdout.readline, ""):
|
||||
Logger.debug(stdout_line)
|
||||
process.stdout.close()
|
||||
return_code = process.wait()
|
||||
Logger.debug("Shell returned: %s", return_code)
|
||||
|
||||
return process.returncode
|
||||
return None
|
||||
|
||||
|
||||
async def binary_send(websocket, fw_file):
|
||||
"""Read firmware file, divide it to chunks and send them"""
|
||||
with open(fw_file, "rb") as binaryfile:
|
||||
|
||||
while True:
|
||||
chunk = binaryfile.read(2048)
|
||||
if not chunk:
|
||||
break
|
||||
try:
|
||||
await websocket.send(chunk)
|
||||
except Exception as exception:
|
||||
Logger.exception(exception)
|
||||
return False
|
||||
time.sleep(0.2)
|
||||
|
||||
|
||||
def version_checker(name, vdev, vapp):
|
||||
"""Parse and compare FW version"""
|
||||
|
||||
if version.parse(vdev) < version.parse(vapp):
|
||||
Logger.info("Client(%s) version %s is smaller than %s: Go for update", name, vdev, vapp)
|
||||
return True
|
||||
Logger.info("Client(%s) version %s is greater or equal to %s: Not updating", name, vdev, vapp)
|
||||
return False
|
||||
|
||||
|
||||
class WsOtaHandler (threading.Thread):
|
||||
"""Thread handling ota update
|
||||
|
||||
Runing ota directly from message would kill WS
|
||||
as message bus would timeout.
|
||||
"""
|
||||
def __init__(self, name, message, websocket):
|
||||
threading.Thread.__init__(self, daemon=True)
|
||||
self.name = name
|
||||
self.msg = message
|
||||
self.websocket = websocket
|
||||
|
||||
def run(self, ):
|
||||
try:
|
||||
asyncio.run(self.start_)
|
||||
except Exception as exception:
|
||||
Logger.exception(exception)
|
||||
finally:
|
||||
pass
|
||||
|
||||
async def start_(self):
|
||||
"""Start _ota se asyncio future"""
|
||||
msg_task = asyncio.ensure_future(
|
||||
self._ota())
|
||||
|
||||
done, pending = await asyncio.wait(
|
||||
[msg_task],
|
||||
return_when=asyncio.FIRST_COMPLETED,
|
||||
)
|
||||
Logger.info("WS Ota Handler done: %s", done)
|
||||
for task in pending:
|
||||
task.cancel()
|
||||
|
||||
async def _ota(self):
|
||||
"""Check for new fw and update or pass"""
|
||||
device_name = self.msg['name']
|
||||
device_chip = self.msg['chip']
|
||||
device_version = self.msg['version']
|
||||
fw_version = ''
|
||||
fw_name = ''
|
||||
fw_device = ''
|
||||
|
||||
for filename in listdir(fw_path):
|
||||
fw_info = filename.split("-")
|
||||
fw_device = fw_info[0]
|
||||
if fw_device == device_name:
|
||||
fw_version = fw_info[1]
|
||||
fw_name = filename
|
||||
break
|
||||
|
||||
if not fw_version:
|
||||
Logger.info("Client(%s): No fw found!", device_name)
|
||||
msg = '{"type": "ota", "value":"ok"}'
|
||||
await self.websocket.send(msg)
|
||||
return
|
||||
|
||||
if not version_checker(device_name, device_version, fw_version):
|
||||
return
|
||||
|
||||
fw_file = join_pth(fw_path, fw_name)
|
||||
if device_chip == 'esp8266' and not fw_file.endswith('.gz'):
|
||||
# We can compress fw to make it smaller for upload
|
||||
fw_cpress = fw_file
|
||||
fw_file = fw_cpress + ".gz"
|
||||
cpress = f"gzip -9 {fw_cpress}"
|
||||
cstate = shell(cpress)
|
||||
if cstate:
|
||||
Logger.error("Cannot compress firmware: %s", fw_name)
|
||||
return
|
||||
|
||||
# Get size of fw
|
||||
size = Path(fw_file).stat().st_size
|
||||
|
||||
# Request ota mode
|
||||
msg = '{"type": "ota", "value":"go", "size":' + str(size) + '}'
|
||||
await self.websocket.send(msg)
|
||||
|
||||
# send file by chunks trough websocket
|
||||
await binary_send(self.websocket, fw_file)
|
||||
|
||||
|
||||
async def _register(websocket, message):
|
||||
mac = message.get('mac')
|
||||
name = message.get('name')
|
||||
Logger.info("Client(%s) mac: %s", name, mac)
|
||||
# Some code
|
||||
|
||||
response = {'response_type': 'registry', 'state': 'ok'}
|
||||
await websocket.send(json.dumps(response))
|
||||
|
||||
|
||||
async def _state(websocket, message):
|
||||
mac = message.get('mac')
|
||||
name = message.get('name')
|
||||
Logger.info("Client(%s) mac: %s", name, mac)
|
||||
# Some code
|
||||
|
||||
response = {'response_type': 'state', 'state': 'ok'}
|
||||
await websocket.send(json.dumps(response))
|
||||
|
||||
|
||||
async def _unhandleld(websocket, msg):
|
||||
Logger.info("Unhandled message from device: %s", str(msg))
|
||||
response = {'response_type': 'response', 'state': 'nok'}
|
||||
await websocket.send(json.dumps(response))
|
||||
|
||||
|
||||
async def _greetings(websocket, message):
|
||||
WsOtaHandler('thread_ota', copy.deepcopy(message), websocket).start()
|
||||
|
||||
|
||||
async def message_received(websocket, message) -> None:
|
||||
"""Handle incoming messages
|
||||
|
||||
Check if message contain json and run waned function
|
||||
"""
|
||||
switcher = {"greetings": _greetings,
|
||||
"register": _register,
|
||||
"state": _state
|
||||
}
|
||||
|
||||
if message[0:1] == "{":
|
||||
try:
|
||||
msg_json = json.loads(message)
|
||||
except Exception as exception:
|
||||
Logger.error(exception)
|
||||
return
|
||||
|
||||
type_ = msg_json.get('type')
|
||||
name = msg_json.get('name')
|
||||
func = switcher.get(type_, _unhandleld)
|
||||
Logger.debug("Client(%s)said: %s", name, type_)
|
||||
|
||||
try:
|
||||
await func(websocket, msg_json)
|
||||
except Exception as exception:
|
||||
Logger.error(exception)
|
||||
|
||||
|
||||
# pylint: disable=W0613
|
||||
async def ws_server(websocket, path) -> None:
|
||||
"""Run in cycle and wait for new messages"""
|
||||
async for message in websocket:
|
||||
await message_received(websocket, message)
|
||||
|
||||
|
||||
async def main():
|
||||
"""Server starter
|
||||
|
||||
Normal user can bind only port nubers greater than 1024
|
||||
"""
|
||||
async with websockets.serve(ws_server, "10.0.1.5", 8081):
|
||||
await asyncio.Future() # run forever
|
||||
|
||||
|
||||
create_path(fw_path)
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,2 @@
|
||||
packaging
|
||||
websockets
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* WebSocketClientSSL.ino
|
||||
*
|
||||
* Created on: 10.12.2015
|
||||
*
|
||||
* note SSL is only possible with the ESP8266
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(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);
|
||||
}
|
||||
|
||||
webSocket.beginSSL("192.168.0.123", 81);
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* WebSocketClientSSLWithCA.ino
|
||||
*
|
||||
* Created on: 27.10.2019
|
||||
*
|
||||
* note SSL is only possible with the ESP8266
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
|
||||
// Can be obtained with:
|
||||
// openssl s_client -showcerts -connect echo.websocket.org:443 </dev/null
|
||||
const char ENDPOINT_CA_CERT[] PROGMEM = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlGPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
//When using BearSSL, client certificate and private key can be set:
|
||||
//webSocket.setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||
//clientCert and clientPrivateKey can be of types (const char *, const char *) , or of types (BearSSL::X509List, BearSSL::PrivateKey)
|
||||
|
||||
webSocket.beginSslWithCA("echo.websocket.org", 443, "/", ENDPOINT_CA_CERT);
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* WebSocketClientSocketIO.ino
|
||||
*
|
||||
* Created on: 06.06.2016
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
#include <SocketIOclient.h>
|
||||
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
SocketIOclient socketIO;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
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:
|
||||
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
|
||||
break;
|
||||
case sIOtype_ACK:
|
||||
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_ERROR:
|
||||
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_BINARY_EVENT:
|
||||
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_BINARY_ACK:
|
||||
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// disable AP
|
||||
if(WiFi.getMode() & WIFI_AP) {
|
||||
WiFi.softAPdisconnect(true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* WebSocketClientSocketIOack.ino
|
||||
*
|
||||
* Created on: 20.07.2019
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
#include <SocketIOclient.h>
|
||||
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti 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);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_ERROR:
|
||||
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_BINARY_EVENT:
|
||||
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
case sIOtype_BINARY_ACK:
|
||||
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
//USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// disable AP
|
||||
if(WiFi.getMode() & WIFI_AP) {
|
||||
WiFi.softAPdisconnect(true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
WebSocketClientStomp.ino
|
||||
|
||||
Example for connecting and maintining a connection with a STOMP websocket connection.
|
||||
In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html).
|
||||
|
||||
Created on: 25.09.2017
|
||||
Author: Martin Becker <mgbckr>, Contact: becker@informatik.uni-wuerzburg.de
|
||||
*/
|
||||
|
||||
// PRE
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
|
||||
// LIBRARIES
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Hash.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
// SETTINGS
|
||||
|
||||
const char* wlan_ssid = "yourssid";
|
||||
const char* wlan_password = "somepassword";
|
||||
|
||||
const char* ws_host = "the.host.net";
|
||||
const int ws_port = 80;
|
||||
|
||||
// URL for STOMP endpoint.
|
||||
// For the default config of Spring's STOMP support, the default URL is "/socketentry/websocket".
|
||||
const char* stompUrl = "/socketentry/websocket"; // don't forget the leading "/" !!!
|
||||
|
||||
|
||||
// VARIABLES
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
/**
|
||||
* STOMP messages need to be NULL-terminated (i.e., \0 or \u0000).
|
||||
* However, when we send a String or a char[] array without specifying
|
||||
* a length, the size of the message payload is derived by strlen() internally,
|
||||
* thus dropping any NULL values appended to the "msg"-String.
|
||||
*
|
||||
* To solve this, we first convert the String to a NULL terminated char[] array
|
||||
* via "c_str" and set the length of the payload to include the NULL value.
|
||||
*/
|
||||
void sendMessage(String & msg) {
|
||||
webSocket.sendTXT(msg.c_str(), msg.length() + 1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
String msg = "CONNECT\r\naccept-version:1.1,1.0\r\nheart-beat:10000,10000\r\n\r\n";
|
||||
sendMessage(msg);
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
{
|
||||
// #####################
|
||||
// handle STOMP protocol
|
||||
// #####################
|
||||
|
||||
String text = (char*) payload;
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
if (text.startsWith("CONNECTED")) {
|
||||
|
||||
// subscribe to some channels
|
||||
|
||||
String msg = "SUBSCRIBE\nid:sub-0\ndestination:/user/queue/messages\n\n";
|
||||
sendMessage(msg);
|
||||
delay(1000);
|
||||
|
||||
// and send a message
|
||||
|
||||
msg = "SEND\ndestination:/app/message\n\n{\"user\":\"esp\",\"message\":\"Hello!\"}";
|
||||
sendMessage(msg);
|
||||
delay(1000);
|
||||
|
||||
} else {
|
||||
|
||||
// do something with messages
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
// setup serial
|
||||
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
// USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
|
||||
|
||||
// connect to WiFi
|
||||
|
||||
USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(wlan_ssid, wlan_password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
USE_SERIAL.print(".");
|
||||
}
|
||||
USE_SERIAL.println(" success.");
|
||||
USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP());
|
||||
|
||||
|
||||
// connect to websocket
|
||||
webSocket.begin(ws_host, ws_port, stompUrl);
|
||||
webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config
|
||||
// webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
WebSocketClientStompOverSockJs.ino
|
||||
|
||||
Example for connecting and maintining a connection with a SockJS+STOMP websocket connection.
|
||||
In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html).
|
||||
|
||||
Created on: 18.07.2017
|
||||
Author: Martin Becker <mgbckr>, Contact: becker@informatik.uni-wuerzburg.de
|
||||
*/
|
||||
|
||||
// PRE
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
|
||||
// LIBRARIES
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Hash.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
// SETTINGS
|
||||
|
||||
const char* wlan_ssid = "yourssid";
|
||||
const char* wlan_password = "somepassword";
|
||||
|
||||
const char* ws_host = "the.host.net";
|
||||
const int ws_port = 80;
|
||||
|
||||
// base URL for SockJS (websocket) connection
|
||||
// The complete URL will look something like this(cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36):
|
||||
// ws://<ws_host>:<ws_port>/<ws_baseurl>/<3digits>/<randomstring>/websocket
|
||||
// For the default config of Spring's SockJS/STOMP support, the default base URL is "/socketentry/".
|
||||
const char* ws_baseurl = "/socketentry/"; // don't forget leading and trailing "/" !!!
|
||||
|
||||
|
||||
// VARIABLES
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
{
|
||||
// #####################
|
||||
// handle SockJs+STOMP protocol
|
||||
// #####################
|
||||
|
||||
String text = (char*) payload;
|
||||
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
if (payload[0] == 'h') {
|
||||
|
||||
USE_SERIAL.println("Heartbeat!");
|
||||
|
||||
} else if (payload[0] == 'o') {
|
||||
|
||||
// on open connection
|
||||
char *msg = "[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]";
|
||||
webSocket.sendTXT(msg);
|
||||
|
||||
} else if (text.startsWith("a[\"CONNECTED")) {
|
||||
|
||||
// subscribe to some channels
|
||||
|
||||
char *msg = "[\"SUBSCRIBE\\nid:sub-0\\ndestination:/user/queue/messages\\n\\n\\u0000\"]";
|
||||
webSocket.sendTXT(msg);
|
||||
delay(1000);
|
||||
|
||||
// and send a message
|
||||
|
||||
msg = "[\"SEND\\ndestination:/app/message\\n\\n{\\\"user\\\":\\\"esp\\\",\\\"message\\\":\\\"Hello!\\\"}\\u0000\"]";
|
||||
webSocket.sendTXT(msg);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
// setup serial
|
||||
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
// USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
|
||||
|
||||
// connect to WiFi
|
||||
|
||||
USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(wlan_ssid, wlan_password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
USE_SERIAL.print(".");
|
||||
}
|
||||
USE_SERIAL.println(" success.");
|
||||
USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP());
|
||||
|
||||
|
||||
// #####################
|
||||
// create socket url according to SockJS protocol (cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36)
|
||||
// #####################
|
||||
String socketUrl = ws_baseurl;
|
||||
socketUrl += random(0, 999);
|
||||
socketUrl += "/";
|
||||
socketUrl += random(0, 999999); // should be a random string, but this works (see )
|
||||
socketUrl += "/websocket";
|
||||
|
||||
// connect to websocket
|
||||
webSocket.begin(ws_host, ws_port, socketUrl);
|
||||
webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config
|
||||
// webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* WebSocketServer.ino
|
||||
*
|
||||
* Created on: 22.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendTXT(num, "message here");
|
||||
|
||||
// send data to all connected clients
|
||||
// webSocket.broadcastTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendBIN(num, payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* WebSocketServerAllFunctionsDemo.ino
|
||||
*
|
||||
* Created on: 10.05.2018
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <Hash.h>
|
||||
|
||||
#define LED_RED 15
|
||||
#define LED_GREEN 12
|
||||
#define LED_BLUE 13
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED: {
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
|
||||
if(payload[0] == '#') {
|
||||
// we get RGB data
|
||||
|
||||
// decode rgb data
|
||||
uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
|
||||
analogWrite(LED_RED, ((rgb >> 16) & 0xFF));
|
||||
analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF));
|
||||
analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
//USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
pinMode(LED_RED, OUTPUT);
|
||||
pinMode(LED_GREEN, OUTPUT);
|
||||
pinMode(LED_BLUE, OUTPUT);
|
||||
|
||||
digitalWrite(LED_RED, 1);
|
||||
digitalWrite(LED_GREEN, 1);
|
||||
digitalWrite(LED_BLUE, 1);
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// start webSocket server
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
if(MDNS.begin("esp8266")) {
|
||||
USE_SERIAL.println("MDNS responder started");
|
||||
}
|
||||
|
||||
// handle index
|
||||
server.on("/", []() {
|
||||
// send index.html
|
||||
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/></body></html>");
|
||||
});
|
||||
|
||||
server.begin();
|
||||
|
||||
// Add service to MDNS
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("ws", "tcp", 81);
|
||||
|
||||
digitalWrite(LED_RED, 0);
|
||||
digitalWrite(LED_GREEN, 0);
|
||||
digitalWrite(LED_BLUE, 0);
|
||||
|
||||
}
|
||||
|
||||
unsigned long last_10sec = 0;
|
||||
unsigned int counter = 0;
|
||||
|
||||
void loop() {
|
||||
unsigned long t = millis();
|
||||
webSocket.loop();
|
||||
server.handleClient();
|
||||
|
||||
if((t - last_10sec) > 10 * 1000) {
|
||||
counter++;
|
||||
bool ping = (counter % 2);
|
||||
int i = webSocket.connectedClients(ping);
|
||||
USE_SERIAL.printf("%d Connected websocket clients ping: %d\n", i, ping);
|
||||
last_10sec = millis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* WebSocketServer.ino
|
||||
*
|
||||
* Created on: 22.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
String fragmentBuffer = "";
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED: {
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||
hexdump(payload, length);
|
||||
break;
|
||||
|
||||
// Fragmentation / continuation opcode handling
|
||||
// case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
fragmentBuffer = (char*)payload;
|
||||
USE_SERIAL.printf("[%u] get start start of Textfragment: %s\n", num, payload);
|
||||
break;
|
||||
case WStype_FRAGMENT:
|
||||
fragmentBuffer += (char*)payload;
|
||||
USE_SERIAL.printf("[%u] get Textfragment : %s\n", num, payload);
|
||||
break;
|
||||
case WStype_FRAGMENT_FIN:
|
||||
fragmentBuffer += (char*)payload;
|
||||
USE_SERIAL.printf("[%u] get end of Textfragment: %s\n", num, payload);
|
||||
USE_SERIAL.printf("[%u] full frame: %s\n", num, fragmentBuffer.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* WebSocketServerHooked.ino
|
||||
*
|
||||
* Created on: 22.05.2015
|
||||
* Hooked on: 28.10.2020
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSockets4WebServer.h>
|
||||
#include <Hash.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
WebSockets4WebServer webSocket;
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendTXT(num, "message here");
|
||||
|
||||
// send data to all connected clients
|
||||
// webSocket.broadcastTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send message to client
|
||||
// webSocket.sendBIN(num, payload, length);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
server.on("/", []() {
|
||||
server.send(200, "text/plain", "I am a regular webserver on port 80!\r\n");
|
||||
server.send(200, "text/plain", "I am also a websocket server on '/ws' on the same port 80\r\n");
|
||||
});
|
||||
|
||||
server.addHook(webSocket.hookForWebserver("/ws", webSocketEvent));
|
||||
|
||||
server.begin();
|
||||
Serial.println("HTTP server started on port 80");
|
||||
Serial.println("WebSocket server started on the same port");
|
||||
Serial.printf("my network address is either 'arduinoWebsockets.local' (mDNS) or '%s'\n", WiFi.localIP().toString().c_str());
|
||||
|
||||
if (!MDNS.begin("arduinoWebsockets")) {
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
server.handleClient();
|
||||
webSocket.loop();
|
||||
MDNS.update();
|
||||
}
|
||||
20
lib/LT_WebSockets/examples/esp8266/WebSocketServerHooked/emu
Normal file
20
lib/LT_WebSockets/examples/esp8266/WebSocketServerHooked/emu
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# linux script to compile&run arduinoWebSockets in a mock environment
|
||||
|
||||
if [ -z "$ESP8266ARDUINO" ]; then
|
||||
echo "please set ESP8266ARDUINO env-var to where esp8266/arduino sits"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
where=$(pwd)
|
||||
|
||||
cd $ESP8266ARDUINO/tests/host/
|
||||
|
||||
make -j FORCE32=0 \
|
||||
ULIBDIRS=../../libraries/Hash/:~/dev/proj/arduino/libraries/arduinoWebSockets \
|
||||
${where}/WebSocketServerHooked
|
||||
|
||||
valgrind ./bin/WebSocketServerHooked/WebSocketServerHooked -b "$@"
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# python websocket client to test with
|
||||
# emulator: server is at ws://127.0.0.1:9080/ws
|
||||
# esp8266: server is at ws:///ws
|
||||
# (uncomment the right line below)
|
||||
|
||||
#uri = "ws://127.0.0.1:9080/ws"
|
||||
uri = "ws://arduinoWebsockets.local/ws"
|
||||
|
||||
import websocket
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
import _thread as thread
|
||||
import time
|
||||
|
||||
def on_message(ws, message):
|
||||
print("message");
|
||||
print(message)
|
||||
|
||||
def on_error(ws, error):
|
||||
print("error")
|
||||
print(error)
|
||||
|
||||
def on_close(ws):
|
||||
print("### closed ###")
|
||||
|
||||
def on_open(ws):
|
||||
print("opened")
|
||||
def run(*args):
|
||||
for i in range(3):
|
||||
time.sleep(1)
|
||||
ws.send("Hello %d" % i)
|
||||
time.sleep(1)
|
||||
ws.close()
|
||||
print("thread terminating...")
|
||||
thread.start_new_thread(run, ())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
websocket.enableTrace(True)
|
||||
ws = websocket.WebSocketApp(uri, on_message = on_message, on_error = on_error, on_close = on_close)
|
||||
ws.on_open = on_open
|
||||
ws.run_forever()
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* WebSocketServerHttpHeaderValidation.ino
|
||||
*
|
||||
* Created on: 08.06.2016
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <Hash.h>
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
const unsigned long int validSessionId = 12345; //some arbitrary value to act as a valid sessionId
|
||||
|
||||
/*
|
||||
* Returns a bool value as an indicator to describe whether a user is allowed to initiate a websocket upgrade
|
||||
* based on the value of a cookie. This function expects the rawCookieHeaderValue to look like this "sessionId=<someSessionIdNumberValue>|"
|
||||
*/
|
||||
bool isCookieValid(String rawCookieHeaderValue) {
|
||||
|
||||
if (rawCookieHeaderValue.indexOf("sessionId") != -1) {
|
||||
String sessionIdStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("sessionId=") + 10, rawCookieHeaderValue.indexOf("|"));
|
||||
unsigned long int sessionId = strtoul(sessionIdStr.c_str(), NULL, 10);
|
||||
return sessionId == validSessionId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader
|
||||
*/
|
||||
bool validateHttpHeader(String headerName, String headerValue) {
|
||||
|
||||
//assume a true response for any headers not handled by this validator
|
||||
bool valid = true;
|
||||
|
||||
if(headerName.equalsIgnoreCase("Cookie")) {
|
||||
//if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function
|
||||
valid = isCookieValid(headerValue);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
//connecting clients must supply a valid session cookie at websocket upgrade handshake negotiation time
|
||||
const char * headerkeys[] = { "Cookie" };
|
||||
size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*);
|
||||
webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount);
|
||||
webSocket.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* WebSocketServer_LEDcontrol.ino
|
||||
*
|
||||
* Created on: 26.11.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <Hash.h>
|
||||
|
||||
#define LED_RED 15
|
||||
#define LED_GREEN 12
|
||||
#define LED_BLUE 13
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
|
||||
ESP8266WiFiMulti WiFiMulti;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||
break;
|
||||
case WStype_CONNECTED: {
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||
|
||||
if(payload[0] == '#') {
|
||||
// we get RGB data
|
||||
|
||||
// decode rgb data
|
||||
uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
|
||||
analogWrite(LED_RED, ((rgb >> 16) & 0xFF));
|
||||
analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF));
|
||||
analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
//USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
pinMode(LED_RED, OUTPUT);
|
||||
pinMode(LED_GREEN, OUTPUT);
|
||||
pinMode(LED_BLUE, OUTPUT);
|
||||
|
||||
digitalWrite(LED_RED, 1);
|
||||
digitalWrite(LED_GREEN, 1);
|
||||
digitalWrite(LED_BLUE, 1);
|
||||
|
||||
WiFiMulti.addAP("SSID", "passpasspass");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// start webSocket server
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
if(MDNS.begin("esp8266")) {
|
||||
USE_SERIAL.println("MDNS responder started");
|
||||
}
|
||||
|
||||
// handle index
|
||||
server.on("/", []() {
|
||||
// send index.html
|
||||
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/></body></html>");
|
||||
});
|
||||
|
||||
server.begin();
|
||||
|
||||
// Add service to MDNS
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("ws", "tcp", 81);
|
||||
|
||||
digitalWrite(LED_RED, 0);
|
||||
digitalWrite(LED_GREEN, 0);
|
||||
digitalWrite(LED_BLUE, 0);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
server.handleClient();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* To compile using make CLI, create a folder under \firmware\user\applications and copy application.cpp there.
|
||||
* Then, copy src files under particleWebSocket folder.
|
||||
*/
|
||||
|
||||
#include "application.h"
|
||||
#include "particleWebSocket/WebSocketsClient.h"
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t* payload, size_t length)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case WStype_DISCONNECTED:
|
||||
Serial.printlnf("[WSc] Disconnected!");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
Serial.printlnf("[WSc] Connected to URL: %s", payload);
|
||||
webSocket.sendTXT("Connected\r\n");
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
Serial.printlnf("[WSc] get text: %s", payload);
|
||||
break;
|
||||
case WStype_BIN:
|
||||
Serial.printlnf("[WSc] get binary length: %u", length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
WiFi.setCredentials("[SSID]", "[PASSWORD]", WPA2, WLAN_CIPHER_AES_TKIP);
|
||||
WiFi.connect();
|
||||
|
||||
webSocket.begin("192.168.1.153", 85, "/ClientService/?variable=Test1212");
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
webSocket.sendTXT("Hello world!");
|
||||
delay(500);
|
||||
webSocket.loop();
|
||||
}
|
||||
25
lib/LT_WebSockets/library.json
Normal file
25
lib/LT_WebSockets/library.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"authors": [
|
||||
{
|
||||
"maintainer": true,
|
||||
"name": "Markus Sattler",
|
||||
"url": "https://github.com/Links2004"
|
||||
}
|
||||
],
|
||||
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
||||
"export": {
|
||||
"exclude": [
|
||||
"tests"
|
||||
]
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"keywords": "wifi, http, web, server, client, websocket",
|
||||
"license": "LGPL-2.1",
|
||||
"name": "LT_WebSockets",
|
||||
"platforms": "atmelavr, espressif8266, espressif32",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
||||
},
|
||||
"version": "2.3.7"
|
||||
}
|
||||
9
lib/LT_WebSockets/library.properties
Normal file
9
lib/LT_WebSockets/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=LT_WebSockets
|
||||
version=2.3.7
|
||||
author=Markus Sattler
|
||||
maintainer=Markus Sattler
|
||||
sentence=WebSockets for Arduino (Server + Client)
|
||||
paragraph=use 2.x.x for ESP and 1.3 for AVR
|
||||
category=Communication
|
||||
url=https://github.com/Links2004/arduinoWebSockets
|
||||
architectures=*
|
||||
260
lib/LT_WebSockets/src/SocketIOclient.cpp
Normal file
260
lib/LT_WebSockets/src/SocketIOclient.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SocketIOclient.cpp
|
||||
*
|
||||
* Created on: May 12, 2018
|
||||
* Author: links
|
||||
*/
|
||||
|
||||
#include "WebSockets.h"
|
||||
#include "WebSocketsClient.h"
|
||||
#include "SocketIOclient.h"
|
||||
|
||||
SocketIOclient::SocketIOclient() {
|
||||
}
|
||||
|
||||
SocketIOclient::~SocketIOclient() {
|
||||
}
|
||||
|
||||
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||
initClient();
|
||||
}
|
||||
|
||||
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
|
||||
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||
initClient();
|
||||
}
|
||||
#if defined(HAS_SSL)
|
||||
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||
initClient();
|
||||
}
|
||||
|
||||
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) {
|
||||
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||
initClient();
|
||||
}
|
||||
#if defined(SSL_BARESSL)
|
||||
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::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) {
|
||||
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||
initClient();
|
||||
}
|
||||
|
||||
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||
}
|
||||
|
||||
void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SocketIOclient::configureEIOping(bool disableHeartbeat) {
|
||||
_disableHeartbeat = disableHeartbeat;
|
||||
}
|
||||
|
||||
void SocketIOclient::initClient(void) {
|
||||
if(_client.cUrl.indexOf("EIO=4") != -1) {
|
||||
DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n");
|
||||
configureEIOping(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set callback function
|
||||
* @param cbEvent SocketIOclientEvent
|
||||
*/
|
||||
void SocketIOclient::onEvent(SocketIOclientEvent cbEvent) {
|
||||
_cbEvent = cbEvent;
|
||||
}
|
||||
|
||||
bool SocketIOclient::isConnected(void) {
|
||||
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
|
||||
* @param num uint8_t client id
|
||||
* @param type socketIOmessageType_t
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
bool ret = false;
|
||||
if(length == 0) {
|
||||
length = strlen((const char *)payload);
|
||||
}
|
||||
if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) {
|
||||
if(!headerToPayload) {
|
||||
// webSocket Header
|
||||
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
|
||||
// Engine.IO / Socket.IO Header
|
||||
if(ret) {
|
||||
uint8_t buf[3] = { eIOtype_MESSAGE, type, 0x00 };
|
||||
ret = WebSocketsClient::write(&_client, buf, 2);
|
||||
}
|
||||
if(ret && payload && length > 0) {
|
||||
ret = WebSocketsClient::write(&_client, payload, length);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
// TODO implement
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SocketIOclient::send(socketIOmessageType_t type, const uint8_t * payload, size_t length) {
|
||||
return send(type, (uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool SocketIOclient::send(socketIOmessageType_t type, char * payload, size_t length, bool headerToPayload) {
|
||||
return send(type, (uint8_t *)payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool SocketIOclient::send(socketIOmessageType_t type, const char * payload, size_t length) {
|
||||
return send(type, (uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool SocketIOclient::send(socketIOmessageType_t type, String & payload) {
|
||||
return send(type, (uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* send text data to client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
return send(sIOtype_EVENT, payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) {
|
||||
return sendEVENT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool SocketIOclient::sendEVENT(char * payload, size_t length, bool headerToPayload) {
|
||||
return sendEVENT((uint8_t *)payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool SocketIOclient::sendEVENT(const char * payload, size_t length) {
|
||||
return sendEVENT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool SocketIOclient::sendEVENT(String & payload) {
|
||||
return sendEVENT((uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
void SocketIOclient::loop(void) {
|
||||
WebSocketsClient::loop();
|
||||
unsigned long t = millis();
|
||||
if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) {
|
||||
_lastHeartbeat = t;
|
||||
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
||||
WebSocketsClient::sendTXT(eIOtype_PING);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
runIOCbEvent(sIOtype_DISCONNECT, NULL, 0);
|
||||
DEBUG_WEBSOCKETS("[wsIOc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED: {
|
||||
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
|
||||
// send message to server when Connected
|
||||
// Engine.io upgrade confirmation message (required)
|
||||
WebSocketsClient::sendTXT("2probe");
|
||||
WebSocketsClient::sendTXT(eIOtype_UPGRADE);
|
||||
runIOCbEvent(sIOtype_CONNECT, payload, length);
|
||||
} break;
|
||||
case WStype_TEXT: {
|
||||
if(length < 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
engineIOmessageType_t eType = (engineIOmessageType_t)payload[0];
|
||||
switch(eType) {
|
||||
case eIOtype_PING:
|
||||
payload[0] = eIOtype_PONG;
|
||||
DEBUG_WEBSOCKETS("[wsIOc] get ping send pong (%s)\n", payload);
|
||||
WebSocketsClient::sendTXT(payload, length, false);
|
||||
break;
|
||||
case eIOtype_PONG:
|
||||
DEBUG_WEBSOCKETS("[wsIOc] get pong\n");
|
||||
break;
|
||||
case eIOtype_MESSAGE: {
|
||||
if(length < 2) {
|
||||
break;
|
||||
}
|
||||
socketIOmessageType_t ioType = (socketIOmessageType_t)payload[1];
|
||||
uint8_t * data = &payload[2];
|
||||
size_t lData = length - 2;
|
||||
switch(ioType) {
|
||||
case sIOtype_EVENT:
|
||||
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
|
||||
break;
|
||||
case sIOtype_CONNECT:
|
||||
DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data);
|
||||
return;
|
||||
case sIOtype_DISCONNECT:
|
||||
case sIOtype_ACK:
|
||||
case sIOtype_ERROR:
|
||||
case sIOtype_BINARY_EVENT:
|
||||
case sIOtype_BINARY_ACK:
|
||||
default:
|
||||
DEBUG_WEBSOCKETS("[wsIOc] Socket.IO Message Type %c (%02X) is not implemented\n", ioType, ioType);
|
||||
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||
break;
|
||||
}
|
||||
|
||||
runIOCbEvent(ioType, data, lData);
|
||||
} break;
|
||||
case eIOtype_OPEN:
|
||||
case eIOtype_CLOSE:
|
||||
case eIOtype_UPGRADE:
|
||||
case eIOtype_NOOP:
|
||||
default:
|
||||
DEBUG_WEBSOCKETS("[wsIOc] Engine.IO Message Type %c (%02X) is not implemented\n", eType, eType);
|
||||
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case WStype_ERROR:
|
||||
case WStype_BIN:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
case WStype_PING:
|
||||
case WStype_PONG:
|
||||
break;
|
||||
}
|
||||
}
|
||||
105
lib/LT_WebSockets/src/SocketIOclient.h
Normal file
105
lib/LT_WebSockets/src/SocketIOclient.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* SocketIOclient.h
|
||||
*
|
||||
* Created on: May 12, 2018
|
||||
* Author: links
|
||||
*/
|
||||
|
||||
#ifndef SOCKETIOCLIENT_H_
|
||||
#define SOCKETIOCLIENT_H_
|
||||
|
||||
#include "WebSockets.h"
|
||||
#include "WebSocketsClient.h"
|
||||
|
||||
#define EIO_HEARTBEAT_INTERVAL 20000
|
||||
|
||||
#define EIO_MAX_HEADER_SIZE (WEBSOCKETS_MAX_HEADER_SIZE + 1)
|
||||
#define SIO_MAX_HEADER_SIZE (EIO_MAX_HEADER_SIZE + 1)
|
||||
|
||||
typedef enum {
|
||||
eIOtype_OPEN = '0', ///< Sent from the server when a new transport is opened (recheck)
|
||||
eIOtype_CLOSE = '1', ///< Request the close of this transport but does not shutdown the connection itself.
|
||||
eIOtype_PING = '2', ///< Sent by the client. Server should answer with a pong packet containing the same data
|
||||
eIOtype_PONG = '3', ///< Sent by the server to respond to ping packets.
|
||||
eIOtype_MESSAGE = '4', ///< actual message, client and server should call their callbacks with the data
|
||||
eIOtype_UPGRADE = '5', ///< Before engine.io switches a transport, it tests, if server and client can communicate over this transport. If this test succeed, the client sends an upgrade packets which requests the server to flush its cache on the old transport and switch to the new transport.
|
||||
eIOtype_NOOP = '6', ///< A noop packet. Used primarily to force a poll cycle when an incoming websocket connection is received.
|
||||
} engineIOmessageType_t;
|
||||
|
||||
typedef enum {
|
||||
sIOtype_CONNECT = '0',
|
||||
sIOtype_DISCONNECT = '1',
|
||||
sIOtype_EVENT = '2',
|
||||
sIOtype_ACK = '3',
|
||||
sIOtype_ERROR = '4',
|
||||
sIOtype_BINARY_EVENT = '5',
|
||||
sIOtype_BINARY_ACK = '6',
|
||||
} socketIOmessageType_t;
|
||||
|
||||
class SocketIOclient : protected WebSocketsClient {
|
||||
public:
|
||||
#ifdef __AVR__
|
||||
typedef void (*SocketIOclientEvent)(socketIOmessageType_t type, uint8_t * payload, size_t length);
|
||||
#else
|
||||
typedef std::function<void(socketIOmessageType_t type, uint8_t * payload, size_t length)> SocketIOclientEvent;
|
||||
#endif
|
||||
|
||||
SocketIOclient(void);
|
||||
virtual ~SocketIOclient(void);
|
||||
|
||||
void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||
void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||
|
||||
#ifdef HAS_SSL
|
||||
void beginSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||
void beginSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||
#ifndef SSL_AXTLS
|
||||
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||
#endif
|
||||
#endif
|
||||
bool isConnected(void);
|
||||
|
||||
void onEvent(SocketIOclientEvent cbEvent);
|
||||
|
||||
bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendEVENT(const uint8_t * payload, size_t length = 0);
|
||||
bool sendEVENT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendEVENT(const char * payload, size_t length = 0);
|
||||
bool sendEVENT(String & payload);
|
||||
|
||||
bool send(socketIOmessageType_t type, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool send(socketIOmessageType_t type, const uint8_t * payload, size_t length = 0);
|
||||
bool send(socketIOmessageType_t type, char * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
||||
bool send(socketIOmessageType_t type, String & payload);
|
||||
|
||||
void setExtraHeaders(const char * extraHeaders = NULL);
|
||||
void setReconnectInterval(unsigned long time);
|
||||
|
||||
void loop(void);
|
||||
|
||||
void configureEIOping(bool disableHeartbeat = false);
|
||||
|
||||
protected:
|
||||
bool _disableHeartbeat = false;
|
||||
uint64_t _lastHeartbeat = 0;
|
||||
SocketIOclientEvent _cbEvent;
|
||||
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||
if(_cbEvent) {
|
||||
_cbEvent(type, payload, length);
|
||||
}
|
||||
}
|
||||
|
||||
void initClient(void);
|
||||
|
||||
// Handeling events from websocket layer
|
||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
handleCbEvent(type, payload, length);
|
||||
}
|
||||
void handleCbEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
};
|
||||
|
||||
#endif /* SOCKETIOCLIENT_H_ */
|
||||
776
lib/LT_WebSockets/src/WebSockets.cpp
Normal file
776
lib/LT_WebSockets/src/WebSockets.cpp
Normal file
@@ -0,0 +1,776 @@
|
||||
/**
|
||||
* @file WebSockets.cpp
|
||||
* @date 20.05.2015
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "WebSockets.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <core_esp8266_features.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#if defined CORE_HAS_LIBB64 || defined LIBRETINY
|
||||
#include <libb64/cencode.h>
|
||||
#else
|
||||
#include "libb64/cencode_inc.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <Hash.h>
|
||||
#elif defined(ESP32)
|
||||
#include <esp_system.h>
|
||||
|
||||
#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>
|
||||
#endif
|
||||
#else
|
||||
#include <hwcrypto/sha.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if defined LIBRETINY
|
||||
extern "C" {
|
||||
#include <typedef.h>
|
||||
#include <crypto/sha1_i.h>
|
||||
}
|
||||
#else
|
||||
extern "C" {
|
||||
#include "libsha1/libsha1.h"
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @param code uint16_t see RFC
|
||||
* @param reason ptr to the disconnect reason message
|
||||
* @param reasonLen length of the disconnect reason message
|
||||
*/
|
||||
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] clientDisconnect code: %u\n", client->num, code);
|
||||
if(client->status == WSC_CONNECTED && code) {
|
||||
if(reason) {
|
||||
sendFrame(client, WSop_close, (uint8_t *)reason, reasonLen);
|
||||
} else {
|
||||
uint8_t buffer[2];
|
||||
buffer[0] = ((code >> 8) & 0xFF);
|
||||
buffer[1] = (code & 0xFF);
|
||||
sendFrame(client, WSop_close, &buffer[0], 2);
|
||||
}
|
||||
}
|
||||
clientDisconnect(client);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buf uint8_t * ptr to the buffer for writing
|
||||
* @param opcode WSopcode_t
|
||||
* @param length size_t length of the payload
|
||||
* @param mask bool add dummy mask to the frame (needed for web browser)
|
||||
* @param maskkey uint8_t[4] key used for payload
|
||||
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||
*/
|
||||
uint8_t WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) {
|
||||
uint8_t headerSize;
|
||||
// calculate header Size
|
||||
if(length < 126) {
|
||||
headerSize = 2;
|
||||
} else if(length < 0xFFFF) {
|
||||
headerSize = 4;
|
||||
} else {
|
||||
headerSize = 10;
|
||||
}
|
||||
|
||||
if(mask) {
|
||||
headerSize += 4;
|
||||
}
|
||||
|
||||
// create header
|
||||
|
||||
// byte 0
|
||||
*headerPtr = 0x00;
|
||||
if(fin) {
|
||||
*headerPtr |= bit(7); ///< set Fin
|
||||
}
|
||||
*headerPtr |= opcode; ///< set opcode
|
||||
headerPtr++;
|
||||
|
||||
// byte 1
|
||||
*headerPtr = 0x00;
|
||||
if(mask) {
|
||||
*headerPtr |= bit(7); ///< set mask
|
||||
}
|
||||
|
||||
if(length < 126) {
|
||||
*headerPtr |= length;
|
||||
headerPtr++;
|
||||
} else if(length < 0xFFFF) {
|
||||
*headerPtr |= 126;
|
||||
headerPtr++;
|
||||
*headerPtr = ((length >> 8) & 0xFF);
|
||||
headerPtr++;
|
||||
*headerPtr = (length & 0xFF);
|
||||
headerPtr++;
|
||||
} else {
|
||||
// Normally we never get here (to less memory)
|
||||
*headerPtr |= 127;
|
||||
headerPtr++;
|
||||
*headerPtr = 0x00;
|
||||
headerPtr++;
|
||||
*headerPtr = 0x00;
|
||||
headerPtr++;
|
||||
*headerPtr = 0x00;
|
||||
headerPtr++;
|
||||
*headerPtr = 0x00;
|
||||
headerPtr++;
|
||||
*headerPtr = ((length >> 24) & 0xFF);
|
||||
headerPtr++;
|
||||
*headerPtr = ((length >> 16) & 0xFF);
|
||||
headerPtr++;
|
||||
*headerPtr = ((length >> 8) & 0xFF);
|
||||
headerPtr++;
|
||||
*headerPtr = (length & 0xFF);
|
||||
headerPtr++;
|
||||
}
|
||||
|
||||
if(mask) {
|
||||
*headerPtr = maskKey[0];
|
||||
headerPtr++;
|
||||
*headerPtr = maskKey[1];
|
||||
headerPtr++;
|
||||
*headerPtr = maskKey[2];
|
||||
headerPtr++;
|
||||
*headerPtr = maskKey[3];
|
||||
headerPtr++;
|
||||
}
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @param opcode WSopcode_t
|
||||
* @param length size_t length of the payload
|
||||
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSockets::sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length, bool fin) {
|
||||
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
||||
|
||||
uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin);
|
||||
|
||||
if(write(client, &buffer[0], headerSize) != headerSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @param opcode WSopcode_t
|
||||
* @param payload uint8_t * ptr to the payload
|
||||
* @param length size_t length of the payload
|
||||
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||
* @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin, bool headerToPayload) {
|
||||
if(client->tcp && !client->tcp->connected()) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client->status != WSC_CONNECTED) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send message frame -------\n", client->num);
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] fin: %u opCode: %u mask: %u length: %u headerToPayload: %u\n", client->num, fin, opcode, client->cIsClient, length, headerToPayload);
|
||||
|
||||
if(opcode == WSop_text) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] text: %s\n", client->num, (payload + (headerToPayload ? 14 : 0)));
|
||||
}
|
||||
|
||||
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
||||
|
||||
uint8_t headerSize;
|
||||
uint8_t * headerPtr;
|
||||
uint8_t * payloadPtr = payload;
|
||||
bool useInternBuffer = false;
|
||||
bool ret = true;
|
||||
|
||||
// calculate header Size
|
||||
if(length < 126) {
|
||||
headerSize = 2;
|
||||
} else if(length < 0xFFFF) {
|
||||
headerSize = 4;
|
||||
} else {
|
||||
headerSize = 10;
|
||||
}
|
||||
|
||||
if(client->cIsClient) {
|
||||
headerSize += 4;
|
||||
}
|
||||
|
||||
#ifdef WEBSOCKETS_USE_BIG_MEM
|
||||
// only for ESP since AVR has less HEAP
|
||||
// try to send data in one TCP package (only if some free Heap is there)
|
||||
if(!headerToPayload && ((length > 0) && (length < 1400)) && (GET_FREE_HEAP > 6000)) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num);
|
||||
uint8_t * dataPtr = (uint8_t *)malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
|
||||
if(dataPtr) {
|
||||
memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length);
|
||||
headerToPayload = true;
|
||||
useInternBuffer = true;
|
||||
payloadPtr = dataPtr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// set Header Pointer
|
||||
if(headerToPayload) {
|
||||
// calculate offset in payload
|
||||
headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize));
|
||||
} else {
|
||||
headerPtr = &buffer[0];
|
||||
}
|
||||
|
||||
if(client->cIsClient && useInternBuffer) {
|
||||
// if we use a Intern Buffer we can modify the data
|
||||
// by this fact its possible the do the masking
|
||||
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
||||
maskKey[x] = random(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin);
|
||||
|
||||
if(client->cIsClient && useInternBuffer) {
|
||||
uint8_t * dataMaskPtr;
|
||||
|
||||
if(headerToPayload) {
|
||||
dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE);
|
||||
} else {
|
||||
dataMaskPtr = payloadPtr;
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < length; x++) {
|
||||
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
unsigned long start = micros();
|
||||
#endif
|
||||
|
||||
if(headerToPayload) {
|
||||
// header has be added to payload
|
||||
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
|
||||
// offset in payload is calculatetd 14 - headerSize
|
||||
if(write(client, &payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) {
|
||||
ret = false;
|
||||
}
|
||||
} else {
|
||||
// send header
|
||||
if(write(client, &buffer[0], headerSize) != headerSize) {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if(payloadPtr && length > 0) {
|
||||
// send payload
|
||||
if(write(client, &payloadPtr[0], length) != length) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] sending Frame Done (%luus).\n", client->num, (micros() - start));
|
||||
|
||||
#ifdef WEBSOCKETS_USE_BIG_MEM
|
||||
if(useInternBuffer && payloadPtr) {
|
||||
free(payloadPtr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* callen when HTTP header is done
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSockets::headerDone(WSclient_t * client) {
|
||||
client->status = WSC_CONNECTED;
|
||||
client->cWsRXsize = 0;
|
||||
DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done.\n", client->num);
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->cHttpLine = "";
|
||||
handleWebsocket(client);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* handle the WebSocket stream
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSockets::handleWebsocket(WSclient_t * client) {
|
||||
if(client->cWsRXsize == 0) {
|
||||
handleWebsocketCb(client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wait for
|
||||
* @param client
|
||||
* @param size
|
||||
*/
|
||||
bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
|
||||
if(!client->tcp || !client->tcp->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(size > WEBSOCKETS_MAX_HEADER_SIZE) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client->cWsRXsize >= size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d cWsRXsize: %d\n", client->num, size, client->cWsRXsize);
|
||||
readCb(client, &client->cWsHeader[client->cWsRXsize], (size - client->cWsRXsize), std::bind([](WebSockets * server, size_t size, WSclient_t * client, bool ok) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor][readCb] size: %d ok: %d\n", client->num, size, ok);
|
||||
if(ok) {
|
||||
client->cWsRXsize = size;
|
||||
server->handleWebsocketCb(client);
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][readCb] failed.\n", client->num);
|
||||
client->cWsRXsize = 0;
|
||||
// timeout or error
|
||||
server->clientDisconnect(client, 1002);
|
||||
}
|
||||
},
|
||||
this, size, std::placeholders::_1, std::placeholders::_2));
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
||||
if(!client->tcp || !client->tcp->connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t * buffer = client->cWsHeader;
|
||||
|
||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
||||
uint8_t * payload = NULL;
|
||||
|
||||
uint8_t headerLen = 2;
|
||||
|
||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// split first 2 bytes in the data
|
||||
header->fin = ((*buffer >> 7) & 0x01);
|
||||
header->rsv1 = ((*buffer >> 6) & 0x01);
|
||||
header->rsv2 = ((*buffer >> 5) & 0x01);
|
||||
header->rsv3 = ((*buffer >> 4) & 0x01);
|
||||
header->opCode = (WSopcode_t)(*buffer & 0x0F);
|
||||
buffer++;
|
||||
|
||||
header->mask = ((*buffer >> 7) & 0x01);
|
||||
header->payloadLen = (WSopcode_t)(*buffer & 0x7F);
|
||||
buffer++;
|
||||
|
||||
if(header->payloadLen == 126) {
|
||||
headerLen += 2;
|
||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
||||
return;
|
||||
}
|
||||
header->payloadLen = buffer[0] << 8 | buffer[1];
|
||||
buffer += 2;
|
||||
} else if(header->payloadLen == 127) {
|
||||
headerLen += 8;
|
||||
// read 64bit integer as length
|
||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
|
||||
// really too big!
|
||||
header->payloadLen = 0xFFFFFFFF;
|
||||
} else {
|
||||
header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
||||
}
|
||||
buffer += 8;
|
||||
}
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ------- read massage frame -------\n", client->num);
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] fin: %u rsv1: %u rsv2: %u rsv3 %u opCode: %u\n", client->num, header->fin, header->rsv1, header->rsv2, header->rsv3, header->opCode);
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen);
|
||||
|
||||
if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen);
|
||||
clientDisconnect(client, 1009);
|
||||
return;
|
||||
}
|
||||
|
||||
if(header->mask) {
|
||||
headerLen += 4;
|
||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
||||
return;
|
||||
}
|
||||
header->maskKey = buffer;
|
||||
buffer += 4;
|
||||
}
|
||||
|
||||
if(header->payloadLen > 0) {
|
||||
// if text data we need one more
|
||||
payload = (uint8_t *)malloc(header->payloadLen + 1);
|
||||
|
||||
if(!payload) {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen);
|
||||
clientDisconnect(client, 1011);
|
||||
return;
|
||||
}
|
||||
readCb(client, payload, header->payloadLen, std::bind(&WebSockets::handleWebsocketPayloadCb, this, std::placeholders::_1, std::placeholders::_2, payload));
|
||||
} else {
|
||||
handleWebsocketPayloadCb(client, true, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) {
|
||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
||||
if(ok) {
|
||||
if(header->payloadLen > 0) {
|
||||
payload[header->payloadLen] = 0x00;
|
||||
|
||||
if(header->mask) {
|
||||
// decode XOR
|
||||
for(size_t i = 0; i < header->payloadLen; i++) {
|
||||
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(header->opCode) {
|
||||
case WSop_text:
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
||||
// no break here!
|
||||
case WSop_binary:
|
||||
case WSop_continuation:
|
||||
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||
break;
|
||||
case WSop_ping:
|
||||
// send pong back
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ping received (%s)\n", client->num, payload ? (const char *)payload : "");
|
||||
sendFrame(client, WSop_pong, payload, header->payloadLen);
|
||||
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||
break;
|
||||
case WSop_pong:
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload ? (const char *)payload : "");
|
||||
client->pongReceived = true;
|
||||
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||
break;
|
||||
case WSop_close: {
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
uint16_t reasonCode = 1000;
|
||||
if(header->payloadLen >= 2) {
|
||||
reasonCode = payload[0] << 8 | payload[1];
|
||||
}
|
||||
#endif
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode);
|
||||
if(header->payloadLen > 2) {
|
||||
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("\n");
|
||||
}
|
||||
clientDisconnect(client, 1000);
|
||||
} break;
|
||||
default:
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode);
|
||||
clientDisconnect(client, 1002);
|
||||
break;
|
||||
}
|
||||
|
||||
if(payload) {
|
||||
free(payload);
|
||||
}
|
||||
|
||||
// reset input
|
||||
client->cWsRXsize = 0;
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
// register callback for next message
|
||||
handleWebsocketWaitFor(client, 2);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] missing data!\n", client->num);
|
||||
free(payload);
|
||||
clientDisconnect(client, 1002);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate the key for Sec-WebSocket-Accept
|
||||
* @param clientKey String
|
||||
* @return String Accept Key
|
||||
*/
|
||||
String WebSockets::acceptKey(String & clientKey) {
|
||||
uint8_t sha1HashBin[20] = { 0 };
|
||||
#ifdef ESP8266
|
||||
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
|
||||
#elif defined(ESP32)
|
||||
String data = clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
esp_sha(SHA1, (unsigned char *)data.c_str(), data.length(), &sha1HashBin[0]);
|
||||
#else
|
||||
clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
SHA1_CTX ctx;
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, (const unsigned char *)clientKey.c_str(), clientKey.length());
|
||||
SHA1Final(&sha1HashBin[0], &ctx);
|
||||
#endif
|
||||
|
||||
String key = base64_encode(sha1HashBin, 20);
|
||||
key.trim();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* base64_encode
|
||||
* @param data uint8_t *
|
||||
* @param length size_t
|
||||
* @return base64 encoded String
|
||||
*/
|
||||
String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
||||
size_t size = ((length * 1.6f) + 1);
|
||||
char * buffer = (char *)malloc(size);
|
||||
if(buffer) {
|
||||
base64_encodestate _state;
|
||||
base64_init_encodestate(&_state);
|
||||
int len = base64_encode_block((const char *)&data[0], length, &buffer[0], &_state);
|
||||
len = base64_encode_blockend((buffer + len), &_state);
|
||||
|
||||
String base64 = String(buffer);
|
||||
free(buffer);
|
||||
return base64;
|
||||
}
|
||||
return String("-FAIL-");
|
||||
}
|
||||
|
||||
/**
|
||||
* read x byte from tcp or get timeout
|
||||
* @param client WSclient_t *
|
||||
* @param out uint8_t * data buffer
|
||||
* @param n size_t byte count
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) {
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
if(!client->tcp || !client->tcp->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client->tcp->readBytes(out, n, std::bind([](WSclient_t * client, bool ok, WSreadWaitCb cb) {
|
||||
if(cb) {
|
||||
cb(client, ok);
|
||||
}
|
||||
},
|
||||
client, std::placeholders::_1, cb));
|
||||
|
||||
#else
|
||||
unsigned long t = millis();
|
||||
ssize_t len;
|
||||
DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t);
|
||||
while(n > 0) {
|
||||
if(client->tcp == NULL) {
|
||||
DEBUG_WEBSOCKETS("[readCb] tcp is null!\n");
|
||||
if(cb) {
|
||||
cb(client, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!client->tcp->connected()) {
|
||||
DEBUG_WEBSOCKETS("[readCb] not connected!\n");
|
||||
if(cb) {
|
||||
cb(client, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
||||
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %lu\n", (millis() - t));
|
||||
if(cb) {
|
||||
cb(client, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!client->tcp->available()) {
|
||||
WEBSOCKETS_YIELD_MORE();
|
||||
continue;
|
||||
}
|
||||
|
||||
len = client->tcp->read((uint8_t *)out, n);
|
||||
if(len > 0) {
|
||||
t = millis();
|
||||
out += len;
|
||||
n -= len;
|
||||
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||
} else {
|
||||
// DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||
}
|
||||
if(n > 0) {
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
}
|
||||
if(cb) {
|
||||
cb(client, true);
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* write x byte to tcp or get timeout
|
||||
* @param client WSclient_t *
|
||||
* @param out uint8_t * data buffer
|
||||
* @param n size_t byte count
|
||||
* @return bytes send
|
||||
*/
|
||||
size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
|
||||
if(out == NULL)
|
||||
return 0;
|
||||
if(client == NULL)
|
||||
return 0;
|
||||
unsigned long t = millis();
|
||||
size_t len = 0;
|
||||
size_t total = 0;
|
||||
DEBUG_WEBSOCKETS("[write] n: %zu t: %lu\n", n, t);
|
||||
while(n > 0) {
|
||||
if(client->tcp == NULL) {
|
||||
DEBUG_WEBSOCKETS("[write] tcp is null!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!client->tcp->connected()) {
|
||||
DEBUG_WEBSOCKETS("[write] not connected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
||||
DEBUG_WEBSOCKETS("[write] write TIMEOUT! %lu\n", (millis() - t));
|
||||
break;
|
||||
}
|
||||
|
||||
len = client->tcp->write((const uint8_t *)out, n);
|
||||
if(len) {
|
||||
t = millis();
|
||||
out += len;
|
||||
n -= len;
|
||||
total += len;
|
||||
// DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n);
|
||||
}
|
||||
if(n > 0) {
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t WebSockets::write(WSclient_t * client, const char * out) {
|
||||
if(client == NULL)
|
||||
return 0;
|
||||
if(out == NULL)
|
||||
return 0;
|
||||
return write(client, (uint8_t *)out, strlen(out));
|
||||
}
|
||||
|
||||
/**
|
||||
* enable ping/pong heartbeat process
|
||||
* @param client WSclient_t *
|
||||
* @param pingInterval uint32_t how often ping will be sent
|
||||
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||
*/
|
||||
void WebSockets::enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||
if(client == NULL)
|
||||
return;
|
||||
client->pingInterval = pingInterval;
|
||||
client->pongTimeout = pongTimeout;
|
||||
client->disconnectTimeoutCount = disconnectTimeoutCount;
|
||||
client->pongReceived = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle ping/pong heartbeat timeout process
|
||||
* @param client WSclient_t *
|
||||
*/
|
||||
void WebSockets::handleHBTimeout(WSclient_t * client) {
|
||||
if(client->pingInterval) { // if heartbeat is enabled
|
||||
uint32_t pi = millis() - client->lastPing;
|
||||
|
||||
if(client->pongReceived) {
|
||||
client->pongTimeoutCount = 0;
|
||||
} else {
|
||||
if(pi > client->pongTimeout) { // pong not received in time
|
||||
client->pongTimeoutCount++;
|
||||
client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run
|
||||
|
||||
DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%d pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount);
|
||||
|
||||
if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) {
|
||||
DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount);
|
||||
clientDisconnect(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBRETINY
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
if (seed != 0) {
|
||||
srand(seed);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
379
lib/LT_WebSockets/src/WebSockets.h
Normal file
379
lib/LT_WebSockets/src/WebSockets.h
Normal file
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* @file WebSockets.h
|
||||
* @date 20.05.2015
|
||||
* @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 WEBSOCKETS_H_
|
||||
#define WEBSOCKETS_H_
|
||||
|
||||
#ifdef STM32_DEVICE
|
||||
#include <application.h>
|
||||
#define bit(b) (1UL << (b)) // Taken directly from Arduino.h
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
#error Version 2.x.x currently does not support Arduino with AVR since there is no support for std namespace of c++.
|
||||
#error Use Version 1.x.x. (ATmega branch)
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#include "WebSocketsVersion.h"
|
||||
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_WEBSOCKETS(...) \
|
||||
{ \
|
||||
DEBUG_ESP_PORT.printf(__VA_ARGS__); \
|
||||
DEBUG_ESP_PORT.flush(); \
|
||||
}
|
||||
#else
|
||||
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_WEBSOCKETS
|
||||
#define DEBUG_WEBSOCKETS(...)
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
#define NODEBUG_WEBSOCKETS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
|
||||
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||
#define WEBSOCKETS_USE_BIG_MEM
|
||||
#define GET_FREE_HEAP ESP.getFreeHeap()
|
||||
// moves all Header strings to Flash (~300 Byte)
|
||||
//#define WEBSOCKETS_SAVE_RAM
|
||||
|
||||
#if defined(ESP8266)
|
||||
#define WEBSOCKETS_YIELD() delay(0)
|
||||
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||
#elif defined(ESP32)
|
||||
#define WEBSOCKETS_YIELD() yield()
|
||||
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||
#endif
|
||||
|
||||
#elif defined(STM32_DEVICE)
|
||||
|
||||
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||
#define WEBSOCKETS_USE_BIG_MEM
|
||||
#define GET_FREE_HEAP System.freeMemory()
|
||||
#define WEBSOCKETS_YIELD()
|
||||
#define WEBSOCKETS_YIELD_MORE()
|
||||
#else
|
||||
|
||||
// atmega328p has only 2KB ram!
|
||||
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
||||
// moves all Header strings to Flash
|
||||
#define WEBSOCKETS_SAVE_RAM
|
||||
#define WEBSOCKETS_YIELD()
|
||||
#define WEBSOCKETS_YIELD_MORE()
|
||||
#endif
|
||||
|
||||
#define WEBSOCKETS_TCP_TIMEOUT (5000)
|
||||
|
||||
#define NETWORK_ESP8266_ASYNC (0)
|
||||
#define NETWORK_ESP8266 (1)
|
||||
#define NETWORK_W5100 (2)
|
||||
#define NETWORK_ENC28J60 (3)
|
||||
#define NETWORK_ESP32 (4)
|
||||
#define NETWORK_ESP32_ETH (5)
|
||||
|
||||
// max size of the WS Message Header
|
||||
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
||||
|
||||
#if !defined(WEBSOCKETS_NETWORK_TYPE)
|
||||
// select Network type based
|
||||
#if defined(ESP8266) || defined(ESP31B)
|
||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||
|
||||
#elif defined(ESP32)
|
||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
|
||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
|
||||
#elif defined(LIBRETINY)
|
||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||
#else
|
||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Includes and defined based on Network Type
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
|
||||
// Note:
|
||||
// No SSL/WSS support for client in Async mode
|
||||
// TLS lib need a sync interface!
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#define SSL_AXTLS
|
||||
#elif defined(ESP31B)
|
||||
#include <ESP31BWiFi.h>
|
||||
#else
|
||||
#error "network type ESP8266 ASYNC only possible on the ESP mcu!"
|
||||
#endif
|
||||
|
||||
#include <ESPAsyncTCP.h>
|
||||
#include <ESPAsyncTCPbuffer.h>
|
||||
#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer
|
||||
|
||||
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) && !defined(LIBRETINY)
|
||||
#if !defined(ESP8266) && !defined(ESP31B)
|
||||
#error "network type ESP8266 only possible on the ESP mcu!"
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
|
||||
#define SSL_BARESSL
|
||||
#else
|
||||
#define SSL_AXTLS
|
||||
#endif
|
||||
#else
|
||||
#include <ESP31BWiFi.h>
|
||||
#endif
|
||||
|
||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
||||
|
||||
#ifdef STM32_DEVICE
|
||||
#define WEBSOCKETS_NETWORK_CLASS TCPClient
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS TCPServer
|
||||
#endif
|
||||
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
|
||||
|
||||
#include <UIPEthernet.h>
|
||||
#define WEBSOCKETS_NETWORK_CLASS UIPClient
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer
|
||||
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#define SSL_AXTLS
|
||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32_ETH)
|
||||
|
||||
#include <ETH.h>
|
||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||
|
||||
#elif defined(LIBRETINY)
|
||||
//#include <Ethernet.h>
|
||||
//#include <SPI.h>
|
||||
//#define WEBSOCKETS_NETWORK_CLASS EthernetClient
|
||||
//#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
|
||||
//#if defined(LIBRETINY)
|
||||
typedef struct SHA1Context SHA1_CTX;
|
||||
#include <WiFi.h>
|
||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||
//#include <WiFiClientSecure.h>
|
||||
//#define SSL_AXTLS
|
||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||
//#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||
//#endif
|
||||
#else
|
||||
#error "no network type selected!"
|
||||
#endif
|
||||
|
||||
#ifdef WEBSOCKETS_NETWORK_SSL_CLASS
|
||||
#define HAS_SSL
|
||||
#endif
|
||||
|
||||
// moves all Header strings to Flash (~300 Byte)
|
||||
#ifdef WEBSOCKETS_SAVE_RAM
|
||||
#define WEBSOCKETS_STRING(var) F(var)
|
||||
#else
|
||||
#define WEBSOCKETS_STRING(var) var
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
WSC_NOT_CONNECTED,
|
||||
WSC_HEADER,
|
||||
WSC_BODY,
|
||||
WSC_CONNECTED
|
||||
} WSclientsStatus_t;
|
||||
|
||||
typedef enum {
|
||||
WStype_ERROR,
|
||||
WStype_DISCONNECTED,
|
||||
WStype_CONNECTED,
|
||||
WStype_TEXT,
|
||||
WStype_BIN,
|
||||
WStype_FRAGMENT_TEXT_START,
|
||||
WStype_FRAGMENT_BIN_START,
|
||||
WStype_FRAGMENT,
|
||||
WStype_FRAGMENT_FIN,
|
||||
WStype_PING,
|
||||
WStype_PONG,
|
||||
} WStype_t;
|
||||
|
||||
typedef enum {
|
||||
WSop_continuation = 0x00, ///< %x0 denotes a continuation frame
|
||||
WSop_text = 0x01, ///< %x1 denotes a text frame
|
||||
WSop_binary = 0x02, ///< %x2 denotes a binary frame
|
||||
///< %x3-7 are reserved for further non-control frames
|
||||
WSop_close = 0x08, ///< %x8 denotes a connection close
|
||||
WSop_ping = 0x09, ///< %x9 denotes a ping
|
||||
WSop_pong = 0x0A ///< %xA denotes a pong
|
||||
///< %xB-F are reserved for further control frames
|
||||
} WSopcode_t;
|
||||
|
||||
typedef struct {
|
||||
bool fin;
|
||||
bool rsv1;
|
||||
bool rsv2;
|
||||
bool rsv3;
|
||||
|
||||
WSopcode_t opCode;
|
||||
bool mask;
|
||||
|
||||
size_t payloadLen;
|
||||
|
||||
uint8_t * maskKey;
|
||||
} WSMessageHeader_t;
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
}
|
||||
|
||||
uint8_t num = 0; ///< connection number
|
||||
|
||||
WSclientsStatus_t status = WSC_NOT_CONNECTED;
|
||||
|
||||
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr;
|
||||
|
||||
bool isSocketIO = false; ///< client for socket.io server
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
bool isSSL = false; ///< run in ssl mode
|
||||
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
||||
#endif
|
||||
|
||||
String cUrl; ///< http url
|
||||
uint16_t cCode = 0; ///< http code
|
||||
|
||||
bool cIsClient = false; ///< will be used for masking
|
||||
bool cIsUpgrade = false; ///< Connection == Upgrade
|
||||
bool cIsWebsocket = false; ///< Upgrade == websocket
|
||||
|
||||
String cSessionId; ///< client Set-Cookie (session id)
|
||||
String cKey; ///< client Sec-WebSocket-Key
|
||||
String cAccept; ///< client Sec-WebSocket-Accept
|
||||
String cProtocol; ///< client Sec-WebSocket-Protocol
|
||||
String cExtensions; ///< client Sec-WebSocket-Extensions
|
||||
uint16_t cVersion = 0; ///< client Sec-WebSocket-Version
|
||||
|
||||
uint8_t cWsRXsize = 0; ///< State of the RX
|
||||
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
||||
WSMessageHeader_t cWsHeaderDecode;
|
||||
|
||||
String base64Authorization; ///< Base64 encoded Auth request
|
||||
String plainAuthorization; ///< Base64 encoded Auth request
|
||||
|
||||
String extraHeaders;
|
||||
|
||||
bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator
|
||||
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
||||
|
||||
bool pongReceived = false;
|
||||
uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active"
|
||||
uint32_t lastPing = 0; // millis when last pong has been received
|
||||
uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout
|
||||
uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
||||
uint8_t pongTimeoutCount = 0; // current pong timeout count
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
String cHttpLine; ///< HTTP header lines
|
||||
#endif
|
||||
|
||||
} WSclient_t;
|
||||
|
||||
class WebSockets {
|
||||
protected:
|
||||
#ifdef __AVR__
|
||||
typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok);
|
||||
#else
|
||||
typedef std::function<void(WSclient_t * client, bool ok)> WSreadWaitCb;
|
||||
#endif
|
||||
|
||||
virtual void clientDisconnect(WSclient_t * client) = 0;
|
||||
virtual bool clientIsConnected(WSclient_t * client) = 0;
|
||||
|
||||
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
||||
|
||||
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0;
|
||||
|
||||
uint8_t createHeader(uint8_t * buf, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin);
|
||||
bool sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length = 0, bool fin = true);
|
||||
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false);
|
||||
|
||||
void headerDone(WSclient_t * client);
|
||||
|
||||
void handleWebsocket(WSclient_t * client);
|
||||
|
||||
bool handleWebsocketWaitFor(WSclient_t * client, size_t size);
|
||||
void handleWebsocketCb(WSclient_t * client);
|
||||
void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload);
|
||||
|
||||
String acceptKey(String & clientKey);
|
||||
String base64_encode(uint8_t * data, size_t length);
|
||||
|
||||
bool readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb);
|
||||
virtual size_t write(WSclient_t * client, uint8_t * out, size_t n);
|
||||
size_t write(WSclient_t * client, const char * out);
|
||||
|
||||
void enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||
void handleHBTimeout(WSclient_t * client);
|
||||
};
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(var) (void)(var)
|
||||
#endif
|
||||
#endif /* WEBSOCKETS_H_ */
|
||||
80
lib/LT_WebSockets/src/WebSockets4WebServer.h
Normal file
80
lib/LT_WebSockets/src/WebSockets4WebServer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file WebSocketsServer.cpp
|
||||
* @date 28.10.2020
|
||||
* @author Markus Sattler & esp8266/arduino community
|
||||
*
|
||||
* Copyright (c) 2020 Markus Sattler. All rights reserved.
|
||||
* This file is part of the WebSockets for Arduino.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WEBSOCKETS4WEBSERVER_H
|
||||
#define __WEBSOCKETS4WEBSERVER_H
|
||||
|
||||
#include <WebSocketsServer.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||
|
||||
class WebSockets4WebServer : public WebSocketsServerCore {
|
||||
public:
|
||||
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
|
||||
: WebSocketsServerCore(origin, protocol) {
|
||||
begin();
|
||||
}
|
||||
|
||||
ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
|
||||
onEvent(event);
|
||||
|
||||
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
|
||||
(void)contentType;
|
||||
|
||||
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
|
||||
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
|
||||
}
|
||||
|
||||
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
|
||||
WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
|
||||
|
||||
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
|
||||
WSclient_t * client = handleNewClient(newTcpClient);
|
||||
|
||||
if(client) {
|
||||
// give "GET <url>"
|
||||
String headerLine;
|
||||
headerLine.reserve(url.length() + 5);
|
||||
headerLine = "GET ";
|
||||
headerLine += url;
|
||||
handleHeader(client, &headerLine);
|
||||
}
|
||||
|
||||
// tell webserver to not close but forget about this client
|
||||
return ESP8266WebServer::CLIENT_IS_GIVEN;
|
||||
};
|
||||
}
|
||||
};
|
||||
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||
|
||||
#ifndef WEBSERVER_HAS_HOOK
|
||||
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
|
||||
#else
|
||||
#error Your Hardware Platform does not support Webserver Hook Functions
|
||||
#endif
|
||||
|
||||
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||
|
||||
#endif // __WEBSOCKETS4WEBSERVER_H
|
||||
980
lib/LT_WebSockets/src/WebSocketsClient.cpp
Normal file
980
lib/LT_WebSockets/src/WebSocketsClient.cpp
Normal file
@@ -0,0 +1,980 @@
|
||||
/**
|
||||
* @file WebSocketsClient.cpp
|
||||
* @date 20.05.2015
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "WebSockets.h"
|
||||
#include "WebSocketsClient.h"
|
||||
|
||||
WebSocketsClient::WebSocketsClient() {
|
||||
_cbEvent = NULL;
|
||||
_client.num = 0;
|
||||
_client.cIsClient = true;
|
||||
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
|
||||
_reconnectInterval = 500;
|
||||
_port = 0;
|
||||
_host = "";
|
||||
}
|
||||
|
||||
WebSocketsClient::~WebSocketsClient() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* calles to init the Websockets server
|
||||
*/
|
||||
void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||
_host = host;
|
||||
_port = port;
|
||||
#if defined(HAS_SSL)
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
_CA_cert = NULL;
|
||||
#endif
|
||||
|
||||
_client.num = 0;
|
||||
_client.status = WSC_NOT_CONNECTED;
|
||||
_client.tcp = NULL;
|
||||
#if defined(HAS_SSL)
|
||||
_client.isSSL = false;
|
||||
_client.ssl = NULL;
|
||||
#endif
|
||||
_client.cUrl = url;
|
||||
_client.cCode = 0;
|
||||
_client.cIsUpgrade = false;
|
||||
_client.cIsWebsocket = true;
|
||||
_client.cKey = "";
|
||||
_client.cAccept = "";
|
||||
_client.cProtocol = protocol;
|
||||
_client.cExtensions = "";
|
||||
_client.cVersion = 0;
|
||||
_client.base64Authorization = "";
|
||||
_client.plainAuthorization = "";
|
||||
_client.isSocketIO = false;
|
||||
|
||||
_client.lastPing = 0;
|
||||
_client.pongReceived = false;
|
||||
_client.pongTimeoutCount = 0;
|
||||
|
||||
#ifdef ESP8266
|
||||
randomSeed(RANDOM_REG32);
|
||||
#else
|
||||
// todo find better seed
|
||||
randomSeed(millis());
|
||||
#endif
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
asyncConnect();
|
||||
#endif
|
||||
|
||||
_lastConnectionFail = 0;
|
||||
_lastHeaderSent = 0;
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||
}
|
||||
|
||||
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
||||
begin(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||
}
|
||||
|
||||
#ifndef LIBRETINY
|
||||
void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, const char * protocol) {
|
||||
return begin(host.toString().c_str(), port, url, protocol);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
#if defined(SSL_AXTLS)
|
||||
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSSL = true;
|
||||
_fingerprint = fingerprint;
|
||||
_CA_cert = NULL;
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
||||
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSSL = true;
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
_CA_cert = CA_cert;
|
||||
}
|
||||
#else
|
||||
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSSL = true;
|
||||
_fingerprint = fingerprint;
|
||||
_CA_cert = NULL;
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSSL = true;
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
_CA_cert = CA_cert;
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||
beginSslWithCA(host, port, url, new BearSSL::X509List(CA_cert), protocol);
|
||||
}
|
||||
|
||||
void WebSocketsClient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||
_client_cert = clientCert;
|
||||
_client_key = clientPrivateKey;
|
||||
}
|
||||
|
||||
void WebSocketsClient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||
setSSLClientCertKey(new BearSSL::X509List(clientCert), new BearSSL::PrivateKey(clientPrivateKey));
|
||||
}
|
||||
|
||||
#endif // SSL_AXTLS
|
||||
#endif // HAS_SSL
|
||||
|
||||
void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSocketIO = true;
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) {
|
||||
beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||
}
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSocketIO = true;
|
||||
_client.isSSL = true;
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
}
|
||||
|
||||
void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
|
||||
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||
}
|
||||
|
||||
#if defined(SSL_BARESSL)
|
||||
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSocketIO = true;
|
||||
_client.isSSL = true;
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
_CA_cert = CA_cert;
|
||||
}
|
||||
#endif
|
||||
|
||||
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||
begin(host, port, url, protocol);
|
||||
_client.isSocketIO = true;
|
||||
_client.isSSL = true;
|
||||
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||
#if defined(SSL_BARESSL)
|
||||
_CA_cert = new BearSSL::X509List(CA_cert);
|
||||
#else
|
||||
_CA_cert = CA_cert;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
/**
|
||||
* called in arduino loop
|
||||
*/
|
||||
void WebSocketsClient::loop(void) {
|
||||
if(_port == 0) {
|
||||
return;
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
if(!clientIsConnected(&_client)) {
|
||||
// do not flood the server
|
||||
if((millis() - _lastConnectionFail) < _reconnectInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
if(_client.isSSL) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
|
||||
if(_client.ssl) {
|
||||
delete _client.ssl;
|
||||
_client.ssl = NULL;
|
||||
_client.tcp = NULL;
|
||||
}
|
||||
_client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS();
|
||||
_client.tcp = _client.ssl;
|
||||
if(_CA_cert) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
|
||||
#if defined(ESP32)
|
||||
_client.ssl->setCACert(_CA_cert);
|
||||
#elif defined(ESP8266) && defined(SSL_AXTLS)
|
||||
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
|
||||
#elif defined(ESP8266) && defined(SSL_BARESSL)
|
||||
_client.ssl->setTrustAnchors(_CA_cert);
|
||||
#else
|
||||
#error setCACert not implemented
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
} else if(!SSL_FINGERPRINT_IS_SET) {
|
||||
_client.ssl->setInsecure();
|
||||
#elif defined(SSL_BARESSL)
|
||||
} else if(SSL_FINGERPRINT_IS_SET) {
|
||||
_client.ssl->setFingerprint(_fingerprint);
|
||||
} else {
|
||||
_client.ssl->setInsecure();
|
||||
}
|
||||
if(_client_cert && _client_key) {
|
||||
_client.ssl->setClientRSACert(_client_cert, _client_key);
|
||||
DEBUG_WEBSOCKETS("[WS-Client] setting client certificate and key");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
|
||||
if(_client.tcp) {
|
||||
delete _client.tcp;
|
||||
_client.tcp = NULL;
|
||||
}
|
||||
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
||||
}
|
||||
#else
|
||||
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
||||
#endif
|
||||
|
||||
if(!_client.tcp) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
||||
return;
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
#if defined(ESP32)
|
||||
if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
|
||||
#else
|
||||
if(_client.tcp->connect(_host.c_str(), _port)) {
|
||||
#endif
|
||||
connectedCb();
|
||||
_lastConnectionFail = 0;
|
||||
} else {
|
||||
connectFailedCb();
|
||||
_lastConnectionFail = millis();
|
||||
}
|
||||
} else {
|
||||
handleClientData();
|
||||
WEBSOCKETS_YIELD();
|
||||
if(_client.status == WSC_CONNECTED) {
|
||||
handleHBPing();
|
||||
handleHBTimeout(&_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* set callback function
|
||||
* @param cbEvent WebSocketServerEvent
|
||||
*/
|
||||
void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
|
||||
_cbEvent = cbEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* send text data to client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
if(length == 0) {
|
||||
length = strlen((const char *)payload);
|
||||
}
|
||||
if(clientIsConnected(&_client)) {
|
||||
return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
|
||||
return sendTXT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
|
||||
return sendTXT((uint8_t *)payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
|
||||
return sendTXT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendTXT(String & payload) {
|
||||
return sendTXT((uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendTXT(char payload) {
|
||||
uint8_t buf[WEBSOCKETS_MAX_HEADER_SIZE + 2] = { 0x00 };
|
||||
buf[WEBSOCKETS_MAX_HEADER_SIZE] = payload;
|
||||
return sendTXT(buf, 1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* send binary data to client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
if(clientIsConnected(&_client)) {
|
||||
return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
|
||||
return sendBIN((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a WS ping to Server
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @return true if ping is send out
|
||||
*/
|
||||
bool WebSocketsClient::sendPing(uint8_t * payload, size_t length) {
|
||||
if(clientIsConnected(&_client)) {
|
||||
bool sent = sendFrame(&_client, WSop_ping, payload, length);
|
||||
if(sent)
|
||||
_client.lastPing = millis();
|
||||
return sent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsClient::sendPing(String & payload) {
|
||||
return sendPing((uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect one client
|
||||
* @param num uint8_t client id
|
||||
*/
|
||||
void WebSocketsClient::disconnect(void) {
|
||||
if(clientIsConnected(&_client)) {
|
||||
WebSockets::clientDisconnect(&_client, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the Authorizatio for the http request
|
||||
* @param user const char *
|
||||
* @param password const char *
|
||||
*/
|
||||
void WebSocketsClient::setAuthorization(const char * user, const char * password) {
|
||||
if(user && password) {
|
||||
String auth = user;
|
||||
auth += ":";
|
||||
auth += password;
|
||||
_client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the Authorizatio for the http request
|
||||
* @param auth const char * base64
|
||||
*/
|
||||
void WebSocketsClient::setAuthorization(const char * auth) {
|
||||
if(auth) {
|
||||
//_client.base64Authorization = auth;
|
||||
_client.plainAuthorization = auth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set extra headers for the http request;
|
||||
* separate headers by "\r\n"
|
||||
* @param extraHeaders const char * extraHeaders
|
||||
*/
|
||||
void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
|
||||
_client.extraHeaders = extraHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the reconnect Interval
|
||||
* how long to wait after a connection initiate failed
|
||||
* @param time in ms
|
||||
*/
|
||||
void WebSocketsClient::setReconnectInterval(unsigned long time) {
|
||||
_reconnectInterval = time;
|
||||
}
|
||||
|
||||
bool WebSocketsClient::isConnected(void) {
|
||||
return (_client.status == WSC_CONNECTED);
|
||||
}
|
||||
|
||||
//#################################################################################
|
||||
//#################################################################################
|
||||
//#################################################################################
|
||||
|
||||
/**
|
||||
*
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @param opcode WSopcode_t
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
*/
|
||||
void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
||||
WStype_t type = WStype_ERROR;
|
||||
|
||||
UNUSED(client);
|
||||
|
||||
switch(opcode) {
|
||||
case WSop_text:
|
||||
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
|
||||
break;
|
||||
case WSop_binary:
|
||||
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
|
||||
break;
|
||||
case WSop_continuation:
|
||||
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
|
||||
break;
|
||||
case WSop_ping:
|
||||
type = WStype_PING;
|
||||
break;
|
||||
case WSop_pong:
|
||||
type = WStype_PONG;
|
||||
break;
|
||||
case WSop_close:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
runCbEvent(type, payload, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect an client
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
||||
bool event = false;
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
if(client->isSSL && client->ssl) {
|
||||
if(client->ssl->connected()) {
|
||||
client->ssl->flush();
|
||||
client->ssl->stop();
|
||||
}
|
||||
event = true;
|
||||
delete client->ssl;
|
||||
client->ssl = NULL;
|
||||
client->tcp = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif //ssl
|
||||
if(client->tcp) {
|
||||
if(client->tcp->connected()) {
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
client->tcp->flush();
|
||||
#endif
|
||||
client->tcp->stop();
|
||||
}
|
||||
event = true;
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
#else
|
||||
delete client->tcp;
|
||||
#endif
|
||||
client->tcp = NULL;
|
||||
}
|
||||
|
||||
client->cCode = 0;
|
||||
client->cKey = "";
|
||||
client->cAccept = "";
|
||||
client->cVersion = 0;
|
||||
client->cIsUpgrade = false;
|
||||
client->cIsWebsocket = false;
|
||||
client->cSessionId = "";
|
||||
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
_lastConnectionFail = millis();
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
||||
if(event) {
|
||||
runCbEvent(WStype_DISCONNECTED, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get client state
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @return true = conneted
|
||||
*/
|
||||
bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
||||
if(!client->tcp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client->tcp->connected()) {
|
||||
if(client->status != WSC_NOT_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// client lost
|
||||
if(client->status != WSC_NOT_CONNECTED) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] connection lost.\n");
|
||||
// do cleanup
|
||||
clientDisconnect(client);
|
||||
}
|
||||
}
|
||||
|
||||
if(client->tcp) {
|
||||
// do cleanup
|
||||
clientDisconnect(client);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
/**
|
||||
* Handel incomming data from Client
|
||||
*/
|
||||
void WebSocketsClient::handleClientData(void) {
|
||||
if((_client.status == WSC_HEADER || _client.status == WSC_BODY) && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
|
||||
clientDisconnect(&_client);
|
||||
WEBSOCKETS_YIELD();
|
||||
return;
|
||||
}
|
||||
|
||||
int len = _client.tcp->available();
|
||||
if(len > 0) {
|
||||
switch(_client.status) {
|
||||
case WSC_HEADER: {
|
||||
String headerLine = _client.tcp->readStringUntil('\n');
|
||||
handleHeader(&_client, &headerLine);
|
||||
} break;
|
||||
case WSC_BODY: {
|
||||
char buf[256] = { 0 };
|
||||
_client.tcp->readBytes(&buf[0], std::min((size_t)len, sizeof(buf)));
|
||||
String bodyLine = buf;
|
||||
handleHeader(&_client, &bodyLine);
|
||||
} break;
|
||||
case WSC_CONNECTED:
|
||||
WebSockets::handleWebsocket(&_client);
|
||||
break;
|
||||
default:
|
||||
WebSockets::clientDisconnect(&_client, 1002);
|
||||
break;
|
||||
}
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* send the WebSocket header to Server
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSocketsClient::sendHeader(WSclient_t * client) {
|
||||
static const char * NEW_LINE = "\r\n";
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
|
||||
|
||||
uint8_t randomKey[16] = { 0 };
|
||||
|
||||
for(uint8_t i = 0; i < sizeof(randomKey); i++) {
|
||||
randomKey[i] = random(0xFF);
|
||||
}
|
||||
|
||||
client->cKey = base64_encode(&randomKey[0], 16);
|
||||
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
unsigned long start = micros();
|
||||
#endif
|
||||
|
||||
String handshake;
|
||||
bool ws_header = true;
|
||||
String url = client->cUrl;
|
||||
|
||||
if(client->isSocketIO) {
|
||||
if(client->cSessionId.length() == 0) {
|
||||
url += WEBSOCKETS_STRING("&transport=polling");
|
||||
ws_header = false;
|
||||
} else {
|
||||
url += WEBSOCKETS_STRING("&transport=websocket&sid=");
|
||||
url += client->cSessionId;
|
||||
}
|
||||
}
|
||||
|
||||
handshake = WEBSOCKETS_STRING("GET ");
|
||||
handshake += url + WEBSOCKETS_STRING(
|
||||
" HTTP/1.1\r\n"
|
||||
"Host: ");
|
||||
handshake += _host + ":" + _port + NEW_LINE;
|
||||
|
||||
if(ws_header) {
|
||||
handshake += WEBSOCKETS_STRING(
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"Sec-WebSocket-Key: ");
|
||||
handshake += client->cKey + NEW_LINE;
|
||||
|
||||
if(client->cProtocol.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
|
||||
handshake += client->cProtocol + NEW_LINE;
|
||||
}
|
||||
|
||||
if(client->cExtensions.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: ");
|
||||
handshake += client->cExtensions + NEW_LINE;
|
||||
}
|
||||
} else {
|
||||
handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n");
|
||||
}
|
||||
|
||||
// add extra headers; by default this includes "Origin: file://"
|
||||
if(client->extraHeaders.length() > 0) {
|
||||
handshake += client->extraHeaders + NEW_LINE;
|
||||
}
|
||||
|
||||
handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n");
|
||||
|
||||
if(client->base64Authorization.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Authorization: Basic ");
|
||||
handshake += client->base64Authorization + NEW_LINE;
|
||||
}
|
||||
|
||||
if(client->plainAuthorization.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Authorization: ");
|
||||
handshake += client->plainAuthorization + NEW_LINE;
|
||||
}
|
||||
|
||||
handshake += NEW_LINE;
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str());
|
||||
write(client, (uint8_t *)handshake.c_str(), handshake.length());
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
||||
#endif
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
|
||||
_lastHeaderSent = millis();
|
||||
}
|
||||
|
||||
/**
|
||||
* handle the WebSocket header reading
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
||||
headerLine->trim(); // remove \r
|
||||
|
||||
// this code handels the http body for Socket.IO V3 requests
|
||||
if(headerLine->length() > 0 && client->isSocketIO && client->status == WSC_BODY && client->cSessionId.length() == 0) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] socket.io json: %s\n", headerLine->c_str());
|
||||
String sid_begin = WEBSOCKETS_STRING("\"sid\":\"");
|
||||
if(headerLine->indexOf(sid_begin) > -1) {
|
||||
int start = headerLine->indexOf(sid_begin) + sid_begin.length();
|
||||
int end = headerLine->indexOf('"', start);
|
||||
client->cSessionId = headerLine->substring(start, end);
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||
|
||||
// Trigger websocket connection code path
|
||||
*headerLine = "";
|
||||
}
|
||||
}
|
||||
|
||||
// headle HTTP header
|
||||
if(headerLine->length() > 0) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
||||
|
||||
if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) {
|
||||
// "HTTP/1.1 101 Switching Protocols"
|
||||
client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
|
||||
} else if(headerLine->indexOf(':') >= 0) {
|
||||
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
||||
String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
|
||||
|
||||
// remove space in the beginning (RFC2616)
|
||||
if(headerValue[0] == ' ') {
|
||||
headerValue.remove(0, 1);
|
||||
}
|
||||
|
||||
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
|
||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
|
||||
client->cIsUpgrade = true;
|
||||
}
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
|
||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
|
||||
client->cIsWebsocket = true;
|
||||
}
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
|
||||
client->cAccept = headerValue;
|
||||
client->cAccept.trim(); // see rfc6455
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
|
||||
client->cProtocol = headerValue;
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
|
||||
client->cExtensions = headerValue;
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
||||
client->cVersion = headerValue.toInt();
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
|
||||
if(headerValue.indexOf(';') > -1) {
|
||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
|
||||
} else {
|
||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
||||
}
|
||||
|
||||
(*headerLine) = "";
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cURL: %s\n", client->cUrl.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cKey: %s\n", client->cKey.c_str());
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n");
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cCode: %d\n", client->cCode);
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsUpgrade: %d\n", client->cIsUpgrade);
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsWebsocket: %d\n", client->cIsWebsocket);
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cAccept: %s\n", client->cAccept.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||
|
||||
if(client->isSocketIO && client->cSessionId.length() == 0 && clientIsConnected(client)) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still missing cSessionId try socket.io V3\n");
|
||||
client->status = WSC_BODY;
|
||||
return;
|
||||
} else {
|
||||
client->status = WSC_HEADER;
|
||||
}
|
||||
|
||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||
|
||||
if(ok) {
|
||||
switch(client->cCode) {
|
||||
case 101: ///< Switching Protocols
|
||||
|
||||
break;
|
||||
case 200:
|
||||
if(client->isSocketIO) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case 403: ///< Forbidden
|
||||
// todo handle login
|
||||
// falls through
|
||||
default: ///< Server dont unterstand requrst
|
||||
ok = false;
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
||||
clientDisconnect(client);
|
||||
_lastConnectionFail = millis();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ok) {
|
||||
if(client->cAccept.length() == 0) {
|
||||
ok = false;
|
||||
} else {
|
||||
// generate Sec-WebSocket-Accept key for check
|
||||
String sKey = acceptKey(client->cKey);
|
||||
if(sKey != client->cAccept) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Sec-WebSocket-Accept is wrong\n");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ok) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
|
||||
headerDone(client);
|
||||
|
||||
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
} else if(client->isSocketIO) {
|
||||
if(client->cSessionId.length() > 0) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] found cSessionId\n");
|
||||
if(clientIsConnected(client) && _client.tcp->available()) {
|
||||
// read not needed data
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
|
||||
while(_client.tcp->available() > 0) {
|
||||
_client.tcp->read();
|
||||
}
|
||||
}
|
||||
sendHeader(client);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
||||
_lastConnectionFail = millis();
|
||||
if(clientIsConnected(client)) {
|
||||
write(client, "This is a webSocket client!");
|
||||
}
|
||||
clientDisconnect(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketsClient::connectedCb() {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
_client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
client->tcp = NULL;
|
||||
|
||||
// reconnect
|
||||
c->asyncConnect();
|
||||
|
||||
return true;
|
||||
},
|
||||
this, std::placeholders::_1, &_client));
|
||||
#endif
|
||||
|
||||
_client.status = WSC_HEADER;
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
// set Timeout for readBytesUntil and readStringUntil
|
||||
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||
#endif
|
||||
|
||||
#if !defined(LIBRETINY)
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
_client.tcp->setNoDelay(true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
#if defined(SSL_AXTLS) || defined(ESP32)
|
||||
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
||||
WebSockets::clientDisconnect(&_client, 1000);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||
#endif
|
||||
} else if(_client.isSSL && !_CA_cert) {
|
||||
#if defined(SSL_BARESSL)
|
||||
_client.ssl->setInsecure();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// send Header to Server
|
||||
sendHeader(&_client);
|
||||
}
|
||||
|
||||
void WebSocketsClient::connectFailedCb() {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Failed\n", _host.c_str(), _port);
|
||||
}
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
|
||||
void WebSocketsClient::asyncConnect() {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
|
||||
|
||||
AsyncClient * tcpclient = new AsyncClient();
|
||||
|
||||
if(!tcpclient) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] creating AsyncClient class failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tcpclient->onDisconnect([](void * obj, AsyncClient * c) {
|
||||
c->free();
|
||||
delete c;
|
||||
});
|
||||
|
||||
tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
|
||||
ws->_client.tcp = new AsyncTCPbuffer(tcp);
|
||||
if(!ws->_client.tcp) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
|
||||
ws->connectFailedCb();
|
||||
return;
|
||||
}
|
||||
ws->connectedCb();
|
||||
},
|
||||
this, std::placeholders::_2));
|
||||
|
||||
tcpclient->onError(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
|
||||
ws->connectFailedCb();
|
||||
|
||||
// reconnect
|
||||
ws->asyncConnect();
|
||||
},
|
||||
this, std::placeholders::_2));
|
||||
|
||||
if(!tcpclient->connect(_host.c_str(), _port)) {
|
||||
connectFailedCb();
|
||||
delete tcpclient;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* send heartbeat ping to server in set intervals
|
||||
*/
|
||||
void WebSocketsClient::handleHBPing() {
|
||||
if(_client.pingInterval == 0)
|
||||
return;
|
||||
uint32_t pi = millis() - _client.lastPing;
|
||||
if(pi > _client.pingInterval) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping\n");
|
||||
if(sendPing()) {
|
||||
_client.lastPing = millis();
|
||||
_client.pongReceived = false;
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n");
|
||||
WebSockets::clientDisconnect(&_client, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* enable ping/pong heartbeat process
|
||||
* @param pingInterval uint32_t how often ping will be sent
|
||||
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||
*/
|
||||
void WebSocketsClient::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||
WebSockets::enableHeartbeat(&_client, pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable ping/pong heartbeat process
|
||||
*/
|
||||
void WebSocketsClient::disableHeartbeat() {
|
||||
_client.pingInterval = 0;
|
||||
}
|
||||
171
lib/LT_WebSockets/src/WebSocketsClient.h
Normal file
171
lib/LT_WebSockets/src/WebSocketsClient.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* @file WebSocketsClient.h
|
||||
* @date 20.05.2015
|
||||
* @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 WEBSOCKETSCLIENT_H_
|
||||
#define WEBSOCKETSCLIENT_H_
|
||||
|
||||
#include "WebSockets.h"
|
||||
|
||||
class WebSocketsClient : protected WebSockets {
|
||||
public:
|
||||
#ifdef __AVR__
|
||||
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
||||
#else
|
||||
typedef std::function<void(WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;
|
||||
#endif
|
||||
|
||||
WebSocketsClient(void);
|
||||
virtual ~WebSocketsClient(void);
|
||||
|
||||
void begin(const char * host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
||||
#ifndef LIBRETINY
|
||||
void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
#ifdef SSL_AXTLS
|
||||
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino");
|
||||
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
||||
#else
|
||||
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
|
||||
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||
#endif
|
||||
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||
#endif
|
||||
|
||||
void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||
void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||
|
||||
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||
#if defined(SSL_BARESSL)
|
||||
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void loop(void);
|
||||
#else
|
||||
// Async interface not need a loop call
|
||||
void loop(void) __attribute__((deprecated)) {}
|
||||
#endif
|
||||
|
||||
void onEvent(WebSocketClientEvent cbEvent);
|
||||
|
||||
bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendTXT(const uint8_t * payload, size_t length = 0);
|
||||
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendTXT(const char * payload, size_t length = 0);
|
||||
bool sendTXT(String & payload);
|
||||
bool sendTXT(char payload);
|
||||
|
||||
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||
bool sendBIN(const uint8_t * payload, size_t length);
|
||||
|
||||
bool sendPing(uint8_t * payload = NULL, size_t length = 0);
|
||||
bool sendPing(String & payload);
|
||||
|
||||
void disconnect(void);
|
||||
|
||||
void setAuthorization(const char * user, const char * password);
|
||||
void setAuthorization(const char * auth);
|
||||
|
||||
void setExtraHeaders(const char * extraHeaders = NULL);
|
||||
|
||||
void setReconnectInterval(unsigned long time);
|
||||
|
||||
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||
void disableHeartbeat();
|
||||
|
||||
bool isConnected(void);
|
||||
|
||||
protected:
|
||||
String _host;
|
||||
uint16_t _port;
|
||||
|
||||
#if defined(HAS_SSL)
|
||||
#ifdef SSL_AXTLS
|
||||
String _fingerprint;
|
||||
const char * _CA_cert;
|
||||
#define SSL_FINGERPRINT_IS_SET (_fingerprint.length())
|
||||
#define SSL_FINGERPRINT_NULL ""
|
||||
#else
|
||||
const uint8_t * _fingerprint;
|
||||
BearSSL::X509List * _CA_cert;
|
||||
BearSSL::X509List * _client_cert;
|
||||
BearSSL::PrivateKey * _client_key;
|
||||
#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL)
|
||||
#define SSL_FINGERPRINT_NULL NULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
WSclient_t _client;
|
||||
|
||||
WebSocketClientEvent _cbEvent;
|
||||
|
||||
unsigned long _lastConnectionFail;
|
||||
unsigned long _reconnectInterval;
|
||||
unsigned long _lastHeaderSent;
|
||||
|
||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||
|
||||
void clientDisconnect(WSclient_t * client);
|
||||
bool clientIsConnected(WSclient_t * client);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void handleClientData(void);
|
||||
#endif
|
||||
|
||||
void sendHeader(WSclient_t * client);
|
||||
void handleHeader(WSclient_t * client, String * headerLine);
|
||||
|
||||
void connectedCb();
|
||||
void connectFailedCb();
|
||||
|
||||
void handleHBPing(); // send ping in specified intervals
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
void asyncConnect();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* called for sending a Event to the app
|
||||
* @param type WStype_t
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
*/
|
||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
if(_cbEvent) {
|
||||
_cbEvent(type, payload, length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* WEBSOCKETSCLIENT_H_ */
|
||||
966
lib/LT_WebSockets/src/WebSocketsServer.cpp
Normal file
966
lib/LT_WebSockets/src/WebSocketsServer.cpp
Normal file
@@ -0,0 +1,966 @@
|
||||
/**
|
||||
* @file WebSocketsServer.cpp
|
||||
* @date 20.05.2015
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "WebSockets.h"
|
||||
#include "WebSocketsServer.h"
|
||||
#ifdef LIBRETINY
|
||||
#include "Common.h"
|
||||
#endif
|
||||
WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) {
|
||||
_origin = origin;
|
||||
_protocol = protocol;
|
||||
_runnning = false;
|
||||
_pingInterval = 0;
|
||||
_pongTimeout = 0;
|
||||
_disconnectTimeoutCount = 0;
|
||||
|
||||
_cbEvent = NULL;
|
||||
|
||||
_httpHeaderValidationFunc = NULL;
|
||||
_mandatoryHttpHeaders = NULL;
|
||||
_mandatoryHttpHeaderCount = 0;
|
||||
}
|
||||
|
||||
WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol)
|
||||
: WebSocketsServerCore(origin, protocol) {
|
||||
_port = port;
|
||||
|
||||
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
_server->onClient([](void * s, AsyncClient * c) {
|
||||
((WebSocketsServerCore *)s)->newClient(new AsyncTCPbuffer(c));
|
||||
},
|
||||
this);
|
||||
#endif
|
||||
}
|
||||
|
||||
WebSocketsServerCore::~WebSocketsServerCore() {
|
||||
// disconnect all clients
|
||||
close();
|
||||
|
||||
if(_mandatoryHttpHeaders)
|
||||
delete[] _mandatoryHttpHeaders;
|
||||
|
||||
_mandatoryHttpHeaderCount = 0;
|
||||
}
|
||||
|
||||
WebSocketsServer::~WebSocketsServer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* called to initialize the Websocket server
|
||||
*/
|
||||
void WebSocketsServerCore::begin(void) {
|
||||
// adjust clients storage:
|
||||
// _clients[i]'s constructor are already called,
|
||||
// all its members are initialized to their default value,
|
||||
// except the ones explicitly detailed in WSclient_t() constructor.
|
||||
// Then we need to initialize some members to non-trivial values:
|
||||
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
_clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount);
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
randomSeed(RANDOM_REG32);
|
||||
#elif defined(ESP32)
|
||||
#define DR_REG_RNG_BASE 0x3ff75144
|
||||
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
|
||||
#else
|
||||
// TODO find better seed
|
||||
randomSeed(millis());
|
||||
#endif
|
||||
|
||||
_runnning = true;
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||
}
|
||||
|
||||
void WebSocketsServerCore::close(void) {
|
||||
_runnning = false;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set callback function
|
||||
* @param cbEvent WebSocketServerEvent
|
||||
*/
|
||||
void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) {
|
||||
_cbEvent = cbEvent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the custom http header validator function
|
||||
* @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function
|
||||
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
|
||||
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
|
||||
*/
|
||||
void WebSocketsServerCore::onValidateHttpHeader(
|
||||
WebSocketServerHttpHeaderValFunc validationFunc,
|
||||
const char * mandatoryHttpHeaders[],
|
||||
size_t mandatoryHttpHeaderCount) {
|
||||
_httpHeaderValidationFunc = validationFunc;
|
||||
|
||||
if(_mandatoryHttpHeaders)
|
||||
delete[] _mandatoryHttpHeaders;
|
||||
|
||||
_mandatoryHttpHeaderCount = mandatoryHttpHeaderCount;
|
||||
_mandatoryHttpHeaders = new String[_mandatoryHttpHeaderCount];
|
||||
|
||||
for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
||||
_mandatoryHttpHeaders[i] = mandatoryHttpHeaders[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* send text data to client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
return false;
|
||||
}
|
||||
if(length == 0) {
|
||||
length = strlen((const char *)payload);
|
||||
}
|
||||
WSclient_t * client = &_clients[num];
|
||||
if(clientIsConnected(client)) {
|
||||
return sendFrame(client, WSop_text, payload, length, true, headerToPayload);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
|
||||
return sendTXT(num, (uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
|
||||
return sendTXT(num, (uint8_t *)payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendTXT(uint8_t num, const char * payload, size_t length) {
|
||||
return sendTXT(num, (uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) {
|
||||
return sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* send text data to client all
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||
WSclient_t * client;
|
||||
bool ret = true;
|
||||
if(length == 0) {
|
||||
length = strlen((const char *)payload);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(clientIsConnected(client)) {
|
||||
if(!sendFrame(client, WSop_text, payload, length, true, headerToPayload)) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastTXT(const uint8_t * payload, size_t length) {
|
||||
return broadcastTXT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
|
||||
return broadcastTXT((uint8_t *)payload, length, headerToPayload);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastTXT(const char * payload, size_t length) {
|
||||
return broadcastTXT((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastTXT(String & payload) {
|
||||
return broadcastTXT((uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* send binary data to client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool fin, bool continuation, bool headerToPayload) {
|
||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
return false;
|
||||
}
|
||||
WSclient_t * client = &_clients[num];
|
||||
if(clientIsConnected(client)) {
|
||||
if(continuation) {
|
||||
return sendFrame(client, WSop_continuation, payload, length, fin, headerToPayload);
|
||||
} else {
|
||||
return sendFrame(client, WSop_binary, payload, length, fin, headerToPayload);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
|
||||
return sendBIN(num, (uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* send binary data to client all
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @param headerToPayload bool (see sendFrame for more details)
|
||||
* @return true if ok
|
||||
*/
|
||||
bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool fin, bool continuation, bool headerToPayload) {
|
||||
WSclient_t * client;
|
||||
bool ret = true;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(clientIsConnected(client)) {
|
||||
if(continuation) {
|
||||
ret = sendFrame(client, WSop_continuation, payload, length, fin, headerToPayload);
|
||||
} else {
|
||||
ret = sendFrame(client, WSop_binary, payload, length, fin, headerToPayload);
|
||||
}
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length) {
|
||||
return broadcastBIN((uint8_t *)payload, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a WS ping to Client
|
||||
* @param num uint8_t client id
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @return true if ping is send out
|
||||
*/
|
||||
bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t length) {
|
||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
return false;
|
||||
}
|
||||
WSclient_t * client = &_clients[num];
|
||||
if(clientIsConnected(client)) {
|
||||
return sendFrame(client, WSop_ping, payload, length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) {
|
||||
return sendPing(num, (uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a WS ping to all Client
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
* @return true if ping is send out
|
||||
*/
|
||||
bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) {
|
||||
WSclient_t * client;
|
||||
bool ret = true;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(clientIsConnected(client)) {
|
||||
if(!sendFrame(client, WSop_ping, payload, length)) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WebSocketsServerCore::broadcastPing(String & payload) {
|
||||
return broadcastPing((uint8_t *)payload.c_str(), payload.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect all clients
|
||||
*/
|
||||
void WebSocketsServerCore::disconnect(void) {
|
||||
WSclient_t * client;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(clientIsConnected(client)) {
|
||||
WebSockets::clientDisconnect(client, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect one client
|
||||
* @param num uint8_t client id
|
||||
*/
|
||||
void WebSocketsServerCore::disconnect(uint8_t num) {
|
||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
return;
|
||||
}
|
||||
WSclient_t * client = &_clients[num];
|
||||
if(clientIsConnected(client)) {
|
||||
WebSockets::clientDisconnect(client, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set the Authorization for the http request
|
||||
* @param user const char *
|
||||
* @param password const char *
|
||||
*/
|
||||
void WebSocketsServerCore::setAuthorization(const char * user, const char * password) {
|
||||
if(user && password) {
|
||||
String auth = user;
|
||||
auth += ":";
|
||||
auth += password;
|
||||
_base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the Authorizatio for the http request
|
||||
* @param auth const char * base64
|
||||
*/
|
||||
void WebSocketsServerCore::setAuthorization(const char * auth) {
|
||||
if(auth) {
|
||||
_base64Authorization = auth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* count the connected clients (optional ping them)
|
||||
* @param ping bool ping the connected clients
|
||||
*/
|
||||
int WebSocketsServerCore::connectedClients(bool ping) {
|
||||
WSclient_t * client;
|
||||
int count = 0;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(client->status == WSC_CONNECTED) {
|
||||
if(ping != true || sendPing(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* see if one client is connected
|
||||
* @param num uint8_t client id
|
||||
*/
|
||||
bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
|
||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
return false;
|
||||
}
|
||||
WSclient_t * client = &_clients[num];
|
||||
return clientIsConnected(client);
|
||||
}
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
/**
|
||||
* get an IP for a client
|
||||
* @param num uint8_t client id
|
||||
* @return IPAddress
|
||||
*/
|
||||
IPAddress WebSocketsServerCore::remoteIP(uint8_t num) {
|
||||
if(num < WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||
WSclient_t * client = &_clients[num];
|
||||
if(clientIsConnected(client)) {
|
||||
return client->tcp->remoteIP();
|
||||
}
|
||||
}
|
||||
|
||||
return IPAddress();
|
||||
}
|
||||
#endif
|
||||
|
||||
//#################################################################################
|
||||
//#################################################################################
|
||||
//#################################################################################
|
||||
|
||||
/**
|
||||
* handle new client connection
|
||||
* @param client
|
||||
*/
|
||||
WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
||||
WSclient_t * client;
|
||||
// search free list entry for client
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
|
||||
// state is not connected or tcp connection is lost
|
||||
if(!clientIsConnected(client)) {
|
||||
client->tcp = TCPclient;
|
||||
#if defined(HAS_SSL)
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
client->isSSL = false;
|
||||
client->tcp->setNoDelay(true);
|
||||
#endif
|
||||
#endif //ssl
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
// set Timeout for readBytesUntil and readStringUntil
|
||||
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||
#endif
|
||||
client->status = WSC_HEADER;
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
IPAddress ip = client->tcp->remoteIP();
|
||||
#endif
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]);
|
||||
#else
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num);
|
||||
#endif
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->tcp->onDisconnect(std::bind([](WebSocketsServerCore * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
||||
|
||||
AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
|
||||
if(*sl == obj) {
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
*sl = NULL;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
this, std::placeholders::_1, client));
|
||||
|
||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
|
||||
#endif
|
||||
|
||||
client->pingInterval = _pingInterval;
|
||||
client->pongTimeout = _pongTimeout;
|
||||
client->disconnectTimeoutCount = _disconnectTimeoutCount;
|
||||
client->lastPing = millis();
|
||||
client->pongReceived = false;
|
||||
|
||||
return client;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @param opcode WSopcode_t
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
*/
|
||||
void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
||||
WStype_t type = WStype_ERROR;
|
||||
|
||||
switch(opcode) {
|
||||
case WSop_text:
|
||||
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
|
||||
break;
|
||||
case WSop_binary:
|
||||
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
|
||||
break;
|
||||
case WSop_continuation:
|
||||
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
|
||||
break;
|
||||
case WSop_ping:
|
||||
type = WStype_PING;
|
||||
break;
|
||||
case WSop_pong:
|
||||
type = WStype_PONG;
|
||||
break;
|
||||
case WSop_close:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
runCbEvent(client->num, type, payload, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard a native client
|
||||
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
|
||||
*/
|
||||
void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
||||
if(!client) {
|
||||
return;
|
||||
}
|
||||
if(client->tcp) {
|
||||
if(client->tcp->connected()) {
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
|
||||
client->tcp->flush();
|
||||
#endif
|
||||
client->tcp->stop();
|
||||
}
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
#else
|
||||
delete client->tcp;
|
||||
#endif
|
||||
client->tcp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect an client
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
|
||||
#if defined(HAS_SSL)
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
if(client->isSSL && client->ssl) {
|
||||
if(client->ssl->connected()) {
|
||||
client->ssl->flush();
|
||||
client->ssl->stop();
|
||||
}
|
||||
delete client->ssl;
|
||||
client->ssl = NULL;
|
||||
client->tcp = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif //ssl
|
||||
|
||||
dropNativeClient(client);
|
||||
|
||||
client->cUrl = "";
|
||||
client->cKey = "";
|
||||
client->cProtocol = "";
|
||||
client->cVersion = 0;
|
||||
client->cIsUpgrade = false;
|
||||
client->cIsWebsocket = false;
|
||||
|
||||
client->cWsRXsize = 0;
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->cHttpLine = "";
|
||||
#endif
|
||||
|
||||
client->status = WSC_NOT_CONNECTED;
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num);
|
||||
|
||||
runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* get client state
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
* @return true = connected
|
||||
*/
|
||||
bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) {
|
||||
if(!client->tcp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client->tcp->connected()) {
|
||||
if(client->status != WSC_NOT_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// client lost
|
||||
if(client->status != WSC_NOT_CONNECTED) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] client connection lost.\n", client->num);
|
||||
// do cleanup
|
||||
clientDisconnect(client);
|
||||
}
|
||||
}
|
||||
|
||||
if(client->tcp) {
|
||||
// do cleanup
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] client list cleanup.\n", client->num);
|
||||
clientDisconnect(client);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
/**
|
||||
* Handle incoming Connection Request
|
||||
*/
|
||||
WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient) {
|
||||
WSclient_t * client = newClient(tcpClient);
|
||||
|
||||
if(!client) {
|
||||
// no free space to handle client
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
#ifndef NODEBUG_WEBSOCKETS
|
||||
IPAddress ip = tcpClient->remoteIP();
|
||||
#endif
|
||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
#else
|
||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
||||
#endif
|
||||
// no client! => create dummy!
|
||||
WSclient_t dummy = WSclient_t();
|
||||
client = &dummy;
|
||||
client->tcp = tcpClient;
|
||||
dropNativeClient(client);
|
||||
}
|
||||
|
||||
WEBSOCKETS_YIELD();
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming Connection Request
|
||||
*/
|
||||
void WebSocketsServer::handleNewClients(void) {
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
while(_server->hasClient()) {
|
||||
#endif
|
||||
|
||||
// store new connection
|
||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
||||
if(!tcpClient) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
handleNewClient(tcpClient);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Handel incomming data from Client
|
||||
*/
|
||||
void WebSocketsServerCore::handleClientData(void) {
|
||||
WSclient_t * client;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
if(clientIsConnected(client)) {
|
||||
int len = client->tcp->available();
|
||||
if(len > 0) {
|
||||
// DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
||||
switch(client->status) {
|
||||
case WSC_HEADER: {
|
||||
String headerLine = client->tcp->readStringUntil('\n');
|
||||
handleHeader(client, &headerLine);
|
||||
} break;
|
||||
case WSC_CONNECTED:
|
||||
WebSockets::handleWebsocket(client);
|
||||
break;
|
||||
default:
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] unknown client status %d\n", client->num, client->status);
|
||||
WebSockets::clientDisconnect(client, 1002);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleHBPing(client);
|
||||
handleHBTimeout(client);
|
||||
}
|
||||
WEBSOCKETS_YIELD();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||
* @param headerName String ///< the name of the header being checked
|
||||
*/
|
||||
bool WebSocketsServerCore::hasMandatoryHeader(String headerName) {
|
||||
for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
||||
if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* handles http header reading for WebSocket upgrade
|
||||
* @param client WSclient_t * ///< pointer to the client struct
|
||||
* @param headerLine String ///< the header being read / processed
|
||||
*/
|
||||
void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine) {
|
||||
static const char * NEW_LINE = "\r\n";
|
||||
|
||||
headerLine->trim(); // remove \r
|
||||
|
||||
if(headerLine->length() > 0) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str());
|
||||
|
||||
// websocket requests always start with GET see rfc6455
|
||||
if(headerLine->startsWith("GET ")) {
|
||||
// cut URL out
|
||||
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
||||
|
||||
// reset non-websocket http header validation state for this client
|
||||
client->cHttpHeadersValid = true;
|
||||
client->cMandatoryHeadersCount = 0;
|
||||
|
||||
} else if(headerLine->indexOf(':') >= 0) {
|
||||
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
||||
String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
|
||||
|
||||
// remove space in the beginning (RFC2616)
|
||||
if(headerValue[0] == ' ') {
|
||||
headerValue.remove(0, 1);
|
||||
}
|
||||
|
||||
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
|
||||
headerValue.toLowerCase();
|
||||
if(headerValue.indexOf(WEBSOCKETS_STRING("upgrade")) >= 0) {
|
||||
client->cIsUpgrade = true;
|
||||
}
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
|
||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
|
||||
client->cIsWebsocket = true;
|
||||
}
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
||||
client->cVersion = headerValue.toInt();
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Key"))) {
|
||||
client->cKey = headerValue;
|
||||
client->cKey.trim(); // see rfc6455
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
|
||||
client->cProtocol = headerValue;
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
|
||||
client->cExtensions = headerValue;
|
||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Authorization"))) {
|
||||
client->base64Authorization = headerValue;
|
||||
} else {
|
||||
client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue);
|
||||
if(_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) {
|
||||
client->cMandatoryHeadersCount++;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
||||
}
|
||||
|
||||
(*headerLine) = "";
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str());
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid);
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount);
|
||||
|
||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||
|
||||
if(ok) {
|
||||
if(client->cUrl.length() == 0) {
|
||||
ok = false;
|
||||
}
|
||||
if(client->cKey.length() == 0) {
|
||||
ok = false;
|
||||
}
|
||||
if(client->cVersion != 13) {
|
||||
ok = false;
|
||||
}
|
||||
if(!client->cHttpHeadersValid) {
|
||||
ok = false;
|
||||
}
|
||||
if(client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_base64Authorization.length() > 0) {
|
||||
String auth = WEBSOCKETS_STRING("Basic ");
|
||||
auth += _base64Authorization;
|
||||
if(auth != client->base64Authorization) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num);
|
||||
handleAuthorizationFailed(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(ok) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num);
|
||||
|
||||
// generate Sec-WebSocket-Accept key
|
||||
String sKey = acceptKey(client->cKey);
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - sKey: %s\n", client->num, sKey.c_str());
|
||||
|
||||
client->status = WSC_CONNECTED;
|
||||
|
||||
String handshake = WEBSOCKETS_STRING(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Server: arduino-WebSocketsServer\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"Sec-WebSocket-Accept: ");
|
||||
handshake += sKey + NEW_LINE;
|
||||
|
||||
if(_origin.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Access-Control-Allow-Origin: ");
|
||||
handshake += _origin + NEW_LINE;
|
||||
}
|
||||
|
||||
if(client->cProtocol.length() > 0) {
|
||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
|
||||
handshake += _protocol + NEW_LINE;
|
||||
}
|
||||
|
||||
// header end
|
||||
handshake += NEW_LINE;
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] handshake %s", client->num, (uint8_t *)handshake.c_str());
|
||||
|
||||
write(client, (uint8_t *)handshake.c_str(), handshake.length());
|
||||
|
||||
headerDone(client);
|
||||
|
||||
// send ping
|
||||
WebSockets::sendFrame(client, WSop_ping);
|
||||
|
||||
runCbEvent(client->num, WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
||||
|
||||
} else {
|
||||
handleNonWebsocketConnection(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send heartbeat ping to server in set intervals
|
||||
*/
|
||||
void WebSocketsServerCore::handleHBPing(WSclient_t * client) {
|
||||
if(client->pingInterval == 0)
|
||||
return;
|
||||
uint32_t pi = millis() - client->lastPing;
|
||||
if(pi > client->pingInterval) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d] sending HB ping\n", client->num);
|
||||
if(sendPing(client->num)) {
|
||||
client->lastPing = millis();
|
||||
client->pongReceived = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* enable ping/pong heartbeat process
|
||||
* @param pingInterval uint32_t how often ping will be sent
|
||||
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||
*/
|
||||
void WebSocketsServerCore::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||
_pingInterval = pingInterval;
|
||||
_pongTimeout = pongTimeout;
|
||||
_disconnectTimeoutCount = disconnectTimeoutCount;
|
||||
|
||||
WSclient_t * client;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
WebSockets::enableHeartbeat(client, pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disable ping/pong heartbeat process
|
||||
*/
|
||||
void WebSocketsServerCore::disableHeartbeat() {
|
||||
_pingInterval = 0;
|
||||
|
||||
WSclient_t * client;
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
client->pingInterval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// WebSocketServer
|
||||
|
||||
/**
|
||||
* called to initialize the Websocket server
|
||||
*/
|
||||
void WebSocketsServer::begin(void) {
|
||||
WebSocketsServerCore::begin();
|
||||
_server->begin();
|
||||
|
||||
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
|
||||
}
|
||||
|
||||
void WebSocketsServer::close(void) {
|
||||
WebSocketsServerCore::close();
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||
_server->close();
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
_server->end();
|
||||
#else
|
||||
// TODO how to close server?
|
||||
#endif
|
||||
}
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
/**
|
||||
* called in arduino loop
|
||||
*/
|
||||
void WebSocketsServerCore::loop(void) {
|
||||
if(_runnning) {
|
||||
WEBSOCKETS_YIELD();
|
||||
handleClientData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called in arduino loop
|
||||
*/
|
||||
void WebSocketsServer::loop(void) {
|
||||
if(_runnning) {
|
||||
WEBSOCKETS_YIELD();
|
||||
handleNewClients();
|
||||
WebSocketsServerCore::loop();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
244
lib/LT_WebSockets/src/WebSocketsServer.h
Normal file
244
lib/LT_WebSockets/src/WebSocketsServer.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @file WebSocketsServer.h
|
||||
* @date 20.05.2015
|
||||
* @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 WEBSOCKETSSERVER_H_
|
||||
#define WEBSOCKETSSERVER_H_
|
||||
|
||||
#include "WebSockets.h"
|
||||
|
||||
#ifndef WEBSOCKETS_SERVER_CLIENT_MAX
|
||||
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
||||
#endif
|
||||
|
||||
class WebSocketsServerCore : protected WebSockets {
|
||||
public:
|
||||
WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino");
|
||||
virtual ~WebSocketsServerCore(void);
|
||||
|
||||
void begin(void);
|
||||
void close(void);
|
||||
|
||||
#ifdef __AVR__
|
||||
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
||||
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
|
||||
#else
|
||||
typedef std::function<void(uint8_t num, WStype_t type, uint8_t * payload, size_t length)> WebSocketServerEvent;
|
||||
typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
|
||||
#endif
|
||||
|
||||
void onEvent(WebSocketServerEvent cbEvent);
|
||||
void onValidateHttpHeader(
|
||||
WebSocketServerHttpHeaderValFunc validationFunc,
|
||||
const char * mandatoryHttpHeaders[],
|
||||
size_t mandatoryHttpHeaderCount);
|
||||
|
||||
bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
|
||||
bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool sendTXT(uint8_t num, const char * payload, size_t length = 0);
|
||||
bool sendTXT(uint8_t num, String & payload);
|
||||
|
||||
bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool broadcastTXT(const uint8_t * payload, size_t length = 0);
|
||||
bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||
bool broadcastTXT(const char * payload, size_t length = 0);
|
||||
bool broadcastTXT(String & payload);
|
||||
|
||||
bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool fin = true, bool continuation = false, bool headerToPayload = false);
|
||||
bool sendBIN(uint8_t num, const uint8_t * payload, size_t length);
|
||||
|
||||
bool broadcastBIN(uint8_t * payload, size_t length, bool fin = true, bool continuation = false, bool headerToPayload = false);
|
||||
bool broadcastBIN(const uint8_t * payload, size_t length);
|
||||
|
||||
bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0);
|
||||
bool sendPing(uint8_t num, String & payload);
|
||||
|
||||
bool broadcastPing(uint8_t * payload = NULL, size_t length = 0);
|
||||
bool broadcastPing(String & payload);
|
||||
|
||||
void disconnect(void);
|
||||
void disconnect(uint8_t num);
|
||||
|
||||
void setAuthorization(const char * user, const char * password);
|
||||
void setAuthorization(const char * auth);
|
||||
|
||||
int connectedClients(bool ping = false);
|
||||
|
||||
bool clientIsConnected(uint8_t num);
|
||||
|
||||
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||
void disableHeartbeat();
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
IPAddress remoteIP(uint8_t num);
|
||||
#endif
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void loop(void); // handle client data only
|
||||
#endif
|
||||
|
||||
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
||||
|
||||
protected:
|
||||
String _origin;
|
||||
String _protocol;
|
||||
String _base64Authorization; ///< Base64 encoded Auth request
|
||||
String * _mandatoryHttpHeaders;
|
||||
size_t _mandatoryHttpHeaderCount;
|
||||
|
||||
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
||||
|
||||
WebSocketServerEvent _cbEvent;
|
||||
WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc;
|
||||
|
||||
bool _runnning;
|
||||
|
||||
uint32_t _pingInterval;
|
||||
uint32_t _pongTimeout;
|
||||
uint8_t _disconnectTimeoutCount;
|
||||
|
||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||
|
||||
void clientDisconnect(WSclient_t * client);
|
||||
bool clientIsConnected(WSclient_t * client);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void handleClientData(void);
|
||||
#endif
|
||||
|
||||
void handleHeader(WSclient_t * client, String * headerLine);
|
||||
|
||||
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
||||
|
||||
/**
|
||||
* called if a non Websocket connection is coming in.
|
||||
* Note: can be override
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
||||
client->tcp->write(
|
||||
"HTTP/1.1 400 Bad Request\r\n"
|
||||
"Server: arduino-WebSocket-Server\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Content-Length: 32\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n"
|
||||
"This is a Websocket server only!");
|
||||
clientDisconnect(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* called if a non Authorization connection is coming in.
|
||||
* Note: can be override
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
||||
client->tcp->write(
|
||||
"HTTP/1.1 401 Unauthorized\r\n"
|
||||
"Server: arduino-WebSocket-Server\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Content-Length: 45\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"WWW-Authenticate: Basic realm=\"WebSocket Server\""
|
||||
"\r\n"
|
||||
"This Websocket server requires Authorization!");
|
||||
clientDisconnect(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* called for sending a Event to the app
|
||||
* @param num uint8_t
|
||||
* @param type WStype_t
|
||||
* @param payload uint8_t *
|
||||
* @param length size_t
|
||||
*/
|
||||
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||
if(_cbEvent) {
|
||||
_cbEvent(num, type, payload, length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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-*)
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
||||
if(_httpHeaderValidationFunc) {
|
||||
// return the value of the custom http header validation function
|
||||
return _httpHeaderValidationFunc(headerName, headerValue);
|
||||
}
|
||||
// no custom http header validation so just assume all is good
|
||||
return true;
|
||||
}
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* drop native tcp connection (client->tcp)
|
||||
*/
|
||||
void dropNativeClient(WSclient_t * client);
|
||||
|
||||
private:
|
||||
/*
|
||||
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||
* @param headerName String ///< the name of the header being checked
|
||||
*/
|
||||
bool hasMandatoryHeader(String headerName);
|
||||
};
|
||||
|
||||
class WebSocketsServer : public WebSocketsServerCore {
|
||||
public:
|
||||
WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino");
|
||||
virtual ~WebSocketsServer(void);
|
||||
|
||||
void begin(void);
|
||||
void close(void);
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void loop(void); // handle incoming client and client data
|
||||
#else
|
||||
// Async interface not need a loop call
|
||||
void loop(void) __attribute__((deprecated)) {
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||
void handleNewClients(void);
|
||||
#endif
|
||||
|
||||
uint16_t _port;
|
||||
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
||||
};
|
||||
|
||||
#endif /* WEBSOCKETSSERVER_H_ */
|
||||
36
lib/LT_WebSockets/src/WebSocketsVersion.h
Normal file
36
lib/LT_WebSockets/src/WebSocketsVersion.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @file WebSocketsVersion.h
|
||||
* @date 05.04.2022
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the WebSockets for Arduino.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETSVERSION_H_
|
||||
#define WEBSOCKETSVERSION_H_
|
||||
|
||||
#define WEBSOCKETS_VERSION "2.3.7"
|
||||
|
||||
#define WEBSOCKETS_VERSION_MAJOR 2
|
||||
#define WEBSOCKETS_VERSION_MINOR 3
|
||||
#define WEBSOCKETS_VERSION_PATCH 7
|
||||
|
||||
#define WEBSOCKETS_VERSION_INT 2003007
|
||||
|
||||
#endif /* WEBSOCKETSVERSION_H_ */
|
||||
134
lib/LT_WebSockets/travis/common.sh
Normal file
134
lib/LT_WebSockets/travis/common.sh
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
function build_sketches()
|
||||
{
|
||||
local arduino=$1
|
||||
local srcpath=$2
|
||||
local platform=$3
|
||||
local sketches=$(find $srcpath -name *.ino)
|
||||
for sketch in $sketches; do
|
||||
local sketchdir=$(dirname $sketch)
|
||||
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||
echo -e "\n\n ------------ Skipping $sketch ------------ \n\n";
|
||||
continue
|
||||
fi
|
||||
echo -e "\n\n ------------ Building $sketch ------------ \n\n";
|
||||
$arduino --verify $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
|
||||
done
|
||||
}
|
||||
|
||||
function build_sketch()
|
||||
{
|
||||
local arduino=$1
|
||||
local sketch=$2
|
||||
$arduino --verify $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()
|
||||
{
|
||||
echo Setup core for $1
|
||||
|
||||
cd $HOME/arduino_ide/hardware
|
||||
|
||||
if [ "$1" = "esp8266" ] ; then
|
||||
mkdir esp8266com
|
||||
cd esp8266com
|
||||
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266
|
||||
cd esp8266/
|
||||
git submodule update --init
|
||||
rm -rf .git
|
||||
cd tools
|
||||
python get.py
|
||||
fi
|
||||
|
||||
if [ "$1" = "esp32" ] ; then
|
||||
mkdir espressif
|
||||
cd espressif
|
||||
git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32
|
||||
cd esp32/
|
||||
rm -rf .git
|
||||
cd tools
|
||||
python get.py
|
||||
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
lib/LT_WebSockets/travis/version.py
Normal file
132
lib/LT_WebSockets/travis/version.py
Normal 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!')
|
||||
@@ -105,7 +105,7 @@ void TickerScheduler::update()
|
||||
{
|
||||
if (this->items[i].is_used)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
#if defined ARDUINO_ARCH_AVR || defined LIBRETINY
|
||||
this->items[i].t.Tick();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
#if defined ARDUINO_ARCH_AVR || defined LIBRETINY
|
||||
class Ticker
|
||||
{
|
||||
typedef void(*ticker_callback_t)(bool*);
|
||||
@@ -41,12 +41,17 @@ public:
|
||||
this->is_attached = true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
//#ifdef ARDUINO_ARCH_ESP8266
|
||||
#include <Ticker.h>
|
||||
#include <functional>
|
||||
//#endif
|
||||
#endif
|
||||
#if defined LIBRETINY
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
|
||||
void tickerFlagHandle(volatile bool * flag);
|
||||
|
||||
|
||||
@@ -25,6 +25,14 @@
|
||||
#include "WebSockets.h"
|
||||
#include "WebSocketsServer.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#if defined __has_include
|
||||
#if __has_include("soc/wdev_reg.h")
|
||||
#include "soc/wdev_reg.h"
|
||||
#endif // __has_include
|
||||
#endif // defined __has_include
|
||||
#endif
|
||||
|
||||
WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) {
|
||||
_origin = origin;
|
||||
_protocol = protocol;
|
||||
@@ -65,6 +73,7 @@ WebSocketsServerCore::~WebSocketsServerCore() {
|
||||
}
|
||||
|
||||
WebSocketsServer::~WebSocketsServer() {
|
||||
delete _server;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,9 +91,13 @@ void WebSocketsServerCore::begin(void) {
|
||||
|
||||
#ifdef ESP8266
|
||||
randomSeed(RANDOM_REG32);
|
||||
#elif defined(ESP32) && defined(WDEV_RND_REG)
|
||||
randomSeed(REG_READ(WDEV_RND_REG));
|
||||
#elif defined(ESP32)
|
||||
#define DR_REG_RNG_BASE 0x3ff75144
|
||||
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
randomSeed(rp2040.hwrand32());
|
||||
#else
|
||||
// TODO find better seed
|
||||
randomSeed(millis());
|
||||
@@ -400,7 +413,7 @@ bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
|
||||
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
|
||||
* @param num uint8_t client id
|
||||
@@ -432,8 +445,16 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
|
||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||
client = &_clients[i];
|
||||
|
||||
// state is not connected or tcp connection is lost
|
||||
if(!clientIsConnected(client)) {
|
||||
// look for match to existing socket before creating a new one
|
||||
if(clientIsConnected(client)) {
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
||||
// Check to see if it is the same socket - if so, return it
|
||||
if(client->tcp->getSocketNumber() == TCPclient->getSocketNumber()) {
|
||||
return client;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// state is not connected or tcp connection is lost
|
||||
client->tcp = TCPclient;
|
||||
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||
@@ -445,7 +466,7 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
|
||||
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||
#endif
|
||||
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
|
||||
IPAddress ip = client->tcp->remoteIP();
|
||||
#endif
|
||||
@@ -527,7 +548,7 @@ void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
||||
}
|
||||
if(client->tcp) {
|
||||
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();
|
||||
#endif
|
||||
client->tcp->stop();
|
||||
@@ -546,7 +567,7 @@ void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
|
||||
* @param client WSclient_t * ptr to the client struct
|
||||
*/
|
||||
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->ssl->connected()) {
|
||||
client->ssl->flush();
|
||||
@@ -620,7 +641,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
|
||||
|
||||
if(!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
|
||||
IPAddress ip = tcpClient->remoteIP();
|
||||
#endif
|
||||
@@ -633,6 +654,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
|
||||
client = &dummy;
|
||||
client->tcp = tcpClient;
|
||||
dropNativeClient(client);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WEBSOCKETS_YIELD();
|
||||
@@ -644,12 +666,16 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
|
||||
* Handle incoming Connection Request
|
||||
*/
|
||||
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()) {
|
||||
#endif
|
||||
|
||||
// store new connection
|
||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
||||
// store new connection
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); //available
|
||||
#else
|
||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->accept()); //available
|
||||
#endif
|
||||
if(!tcpClient) {
|
||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
||||
return;
|
||||
@@ -657,7 +683,7 @@ void WebSocketsServer::handleNewClients(void) {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -928,7 +954,7 @@ void WebSocketsServer::begin(void) {
|
||||
|
||||
void WebSocketsServer::close(void) {
|
||||
WebSocketsServerCore::close();
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
|
||||
_server->close();
|
||||
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||
_server->end();
|
||||
|
||||
@@ -90,7 +90,7 @@ class WebSocketsServerCore : protected WebSockets {
|
||||
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||
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);
|
||||
#endif
|
||||
|
||||
|
||||
110
myProfile.json
110
myProfile.json
@@ -15,17 +15,19 @@
|
||||
"mqttUser": "rise",
|
||||
"mqttPass": "3hostel3",
|
||||
"serverip": "http://iotmanager.org",
|
||||
"serverlocal": "http://192.168.1.2:5500",
|
||||
"log": 0,
|
||||
"mqttin": 0,
|
||||
"pinSCL": 0,
|
||||
"pinSDA": 0,
|
||||
"i2cFreq": 100000,
|
||||
"wg": "group1"
|
||||
"wg": "group1",
|
||||
"debugTraceMsgTlgrm": 1
|
||||
},
|
||||
"projectProp": {
|
||||
"platformio": {
|
||||
"default_envs": "esp8266_4mb",
|
||||
"comments_default_envs": "choose from: esp8266_4mb or esp32_4mb or esp32cam_4mb or esp32s2_4mb or esp32_4mb3f or esp32s3_16mb or esp32c3m_4mb or esp8266_1mb or esp8266_1mb_ota or esp8285_1mb or esp8285_1mb_ota",
|
||||
"default_envs": "esp32_4mb3f",
|
||||
"comments_default_envs": "choose from: esp8266_4mb, esp32_4mb, esp32_4mb3f, esp8266_16mb, esp32_16mb, esp32cam_4mb, esp32s2_4mb, esp32s3_16mb, esp32c3m_4mb, esp8266_1mb, esp8266_1mb_ota, esp8266_2mb, esp8266_2mb_ota, esp8285_1mb, esp8285_1mb_ota, esp32c6_4mb, esp32c6_8mb, bk7231n",
|
||||
"envs": [
|
||||
{
|
||||
"name": "esp8266_4mb",
|
||||
@@ -122,6 +124,22 @@
|
||||
"firmware": "0x10000",
|
||||
"partitions": "0x8000",
|
||||
"littlefs": "0x910000"
|
||||
},
|
||||
{
|
||||
"name": "esp32c6_4mb",
|
||||
"boot_app0": "0xe000",
|
||||
"bootloader_qio_80m": "0x1000",
|
||||
"firmware": "0x10000",
|
||||
"partitions": "0x8000",
|
||||
"littlefs": "0x310000"
|
||||
},
|
||||
{
|
||||
"name": "esp32c6_8mb",
|
||||
"boot_app0": "0xe000",
|
||||
"bootloader_qio_80m": "0x1000",
|
||||
"firmware": "0x10000",
|
||||
"partitions": "0x8000",
|
||||
"littlefs": "0x670000"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -136,6 +154,14 @@
|
||||
"path": "src/modules/virtual/Cron",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/DiscoveryHA",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/DiscoveryHomeD",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/GoogleSheet",
|
||||
"active": false
|
||||
@@ -148,6 +174,10 @@
|
||||
"path": "src/modules/virtual/LogingDaily",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/LogingHourly",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/Math",
|
||||
"active": true
|
||||
@@ -164,6 +194,10 @@
|
||||
"path": "src/modules/virtual/Timer",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/UpdateServer",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/virtual/Variable",
|
||||
"active": true
|
||||
@@ -179,16 +213,12 @@
|
||||
],
|
||||
"sensors": [
|
||||
{
|
||||
"path": "src/modules/exec/Pcf8591",
|
||||
"path": "src/modules/sensors/A02Distance",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/A02Distance",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Acs712",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Ads1115",
|
||||
@@ -208,7 +238,11 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/BL0937",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/BL0942",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Ble",
|
||||
@@ -306,12 +340,24 @@
|
||||
"path": "src/modules/sensors/Mhz19",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/ModbusRTU",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/ModbusRTUasync",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/MQgas",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Ntc",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Pcf8591",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
@@ -320,7 +366,7 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Pzem004t_v2",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/RCswitch",
|
||||
@@ -332,7 +378,7 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/S8",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Scd40",
|
||||
@@ -348,15 +394,15 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Sht20",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Sht30",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Sonar",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/UART",
|
||||
@@ -384,6 +430,10 @@
|
||||
"path": "src/modules/exec/Buzzer",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/EctoControlAdapter",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Enconder",
|
||||
"active": true
|
||||
@@ -402,7 +452,11 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/IoTServo",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/IRremote",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Mcp23008",
|
||||
@@ -410,11 +464,11 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Mcp23017",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Mp3",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Multitouch",
|
||||
@@ -426,7 +480,7 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Pcf8574",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Pwm32",
|
||||
@@ -434,7 +488,7 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Pwm8266",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/SDcard",
|
||||
@@ -466,7 +520,7 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/exec/Thermostat",
|
||||
"active": false
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"path": "src/modules/sensors/Ds2423",
|
||||
@@ -476,11 +530,15 @@
|
||||
"screens": [
|
||||
{
|
||||
"path": "src/modules/display/DwinI",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/GyverLAMP",
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/Lcd2004",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/Nextion",
|
||||
@@ -496,11 +554,11 @@
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/Oled64",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/Smi2_m",
|
||||
"active": true
|
||||
"active": false
|
||||
},
|
||||
{
|
||||
"path": "src/modules/display/TM16XX",
|
||||
|
||||
396
platformio.ini
396
platformio.ini
@@ -1,5 +1,5 @@
|
||||
[platformio]
|
||||
default_envs = esp8266_4mb
|
||||
default_envs = esp32_4mb3f
|
||||
data_dir = data_svelte
|
||||
|
||||
[common_env_data]
|
||||
@@ -15,7 +15,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_1mb_ota_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_1mb_ota="esp8266_1mb_ota"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_1mb_ota="esp8266_1mb_ota"
|
||||
framework = arduino
|
||||
board = nodemcuv2
|
||||
board_build.ldscript = eagle.flash.1m64.ld
|
||||
@@ -36,7 +38,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_1mb_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_1mb="esp8266_1mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_1mb="esp8266_1mb"
|
||||
framework = arduino
|
||||
board = nodemcuv2
|
||||
board_build.ldscript = eagle.flash.1m256.ld
|
||||
@@ -57,7 +61,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8285_1mb_ota_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_1mb_ota="esp8266_1mb_ota"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_1mb_ota="esp8266_1mb_ota"
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
board_build.ldscript = eagle.flash.1m64.ld
|
||||
@@ -78,7 +84,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_2mb_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_2mb="esp8266_2mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_2mb="esp8266_2mb"
|
||||
framework = arduino
|
||||
board = d1_wroom_02
|
||||
board_build.ldscript = eagle.flash.2m1m.ld
|
||||
@@ -99,7 +107,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_2mb_ota_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_2mb_ota="esp8266_2mb_ota"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_2mb_ota="esp8266_2mb_ota"
|
||||
framework = arduino
|
||||
board = d1_wroom_02
|
||||
board_build.ldscript = eagle.flash.2m256.ld
|
||||
@@ -120,7 +130,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8285_1mb_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_1mb="esp8266_1mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_1mb="esp8266_1mb"
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
board_build.ldscript = eagle.flash.1m256.ld
|
||||
@@ -141,7 +153,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_4mb_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_4mb="esp8266_4mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_4mb="esp8266_4mb"
|
||||
framework = arduino
|
||||
board = nodemcuv2
|
||||
board_build.ldscript = eagle.flash.4m1m.ld
|
||||
@@ -163,7 +177,9 @@ lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp8266_16mb_fromitems.lib_deps}
|
||||
ESPAsyncUDP
|
||||
build_flags = -Desp8266_16mb="esp8266_16mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp8266_16mb="esp8266_16mb"
|
||||
framework = arduino
|
||||
board = nodemcuv2
|
||||
platform = espressif8266 @4.0.1
|
||||
@@ -184,10 +200,13 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32_4mb_fromitems.lib_deps}
|
||||
build_flags = -Desp32_4mb="esp32_4mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32_4mb="esp32_4mb"
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
platform = espressif32 @5.1.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -205,10 +224,13 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32_4mb3f_fromitems.lib_deps}
|
||||
build_flags = -Desp32_4mb="esp32_4mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32_4mb3f="esp32_4mb3f"
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
platform = espressif32 @5.1.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -227,13 +249,15 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32cam_4mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32cam_4mb="esp32cam_4mb"
|
||||
-DBOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32cam
|
||||
platform = espressif32 @5.1.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -251,13 +275,15 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32s2_4mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32s2_4mb="esp32s2_4mb"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MODE=0
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = lolin_s2_mini
|
||||
platform = espressif32 @6.3.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -275,11 +301,13 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32c3m_4mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32c3m_4mb="esp32c3m_4mb"
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = lolin_c3_mini
|
||||
platform = espressif32 @6.3.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -298,12 +326,14 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32s3_16mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32s3_16mb="esp32s3_16mb"
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32-s3-devkitc-1
|
||||
board_build.mcu = esp32s3
|
||||
platform = espressif32 @6.3.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
@@ -323,10 +353,13 @@ extra_scripts = pre:tools/patch32_ws.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32_16mb_fromitems.lib_deps}
|
||||
build_flags = -Desp32_16mb="esp32_16mb"
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32_16mb="esp32_16mb"
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
platform = espressif32 @5.1.1
|
||||
platform = espressif32 @6.6.0
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_port = COM11
|
||||
upload_speed = 921600
|
||||
@@ -342,6 +375,102 @@ build_src_filter =
|
||||
+<modules/*.cpp>
|
||||
${env:esp32_16mb_fromitems.build_src_filter}
|
||||
|
||||
[env:esp32c6_4mb]
|
||||
extra_scripts = pre:tools/patch32c6.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32c6_4mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32c6_4mb="esp32c6_4mb"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||
-DARDUINO_USB_MODE=0
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32-c6-devkitm-1
|
||||
platform = espressif32 @6.9.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
debug_tool = esp-prog
|
||||
board_build.partitions = tools/partitions_custom.csv
|
||||
board_build.filesystem = littlefs
|
||||
build_src_filter =
|
||||
+<*.cpp>
|
||||
+<classes/*.cpp>
|
||||
+<utils/*.cpp>
|
||||
+<modules/*.cpp>
|
||||
${env:esp32c6_4mb_fromitems.build_src_filter}
|
||||
|
||||
[env:esp32c6_8mb]
|
||||
extra_scripts = pre:tools/patch32c6.py
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:esp32c6_8mb_fromitems.lib_deps}
|
||||
lib_ignore = LT_WebSockets
|
||||
build_flags =
|
||||
-Desp32c6_8mb="esp32c6_8mb"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||
-DARDUINO_USB_MODE=0
|
||||
-Wl,--wrap=esp_panic_handler
|
||||
framework = arduino
|
||||
board = esp32-c6-devkitm-1
|
||||
platform = espressif32 @6.9.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
debug_tool = esp-prog
|
||||
board_build.partitions = tools/partitions_custom_8mb.csv
|
||||
board_upload.flash_size = 8MB
|
||||
board_build.filesystem = littlefs
|
||||
build_src_filter =
|
||||
+<*.cpp>
|
||||
+<classes/*.cpp>
|
||||
+<utils/*.cpp>
|
||||
+<modules/*.cpp>
|
||||
${env:esp32c6_8mb_fromitems.build_src_filter}
|
||||
|
||||
[env:bk7231n]
|
||||
extra_scripts =
|
||||
pre:tools/lt_fsbuild.py
|
||||
pre:tools/lt_fsflash.py
|
||||
lib_compat_mode = off
|
||||
lib_deps =
|
||||
LT_WebSockets
|
||||
https://github.com/Mit4el/ESPAsyncUDP#master
|
||||
${common_env_data.lib_deps_external}
|
||||
${env:bk7231n_fromitems.lib_deps}
|
||||
lib_ignore = EspSoftwareSerial, HTTPUpdate, WebSockets
|
||||
platform = https://github.com/Mit4el/libretiny#master
|
||||
framework = arduino
|
||||
board = generic-bk7231n-qfn32-tuya
|
||||
custom_fw_name = iotm_tiny
|
||||
custom_fw_version = 0.0.1
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
build_flags =
|
||||
-Dbk7231n="bk7231n"
|
||||
-DLT_LOGLEVEL=LT_LEVEL_DEBUG
|
||||
-DLT_DEBUG_ALL=1
|
||||
-DPROJECT_DATA_DIR="data_svelte"
|
||||
-DLT_USE_TIME=1
|
||||
-DDEBUG_ESP_PORT=Serial1
|
||||
-DNODEBUG_WEBSOCKETS=1
|
||||
-DLT_UART_DEFAULT_PORT=1
|
||||
-DUPLOAD_PORT=auto
|
||||
build_src_filter =
|
||||
+<*.cpp>
|
||||
+<classes/*.cpp>
|
||||
+<utils/*.cpp>
|
||||
+<modules/*.cpp>
|
||||
${env:bk7231n_fromitems.build_src_filter}
|
||||
|
||||
[env:esp8266_1mb_ota_fromitems]
|
||||
lib_deps =
|
||||
adafruit/Adafruit BME280 Library
|
||||
@@ -544,62 +673,38 @@ lib_deps =
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
robtillaart/SHT2x@^0.1.1
|
||||
WEMOS SHT3x@1.0.0
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
adafruit/Adafruit MCP23017 Arduino Library@^2.1.0
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
dfrobot/DFRobotDFPlayerMini @ ^1.0.5
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
plerup/EspSoftwareSerial
|
||||
https://github.com/robotclass/RobotClass_LiquidCrystal_I2C
|
||||
marcoschwartz/LiquidCrystal_I2C@^1.1.4
|
||||
https://github.com/stblassitude/Adafruit_SSD1306_Wemos_OLED
|
||||
https://github.com/adafruit/Adafruit-GFX-Library
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/A02Distance>
|
||||
+<modules/sensors/Acs712>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/BL0937>
|
||||
+<modules/sensors/Bme280>
|
||||
+<modules/sensors/Bmp280>
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/MQgas>
|
||||
+<modules/sensors/Pzem004t_v2>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/S8>
|
||||
+<modules/sensors/Sht20>
|
||||
+<modules/sensors/Sht30>
|
||||
+<modules/sensors/Sonar>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/IoTServo>
|
||||
+<modules/exec/Mcp23017>
|
||||
+<modules/exec/Mp3>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/Pcf8574>
|
||||
+<modules/exec/Pwm8266>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/display/DwinI>
|
||||
+<modules/display/Lcd2004>
|
||||
+<modules/display/Oled64>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:esp32_4mb_fromitems]
|
||||
lib_deps =
|
||||
@@ -608,31 +713,20 @@ lib_deps =
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
robtillaart/SHT2x@^0.1.1
|
||||
WEMOS SHT3x@1.0.0
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
https://github.com/RoboticsBrno/ServoESP32#v1.0.3
|
||||
adafruit/Adafruit MCP23017 Arduino Library@^2.1.0
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
dfrobot/DFRobotDFPlayerMini @ ^1.0.5
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
https://github.com/robotclass/RobotClass_LiquidCrystal_I2C
|
||||
marcoschwartz/LiquidCrystal_I2C@^1.1.4
|
||||
https://github.com/stblassitude/Adafruit_SSD1306_Wemos_OLED
|
||||
https://github.com/adafruit/Adafruit-GFX-Library
|
||||
https://github.com/maxint-rd/TM16xx
|
||||
adafruit/Adafruit GFX Library @ ^1.11.5
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/Acs712>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/Bme280>
|
||||
@@ -640,29 +734,18 @@ build_src_filter =
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/Pzem004t>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/S8>
|
||||
+<modules/sensors/Sht20>
|
||||
+<modules/sensors/Sht30>
|
||||
+<modules/sensors/Sonar>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/IoTServo>
|
||||
+<modules/exec/Mcp23017>
|
||||
+<modules/exec/Mp3>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/MySensors>
|
||||
+<modules/exec/Pcf8574>
|
||||
+<modules/exec/Pwm32>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/display/Lcd2004>
|
||||
+<modules/display/Oled64>
|
||||
+<modules/display/Smi2_m>
|
||||
+<modules/display/TM16XX>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:esp32_4mb3f_fromitems]
|
||||
lib_deps =
|
||||
@@ -671,29 +754,20 @@ lib_deps =
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
https://github.com/tremaru/iarduino_RTC
|
||||
robtillaart/SHT2x@^0.1.1
|
||||
WEMOS SHT3x@1.0.0
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
https://github.com/RoboticsBrno/ServoESP32#v1.0.3
|
||||
adafruit/Adafruit MCP23017 Arduino Library@^2.1.0
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
dfrobot/DFRobotDFPlayerMini @ ^1.0.5
|
||||
adafruit/Adafruit BusIO @ ^1.13.2
|
||||
https://github.com/robotclass/RobotClass_LiquidCrystal_I2C
|
||||
marcoschwartz/LiquidCrystal_I2C@^1.1.4
|
||||
https://github.com/maxint-rd/TM16xx
|
||||
adafruit/Adafruit GFX Library @ ^1.11.5
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VariableColor>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/Acs712>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/Bme280>
|
||||
@@ -701,27 +775,18 @@ build_src_filter =
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/Pzem004t>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/S8>
|
||||
+<modules/sensors/Sht20>
|
||||
+<modules/sensors/Sht30>
|
||||
+<modules/sensors/Sonar>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/IoTServo>
|
||||
+<modules/exec/Mcp23017>
|
||||
+<modules/exec/Mp3>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/Pcf8574>
|
||||
+<modules/exec/Pwm32>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/display/Lcd2004>
|
||||
+<modules/display/Smi2_m>
|
||||
+<modules/display/TM16XX>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:esp32cam_4mb_fromitems]
|
||||
lib_deps =
|
||||
@@ -754,19 +819,44 @@ build_src_filter =
|
||||
|
||||
[env:esp8266_16mb_fromitems]
|
||||
lib_deps =
|
||||
https://github.com/dancol90/ESP8266Ping
|
||||
https://github.com/enjoyneering/AHTxx.git
|
||||
adafruit/Adafruit BME280 Library
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VariableColor>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/Bme280>
|
||||
+<modules/sensors/Bmp280>
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:esp32_16mb_fromitems]
|
||||
lib_deps =
|
||||
@@ -804,3 +894,103 @@ build_src_filter =
|
||||
+<modules/virtual/VariableColor>
|
||||
+<modules/virtual/VButton>
|
||||
|
||||
[env:esp32c6_4mb_fromitems]
|
||||
lib_deps =
|
||||
https://github.com/enjoyneering/AHTxx.git
|
||||
adafruit/Adafruit BME280 Library
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/Bme280>
|
||||
+<modules/sensors/Bmp280>
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/Pwm32>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:esp32c6_8mb_fromitems]
|
||||
lib_deps =
|
||||
https://github.com/enjoyneering/AHTxx.git
|
||||
adafruit/Adafruit BME280 Library
|
||||
adafruit/Adafruit BMP280 Library
|
||||
beegee-tokyo/DHT sensor library for ESPx
|
||||
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
||||
plerup/EspSoftwareSerial
|
||||
gyverlibs/EncButton @ ^2.0
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Ping>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/UpdateServer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/AhtXX>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/sensors/Bme280>
|
||||
+<modules/sensors/Bmp280>
|
||||
+<modules/sensors/Dht1122>
|
||||
+<modules/sensors/Ds18b20>
|
||||
+<modules/sensors/Impulse>
|
||||
+<modules/sensors/Ntc>
|
||||
+<modules/sensors/RTC>
|
||||
+<modules/sensors/UART>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/Buzzer>
|
||||
+<modules/exec/Enconder>
|
||||
+<modules/exec/Multitouch>
|
||||
+<modules/exec/Pwm32>
|
||||
+<modules/exec/TelegramLT>
|
||||
+<modules/exec/Thermostat>
|
||||
|
||||
[env:bk7231n_fromitems]
|
||||
lib_deps =
|
||||
build_src_filter =
|
||||
+<modules/virtual/Cron>
|
||||
+<modules/virtual/Loging>
|
||||
+<modules/virtual/LogingDaily>
|
||||
+<modules/virtual/LogingHourly>
|
||||
+<modules/virtual/Math>
|
||||
+<modules/virtual/owmWeather>
|
||||
+<modules/virtual/Timer>
|
||||
+<modules/virtual/Variable>
|
||||
+<modules/virtual/VButton>
|
||||
+<modules/sensors/AnalogAdc>
|
||||
+<modules/exec/AnalogBtn>
|
||||
+<modules/exec/ButtonIn>
|
||||
+<modules/exec/ButtonOut>
|
||||
+<modules/exec/TelegramLT>
|
||||
|
||||
|
||||
352
src/DebugTrace.cpp
Normal file
352
src/DebugTrace.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
#include "DebugTrace.h"
|
||||
#if defined(RESTART_DEBUG_INFO)
|
||||
// #ifdef RESTART_DEBUG_INFO
|
||||
__NOINIT_ATTR static re_restart_debug_t _debug_info;
|
||||
|
||||
#include "esp_debug_helpers.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "soc/cpu.h"
|
||||
|
||||
// RU: Размер буфера для конвертации даты и времeни в строку
|
||||
#define CONFIG_FORMAT_STRFTIME_BUFFER_SIZE 32
|
||||
#define CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE 20 // YYYY.MM.DD HH:NN:SS + \n
|
||||
|
||||
// RU: Форматы даты и времени
|
||||
#define CONFIG_FORMAT_DTS "%d.%m.%Y %H:%M:%S"
|
||||
|
||||
void IRAM_ATTR debugHeapUpdate()
|
||||
{
|
||||
_debug_info.heap_total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
|
||||
_debug_info.heap_free = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
|
||||
size_t _new_free_min = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
|
||||
if ((_debug_info.heap_free_min == 0) || (_new_free_min < _debug_info.heap_free_min))
|
||||
{
|
||||
_debug_info.heap_free_min = _new_free_min;
|
||||
_debug_info.heap_min_time = time(nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
void IRAM_ATTR debugBacktraceUpdate()
|
||||
{
|
||||
esp_backtrace_frame_t stk_frame;
|
||||
esp_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc));
|
||||
_debug_info.backtrace[0] = esp_cpu_process_stack_pc(stk_frame.pc);
|
||||
|
||||
bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) &&
|
||||
esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)))
|
||||
? false
|
||||
: true;
|
||||
|
||||
uint8_t i = CONFIG_RESTART_DEBUG_STACK_DEPTH;
|
||||
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted)
|
||||
{
|
||||
if (!esp_backtrace_get_next_frame(&stk_frame))
|
||||
{
|
||||
corrupted = true;
|
||||
};
|
||||
_debug_info.backtrace[CONFIG_RESTART_DEBUG_STACK_DEPTH - i] = esp_cpu_process_stack_pc(stk_frame.pc);
|
||||
};
|
||||
}
|
||||
|
||||
void IRAM_ATTR debugUpdate()
|
||||
{
|
||||
debugHeapUpdate();
|
||||
debugBacktraceUpdate();
|
||||
}
|
||||
|
||||
extern "C" void __wrap_esp_panic_handler(void *info)
|
||||
{
|
||||
|
||||
debugHeapUpdate();
|
||||
debugBacktraceUpdate();
|
||||
bootloop_panic_count += 1;
|
||||
// Call the original panic handler function to finish processing this error (creating a core dump for example...)
|
||||
__real_esp_panic_handler(info);
|
||||
}
|
||||
|
||||
re_restart_debug_t debugGet()
|
||||
{
|
||||
re_restart_debug_t ret;
|
||||
memset(&ret, 0, sizeof(re_restart_debug_t));
|
||||
esp_reset_reason_t esp_reason = esp_reset_reason();
|
||||
if ((esp_reason != ESP_RST_UNKNOWN) && (esp_reason != ESP_RST_POWERON))
|
||||
{
|
||||
uint8_t i = CONFIG_RESTART_DEBUG_STACK_DEPTH;
|
||||
ret = _debug_info;
|
||||
if (_debug_info.heap_total > heap_caps_get_total_size(MALLOC_CAP_DEFAULT))
|
||||
{
|
||||
memset(&ret, 0, sizeof(re_restart_debug_t));
|
||||
};
|
||||
};
|
||||
memset(&_debug_info, 0, sizeof(re_restart_debug_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CONFIG_MESSAGE_TG_VERSION_DEF "! Устройство запущено\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s"
|
||||
#define CONFIG_MESSAGE_TG_VERSION_HEAP "! Устройство аварийно перезапущено !\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s\nHEAP: %s"
|
||||
#define CONFIG_MESSAGE_TG_VERSION_TRACE "! Устройство аварийно перезапущено !\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s\nHEAP: %s\nTRACE: %s"
|
||||
|
||||
#define INFO_MESSAGE_DEBUG "By used -> USERPROFILE/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin xtensa-esp32-elf-addr2line.exe -pfiaC -e .pio/build/esp32_4mb3f/firmware.elf Стэк_адресов"
|
||||
|
||||
char *malloc_stringf(const char *format, ...)
|
||||
{
|
||||
char *ret = nullptr;
|
||||
if (format != nullptr)
|
||||
{
|
||||
// get the list of arguments
|
||||
va_list args1, args2;
|
||||
va_start(args1, format);
|
||||
va_copy(args2, args1);
|
||||
// calculate length of resulting string
|
||||
int len = vsnprintf(nullptr, 0, format, args1);
|
||||
va_end(args1);
|
||||
// allocate memory for string
|
||||
if (len > 0)
|
||||
{
|
||||
#if USE_ESP_MALLOC
|
||||
ret = (char *)esp_malloc(len + 1);
|
||||
#else
|
||||
ret = (char *)malloc(len + 1);
|
||||
#endif
|
||||
if (ret != nullptr)
|
||||
{
|
||||
memset(ret, 0, len + 1);
|
||||
vsnprintf(ret, len + 1, format, args2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// rlog_e(tagHEAP, "Failed to format string: out of memory!");
|
||||
};
|
||||
};
|
||||
va_end(args2);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *statesGetDebugHeap(re_restart_debug_t *debug)
|
||||
{
|
||||
if ((debug->heap_total > 0) && (debug->heap_total > debug->heap_free))
|
||||
{
|
||||
struct tm timeinfo;
|
||||
localtime_r(&debug->heap_min_time, &timeinfo);
|
||||
char time_buffer[CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE];
|
||||
memset(&time_buffer, 0, CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE);
|
||||
strftime(time_buffer, CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE, CONFIG_FORMAT_DTS, &timeinfo);
|
||||
|
||||
double heapTotal = (double)debug->heap_total / 1024;
|
||||
double heapFree = (double)debug->heap_free / 1024;
|
||||
double heapFreeMin = (double)debug->heap_free_min / 1024;
|
||||
|
||||
return malloc_stringf("Total %.1fkB ; Free %.1fkB (%.1f%%) ; FreeMin %.1fkB (%.1f%%) %s",
|
||||
heapTotal,
|
||||
heapFree, 100.0 * (heapFree / heapTotal),
|
||||
heapFreeMin, 100.0 * (heapFreeMin / heapTotal), time_buffer);
|
||||
};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *statesGetDebugTrace(re_restart_debug_t *debug)
|
||||
{
|
||||
char *backtrace = nullptr;
|
||||
char *item = nullptr;
|
||||
char *temp = nullptr;
|
||||
for (uint8_t i = 0; i < CONFIG_RESTART_DEBUG_STACK_DEPTH; i++)
|
||||
{
|
||||
if (debug->backtrace[i] != 0)
|
||||
{
|
||||
item = malloc_stringf("0x%08x", debug->backtrace[i]);
|
||||
if (item)
|
||||
{
|
||||
if (backtrace)
|
||||
{
|
||||
temp = backtrace;
|
||||
backtrace = malloc_stringf("%s %s", temp, item);
|
||||
free(item);
|
||||
free(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
backtrace = item;
|
||||
};
|
||||
item = nullptr;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
void printDebugTrace()
|
||||
{
|
||||
// esp_register_shutdown_handler(debugUpdate);
|
||||
re_restart_debug_t debug = debugGet();
|
||||
char *debug_heap = statesGetDebugHeap(&debug);
|
||||
char *debug_trace = nullptr;
|
||||
if (debug_heap)
|
||||
{
|
||||
debug_trace = statesGetDebugTrace(&debug);
|
||||
if (debug_trace)
|
||||
{
|
||||
Serial.printf(CONFIG_MESSAGE_TG_VERSION_TRACE,
|
||||
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
||||
debug_heap, debug_trace);
|
||||
// free(debug_trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
||||
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
||||
debug_heap);
|
||||
};
|
||||
// free(debug_heap);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial.println("DEVICE START");
|
||||
Serial.printf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
||||
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
||||
}
|
||||
|
||||
Serial.println(INFO_MESSAGE_DEBUG);
|
||||
}
|
||||
|
||||
void sendDebugTraceAndFreeMemory(bool postMsg)
|
||||
{
|
||||
// esp_register_shutdown_handler(debugUpdate);
|
||||
re_restart_debug_t debug = debugGet();
|
||||
char *debug_heap = statesGetDebugHeap(&debug);
|
||||
char *debug_trace = nullptr;
|
||||
|
||||
if (debug_heap)
|
||||
{
|
||||
if (isNetworkActive() && postMsg)
|
||||
{
|
||||
debug_trace = statesGetDebugTrace(&debug);
|
||||
if (debug_trace)
|
||||
{
|
||||
if (tlgrmItem)
|
||||
{
|
||||
char *msg;
|
||||
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_TRACE,
|
||||
jsonReadStr(settingsFlashJson, F("name")).c_str(), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
||||
debug_heap, debug_trace);
|
||||
tlgrmItem->sendTelegramMsg(false, String(msg));
|
||||
tlgrmItem->sendTelegramMsg(false, String("Подробности /helpDebug в Telegram_v2"));
|
||||
free(msg);
|
||||
}
|
||||
free(debug_trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Serial.printf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
||||
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
||||
debug_heap);
|
||||
*/
|
||||
if (tlgrmItem)
|
||||
{
|
||||
char *msg;
|
||||
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
||||
jsonReadStr(settingsFlashJson, F("name")).c_str(), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
||||
debug_heap);
|
||||
tlgrmItem->sendTelegramMsg(false, String(msg));
|
||||
tlgrmItem->sendTelegramMsg(false, String("Подробности /helpDebug в Telegram_v2"));
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(debug_heap);
|
||||
}
|
||||
/* else
|
||||
{
|
||||
// Serial.println("DEVICE START");
|
||||
// Serial.printf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
||||
// FIRMWARE_VERSION, ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
||||
if (tlgrmItem && isNetworkActive())
|
||||
{
|
||||
char *msg;
|
||||
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
||||
WiFi.localIP().toString(), FIRMWARE_VERSION, ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
||||
tlgrmItem->sendTelegramMsg(false, String(msg));
|
||||
free(msg);
|
||||
}
|
||||
};*/
|
||||
}
|
||||
#else // RESTART_DEBUG_INFO
|
||||
void printDebugTrace() {}
|
||||
void sendDebugTraceAndFreeMemory(bool) {}
|
||||
//void IRAM_ATTR debugUpdate() {}
|
||||
#if !defined(esp32c6_4mb) && !defined(esp32c6_8mb)
|
||||
extern "C" void __wrap_esp_panic_handler(void *info)
|
||||
{
|
||||
// Call the original panic handler function to finish processing this error (creating a core dump for example...)
|
||||
__real_esp_panic_handler(info);
|
||||
}
|
||||
#endif //esp32c6
|
||||
#endif // !RESTART_DEBUG_INFO
|
||||
|
||||
#if defined(ESP32)
|
||||
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
#include <esp_task_wdt.h>
|
||||
// 3 seconds WDT, reset in 1 seconds
|
||||
#define WDT_TIMEOUT 180
|
||||
|
||||
void startWatchDog()
|
||||
{
|
||||
#if !defined(esp32c6_4mb) && !defined(esp32c6_8mb) //TODO esp32-c6 переписать esp_task_wdt_init
|
||||
esp_task_wdt_init(WDT_TIMEOUT, true); // enable panic so ESP32 restarts
|
||||
esp_task_wdt_add(NULL); // add current thread to WDT watch
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" bool verifyRollbackLater()
|
||||
{
|
||||
ets_printf("[SYSTEM] - verifyRollbackLater OVERRIDDEN FUNCTION!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void verifyFirmware()
|
||||
{
|
||||
Serial.printf("[SYSTEM] - Checking firmware...\n");
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK)
|
||||
{
|
||||
const char *otaState = ota_state == ESP_OTA_IMG_NEW ? "ESP_OTA_IMG_NEW"
|
||||
: ota_state == ESP_OTA_IMG_PENDING_VERIFY ? "ESP_OTA_IMG_PENDING_VERIFY"
|
||||
: ota_state == ESP_OTA_IMG_VALID ? "ESP_OTA_IMG_VALID"
|
||||
: ota_state == ESP_OTA_IMG_INVALID ? "ESP_OTA_IMG_INVALID"
|
||||
: ota_state == ESP_OTA_IMG_ABORTED ? "ESP_OTA_IMG_ABORTED"
|
||||
: "ESP_OTA_IMG_UNDEFINED";
|
||||
Serial.printf("[SYSTEM] - Ota state: %s\n", otaState);
|
||||
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
|
||||
{
|
||||
if (esp_ota_mark_app_valid_cancel_rollback() == ESP_OK)
|
||||
{
|
||||
Serial.printf("[SYSTEM] - App is valid, rollback cancelled successfully\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[SYSTEM] - Failed to cancel rollback\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[SYSTEM] - OTA partition has no record in OTA data\n");
|
||||
}
|
||||
}
|
||||
#else //ESP32
|
||||
void startWatchDog() {}
|
||||
//extern "C" bool verifyRollbackLater() {}
|
||||
void verifyFirmware() {}
|
||||
#endif
|
||||
@@ -37,7 +37,11 @@ void addThisDeviceToList() {
|
||||
AsyncUDP asyncUdp;
|
||||
|
||||
void udpListningInit() {
|
||||
if (asyncUdp.listenMulticast(IPAddress(239, 255, 255, 255), 4210)) {
|
||||
#if defined(LIBRETINY)
|
||||
if (asyncUdp.listenMulticast(IPAddress(239, 255, 255, 255), 4210 , WiFi.localIP() )) {
|
||||
#else
|
||||
if (asyncUdp.listenMulticast(IPAddress(239, 255, 255, 255), 4210)) {
|
||||
#endif
|
||||
asyncUdp.onPacket([](AsyncUDPPacket packet) {
|
||||
// если был включен автоматический поиск устройств то начнем запись в оперативную память
|
||||
if (jsonReadInt(settingsFlashJson, F("udps")) != 0) {
|
||||
@@ -65,8 +69,12 @@ void udpListningInit() {
|
||||
String loacalWorkgroup = "";
|
||||
jsonRead(settingsFlashJson, F("wg"), loacalWorkgroup);
|
||||
if (remoteWorkgroup == loacalWorkgroup) {
|
||||
#if defined(LIBRETINY)
|
||||
SerialPrint("i", F("UDP"), "IP: " + ipToString(packet.remoteIP()) + ":" + String(packet.remotePort()) + " localIP:"+String(packet.localIP()));
|
||||
#else
|
||||
SerialPrint("i", F("UDP"), "IP: " + packet.remoteIP().toString() + ":" + String(packet.remotePort()));
|
||||
jsonMergeArrays(devListHeapJson, data);
|
||||
#endif
|
||||
jsonMergeArrays(devListHeapJson, data);
|
||||
// эксперементальный вариант отправки нового списка сразу по приходу
|
||||
// sendStringToWs("devlis", devListHeapJson, -1);
|
||||
}
|
||||
@@ -91,7 +99,7 @@ void udpListningInit() {
|
||||
void udpBroadcastInit() {
|
||||
// будем отправлять каждые 60 секунд презентацию данного устройства
|
||||
ts.add(
|
||||
UDP, 60000, [&](void*) { // UDPP
|
||||
UDPt, 60000, [&](void*) { // UDPP
|
||||
if (isNetworkActive()) {
|
||||
SerialPrint("i", F("UDP"), F("Broadcast device presentation"));
|
||||
asyncUdp.broadcastTo(getThisDevice().c_str(), 4210);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ESPConfiguration.h"
|
||||
#include "classes/IoTGpio.h"
|
||||
//#include "classes/IoTDiscovery.h"
|
||||
|
||||
extern IoTGpio IoTgpio;
|
||||
|
||||
@@ -8,6 +9,10 @@ void* getAPI(String subtype, String params);
|
||||
|
||||
void configure(String path) {
|
||||
File file = seekFile(path);
|
||||
if (!file) {
|
||||
SerialPrint(F("E"), F("FS"), F("configure file open error"));
|
||||
return;
|
||||
}
|
||||
file.find("[");
|
||||
while (file.available()) {
|
||||
String jsonArrayElement = file.readStringUntil('}') + "}";
|
||||
@@ -18,6 +23,7 @@ void configure(String path) {
|
||||
jsonArrayElement = "";
|
||||
}
|
||||
if (jsonArrayElement != "") {
|
||||
IoTItem* myIoTItem;
|
||||
String subtype;
|
||||
if (!jsonRead(jsonArrayElement, F("subtype"), subtype)) { //если нет такого ключа в представленном json или он не валидный
|
||||
SerialPrint(F("E"), F("Config"), "json error " + subtype);
|
||||
@@ -36,6 +42,9 @@ void configure(String path) {
|
||||
// пробуем спросить драйвер Benchmark
|
||||
if (driver = myIoTItem->getBenchmarkTask()) benchTaskItem = ((IoTBench*)driver);
|
||||
if (driver = myIoTItem->getBenchmarkLoad()) benchLoadItem = ((IoTBench*)driver);
|
||||
// пробуем спросить драйвер для интеграций
|
||||
if (driver = myIoTItem->getHOMEdDiscovery()) HOMEdDiscovery = ((IoTDiscovery*)driver);
|
||||
if (driver = myIoTItem->getHADiscovery()) HADiscovery = ((IoTDiscovery*)driver);
|
||||
// пробуем спросить драйвер Telegram_v2
|
||||
if (driver = myIoTItem->getTlgrmDriver()) tlgrmItem = (IoTItem*)driver;
|
||||
IoTItems.push_back(myIoTItem);
|
||||
@@ -45,6 +54,26 @@ void configure(String path) {
|
||||
}
|
||||
file.close();
|
||||
SerialPrint("i", "Config", "Configured");
|
||||
/*
|
||||
#ifdef ESP32
|
||||
if(HOMEdDiscovery)
|
||||
HOMEdDiscovery->mqttSubscribeDiscovery();
|
||||
if(HADiscovery)
|
||||
HADiscovery->mqttSubscribeDiscovery();
|
||||
// оттправляем все статусы
|
||||
if(HOMEdDiscovery || HADiscovery)
|
||||
{
|
||||
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it)
|
||||
{
|
||||
if ((*it)->iAmLocal)
|
||||
{
|
||||
publishStatusMqtt((*it)->getID(), (*it)->getValue());
|
||||
(*it)->onMqttWsAppConnectEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
void clearConfigure() {
|
||||
@@ -59,8 +88,13 @@ void clearConfigure() {
|
||||
if (*it) delete *it;
|
||||
}
|
||||
IoTItems.clear();
|
||||
|
||||
#ifdef LIBRETINY
|
||||
valuesFlashJson.remove(0, valuesFlashJson.length());
|
||||
#else
|
||||
valuesFlashJson.clear();
|
||||
#endif
|
||||
benchTaskItem = nullptr;
|
||||
benchLoadItem = nullptr;
|
||||
HOMEdDiscovery = nullptr;
|
||||
HADiscovery = nullptr;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "EspFileSystem.h"
|
||||
#include "Global.h"
|
||||
#if defined(esp32c6_4mb) || defined(esp32c6_8mb)
|
||||
#include "esp_mac.h"
|
||||
#endif
|
||||
|
||||
bool fileSystemInit()
|
||||
{
|
||||
@@ -18,14 +21,17 @@ void globalVarsSync()
|
||||
|
||||
valuesFlashJson = readFile(F("values.json"), 4096);
|
||||
valuesFlashJson.replace("\r\n", "");
|
||||
|
||||
if (settingsFlashJson == "failed")
|
||||
return;
|
||||
mqttPrefix = jsonReadStr(settingsFlashJson, F("mqttPrefix"));
|
||||
jsonWriteStr_(settingsFlashJson, "id", chipId);
|
||||
|
||||
mqttRootDevice = mqttPrefix + "/" + chipId;
|
||||
|
||||
#ifdef LIBRETINY
|
||||
jsonWriteStr_(settingsFlashJson, "ip", ipToString(WiFi.localIP()));
|
||||
#else
|
||||
jsonWriteStr_(settingsFlashJson, "ip", WiFi.localIP().toString());
|
||||
|
||||
#endif
|
||||
// это не используется - удалить в последствии
|
||||
jsonWriteStr_(settingsFlashJson, "root", mqttRootDevice);
|
||||
}
|
||||
@@ -35,6 +41,25 @@ void syncSettingsFlashJson()
|
||||
writeFile(F("settings.json"), settingsFlashJson);
|
||||
}
|
||||
|
||||
void resetSettingsFlashByPanic()
|
||||
{
|
||||
FileFS.rename("/config.json", "/config_bak.json");
|
||||
/*
|
||||
update.configJson = readFile("config.json", 4096 * 4);
|
||||
update.layoutJson = readFile("layout.json", 4096 * 4);
|
||||
update.scenarioTxt = readFile("scenario.txt", 4096 * 4);
|
||||
writeFile(F("/config_bak.json"), update.configJson);
|
||||
writeFile(F("/scenario_bak.txt"), update.scenarioTxt);
|
||||
writeFile(F("/layout_bak.json"), update.layoutJson);
|
||||
*/
|
||||
//update.configJson = "[]";
|
||||
//update.scenarioTxt = "";
|
||||
//update.layoutJson = "[]";
|
||||
writeFile(F("/config.json"), "[]");
|
||||
writeFile(F("/scenario.txt"), "");
|
||||
writeFile(F("/layout.json"), "[]");
|
||||
}
|
||||
|
||||
void syncValuesFlashJson()
|
||||
{
|
||||
writeFile(F("values.json"), valuesFlashJson);
|
||||
@@ -79,7 +104,7 @@ uint32_t ESP_getChipId(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// устарела используем новую функцию ниже
|
||||
/*// устарела используем новую функцию ниже
|
||||
#if !defined(esp32s2_4mb) && !defined(esp32c3m_4mb) && !defined(esp32s3_16mb)
|
||||
//#ifndef esp32s2_4mb
|
||||
uint32_t ESP_getFlashChipId(void)
|
||||
@@ -93,6 +118,7 @@ uint32_t ESP_getFlashChipId(void)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
// https://github.com/espressif/arduino-esp32/issues/6945#issuecomment-1199900892
|
||||
// получение flash ch id из проекта esp easy
|
||||
@@ -113,7 +139,7 @@ uint32_t getFlashChipIdNew()
|
||||
}
|
||||
|
||||
// esp_flash_read_id(nullptr, &flashChipId);
|
||||
#elif defined(ESP8266)
|
||||
#elif defined(ESP8266) || defined(LIBRETINY)
|
||||
flashChipId = ESP.getFlashChipId();
|
||||
#endif // ifdef ESP32
|
||||
}
|
||||
@@ -127,9 +153,12 @@ const String getMacAddress()
|
||||
#if defined(ESP8266)
|
||||
WiFi.macAddress(mac);
|
||||
sprintf(buf, MACSTR, MAC2STR(mac));
|
||||
#else
|
||||
#elif defined(ESP32)
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
sprintf(buf, MACSTR, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
#elif defined(LIBRETINY)
|
||||
uint32_t macid = lt_cpu_get_mac_id ();
|
||||
memcpy(buf, &macid, sizeof(macid));
|
||||
#endif
|
||||
return String(buf);
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
*****************************************глобальные объекты классов***************************************************
|
||||
**********************************************************************************************************************/
|
||||
|
||||
TickerScheduler ts(END + 1);
|
||||
// TickerScheduler ts(END + 1); // зачем на 1 больше?
|
||||
TickerScheduler ts(END);
|
||||
WiFiClient espClient;
|
||||
PubSubClient mqtt(espClient);
|
||||
|
||||
@@ -20,6 +21,9 @@ ESP8266WebServer HTTP(80);
|
||||
#ifdef ESP32
|
||||
WebServer HTTP(80);
|
||||
#endif
|
||||
#ifdef LIBRETINY
|
||||
WebServer HTTP(80);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD_WEB_SOCKETS
|
||||
@@ -35,6 +39,8 @@ IoTItem* rtcItem = nullptr;
|
||||
IoTItem* tlgrmItem = nullptr;
|
||||
IoTBench* benchTaskItem = nullptr;
|
||||
IoTBench* benchLoadItem = nullptr;
|
||||
IoTDiscovery* HOMEdDiscovery = nullptr;
|
||||
IoTDiscovery* HADiscovery = nullptr;
|
||||
String settingsFlashJson = "{}"; // переменная в которой хранятся все настройки, находится в оперативной памяти и синхронизированна с flash памятью
|
||||
String valuesFlashJson = "{}"; // переменная в которой хранятся все значения элементов, которые необходимо сохранить на flash. Находится в оперативной памяти и синхронизированна с flash памятью
|
||||
String errorsHeapJson = "{}"; // переменная в которой хранятся все ошибки, находится в оперативной памяти только
|
||||
@@ -57,6 +63,7 @@ int mqttPort = 0;
|
||||
String mqttPrefix = "";
|
||||
String mqttUser = "";
|
||||
String mqttPass = "";
|
||||
String nameId = "";
|
||||
|
||||
unsigned long mqttUptime = 0;
|
||||
unsigned long flashWriteNumber = 0;
|
||||
@@ -78,7 +85,7 @@ String prevDate = "";
|
||||
bool firstTimeInit = true;
|
||||
|
||||
// unsigned long loopPeriod;
|
||||
|
||||
int8_t ws_clients[WEBSOCKETS_CLIENT_MAX];
|
||||
bool isTimeSynch = false;
|
||||
Time_t _time_local;
|
||||
Time_t _time_utc;
|
||||
|
||||
115
src/Main.cpp
115
src/Main.cpp
@@ -3,7 +3,13 @@
|
||||
#include "classes/IoTDB.h"
|
||||
#include "utils/Statistic.h"
|
||||
#include "classes/IoTBench.h"
|
||||
#ifndef LIBRETINY
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
#include "DebugTrace.h"
|
||||
#if defined(ESP32)
|
||||
#include <esp_task_wdt.h>
|
||||
#endif
|
||||
#if defined(esp32s2_4mb) || defined(esp32s3_16mb)
|
||||
#include <USB.h>
|
||||
#endif
|
||||
@@ -46,7 +52,7 @@ void elementsLoop() {
|
||||
#define COUNTER_ERRORMARKER 4 // количество шагов счетчика
|
||||
#define STEPPER_ERRORMARKER 100000 // размер шага счетчика интервала доверия выполнения блока кода мкс
|
||||
|
||||
#if defined(esp32_4mb) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
|
||||
static int IRAM_ATTR initErrorMarkerId = 0; // ИД маркера
|
||||
static int IRAM_ATTR errorMarkerId = 0;
|
||||
@@ -65,14 +71,14 @@ void IRAM_ATTR onTimer() {
|
||||
#endif
|
||||
|
||||
void initErrorMarker(int id) {
|
||||
#if defined(esp32_4mb) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
initErrorMarkerId = id;
|
||||
errorMarkerCounter = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void stopErrorMarker(int id) {
|
||||
#if defined(esp32_4mb) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
errorMarkerCounter = -1;
|
||||
if (errorMarkerId)
|
||||
SerialPrint("I", "WARNING!", "A lazy (freezing loop more than " + (String)(COUNTER_ERRORMARKER * STEPPER_ERRORMARKER / 1000) + " ms) section has been found! With ID=" + (String)errorMarkerId);
|
||||
@@ -85,7 +91,7 @@ void setup() {
|
||||
#if defined(esp32s2_4mb) || defined(esp32s3_16mb)
|
||||
USB.begin();
|
||||
#endif
|
||||
#if defined(esp32_4mb) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
My_timer = timerBegin(0, 80, true);
|
||||
timerAttachInterrupt(My_timer, &onTimer, true);
|
||||
timerAlarmWrite(My_timer, STEPPER_ERRORMARKER, true);
|
||||
@@ -97,6 +103,14 @@ void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.flush();
|
||||
//----------- Отладка EXCEPTION (функции с заглушками для отключения) ---------
|
||||
#if defined(RESTART_DEBUG_INFO)
|
||||
//Привязка коллбэк функции для вызова при перезагрузке
|
||||
esp_register_shutdown_handler(debugUpdate);
|
||||
#endif // RESTART_DEBUG_INFO
|
||||
// Печать или оправка отладочной информации
|
||||
printDebugTrace();
|
||||
startWatchDog();
|
||||
Serial.println();
|
||||
Serial.println(F("--------------started----------------"));
|
||||
|
||||
@@ -117,6 +131,8 @@ void setup() {
|
||||
// получение chip id
|
||||
setChipId();
|
||||
|
||||
verifyFirmware();
|
||||
|
||||
// синхронизация глобальных переменных с flash
|
||||
globalVarsSync();
|
||||
|
||||
@@ -134,13 +150,38 @@ void setup() {
|
||||
#ifdef ESP32
|
||||
Wire.end();
|
||||
Wire.begin(pinSDA, pinSCL, (uint32_t)i2cFreq);
|
||||
#else
|
||||
#elif defined(ESP8266)
|
||||
Wire.begin(pinSDA, pinSCL);
|
||||
Wire.setClock(i2cFreq);
|
||||
#endif
|
||||
SerialPrint("i", "i2c", F("i2c pins overriding done"));
|
||||
}
|
||||
|
||||
#if defined(RESTART_DEBUG_INFO)
|
||||
esp_reset_reason_t esp_reason = esp_reset_reason();
|
||||
if (esp_reason == ESP_RST_UNKNOWN || esp_reason == ESP_RST_POWERON)
|
||||
bootloop_panic_count = 0;
|
||||
/* else if (bootloop_panic_count == 3 || bootloop_panic_count == 0 ) bootloop_panic_count = 1;
|
||||
else if (bootloop_panic_count == 2) bootloop_panic_count = 3;
|
||||
else if (bootloop_panic_count == 1) bootloop_panic_count = 2;
|
||||
else bootloop_panic_count = 0; */
|
||||
Serial.println("bootloop_panic_count " + String(bootloop_panic_count));
|
||||
if (bootloop_panic_count >3 )
|
||||
{
|
||||
//resetSettingsFlashByPanic();
|
||||
bootloop_panic_count = 0;
|
||||
}
|
||||
if (bootloop_panic_count >= 3)
|
||||
{
|
||||
resetSettingsFlashByPanic();
|
||||
bootloop_panic_count = -1;
|
||||
}
|
||||
if (bootloop_panic_count == -1)
|
||||
{
|
||||
SerialPrint("E", "CORE", F("CONFIG and SCENARIO reset !!!"));
|
||||
bootloop_panic_count = 0;
|
||||
ESP.restart();
|
||||
}
|
||||
#endif // RESTART_DEBUG_INFO
|
||||
// настраиваем микроконтроллер
|
||||
configure("/config.json");
|
||||
|
||||
@@ -159,8 +200,11 @@ void setup() {
|
||||
initErrorMarker(SETUPINET_ERRORMARKER);
|
||||
|
||||
// подключаемся к роутеру
|
||||
#ifdef ESP8266
|
||||
routerConnect();
|
||||
|
||||
#else
|
||||
WiFiUtilsItit();
|
||||
#endif
|
||||
// инициализация асинхронного веб сервера и веб сокетов
|
||||
#ifdef ASYNC_WEB_SERVER
|
||||
asyncWebServerInit();
|
||||
@@ -179,6 +223,10 @@ void setup() {
|
||||
|
||||
stopErrorMarker(SETUPINET_ERRORMARKER);
|
||||
|
||||
bool postMsgTelegram;
|
||||
if (!jsonRead(settingsFlashJson, "debugTraceMsgTlgrm", postMsgTelegram, false)) postMsgTelegram = 1;
|
||||
sendDebugTraceAndFreeMemory(postMsgTelegram);
|
||||
|
||||
initErrorMarker(SETUPLAST_ERRORMARKER);
|
||||
|
||||
elementsLoop();
|
||||
@@ -188,11 +236,15 @@ void setup() {
|
||||
// инициализация задач переодического выполнения
|
||||
periodicTasksInit();
|
||||
|
||||
#if defined(ESP8266)
|
||||
// Перенесли после получения IP, так как теперь работа WiFi асинхронная
|
||||
// запуск работы udp
|
||||
addThisDeviceToList();
|
||||
#ifdef UDP_ENABLED
|
||||
udpListningInit();
|
||||
udpBroadcastInit();
|
||||
|
||||
#endif
|
||||
#endif
|
||||
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
|
||||
createItemFromNet("onStart", "1", 1);
|
||||
|
||||
@@ -201,6 +253,13 @@ void setup() {
|
||||
// настраиваем секундные обслуживания системы
|
||||
ts.add(
|
||||
TIMES, 1000, [&](void *) {
|
||||
// сброс WDT
|
||||
#if defined(ESP32)
|
||||
//SerialPrint("i", "Task", "reset wdt");
|
||||
#if !defined(esp32c6_4mb) && !defined(esp32c6_8mb) //TODO esp32-c6 переписать esp_task_wdt_init
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
#endif
|
||||
// сохраняем значения IoTItems в файл каждую секунду, если были изменения (установлены маркеры на сохранение)
|
||||
if (needSaveValues) {
|
||||
syncValuesFlashJson();
|
||||
@@ -216,14 +275,50 @@ void setup() {
|
||||
},
|
||||
nullptr, true);
|
||||
|
||||
// ловим пинги от WS (5сек) и дисконнектим если их нет (20сек)
|
||||
ts.add(
|
||||
PiWS, 6000, [&](void*) {
|
||||
if (isNetworkActive()) {
|
||||
for (size_t i = 0; i < WEBSOCKETS_CLIENT_MAX; i++)
|
||||
{
|
||||
if (ws_clients[i] == 0) {
|
||||
disconnectWSClient(i);
|
||||
ws_clients[i]=-1;
|
||||
}
|
||||
if (ws_clients[i] > 0) {
|
||||
ws_clients[i]=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
nullptr, true);
|
||||
|
||||
// test
|
||||
Serial.println("-------test start--------");
|
||||
Serial.println("--------test end---------");
|
||||
//Serial.println("-------test start--------");
|
||||
//Serial.println("--------test end---------");
|
||||
|
||||
stopErrorMarker(SETUPLAST_ERRORMARKER);
|
||||
#if defined(RESTART_DEBUG_INFO)
|
||||
bootloop_panic_count = 0;
|
||||
#endif // RESTART_DEBUG_INFO
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#if !defined(ESP8266)
|
||||
static bool udpFirstFlag = true;
|
||||
// Перенесли после получения IP, так как теперь работа WiFi асинхронная
|
||||
if (isNetworkActive() && udpFirstFlag) {
|
||||
udpFirstFlag = false;
|
||||
// запуск работы udp
|
||||
addThisDeviceToList();
|
||||
#ifdef UDP_ENABLED
|
||||
udpListningInit();
|
||||
udpBroadcastInit();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LOOP_DEBUG
|
||||
unsigned long st = millis();
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "MqttClient.h"
|
||||
#include "classes/IoTDiscovery.h"
|
||||
|
||||
void mqttInit() {
|
||||
mqtt.setCallback(mqttCallback);
|
||||
@@ -59,10 +60,24 @@ boolean mqttConnect() {
|
||||
if (!mqtt.connected()) {
|
||||
bool connected = false;
|
||||
if (mqttUser != "" && mqttPass != "") {
|
||||
connected = mqtt.connect(chipId.c_str(), mqttUser.c_str(), mqttPass.c_str());
|
||||
if (HOMEdDiscovery)
|
||||
{
|
||||
connected = mqtt.connect(chipId.c_str(), mqttUser.c_str(), mqttPass.c_str(), (HOMEdDiscovery->HOMEdTopic + "/device/custom/" + nameId).c_str(), 1, true, "{\"status\":\"offline\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
connected = mqtt.connect(chipId.c_str(), mqttUser.c_str(), mqttPass.c_str(), (mqttRootDevice + "/state").c_str(), 1, true, "{\"status\":\"offline\"}");
|
||||
}
|
||||
SerialPrint("i", F("MQTT"), F("Go to connection with login and password"));
|
||||
} else if (mqttUser == "" && mqttPass == "") {
|
||||
connected = mqtt.connect(chipId.c_str());
|
||||
if (HOMEdDiscovery)
|
||||
{
|
||||
connected = mqtt.connect(chipId.c_str(), (HOMEdDiscovery->HOMEdTopic + "/device/custom/" + nameId).c_str(), 1, true, "{\"status\":\"offline\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
connected = mqtt.connect(chipId.c_str(), (mqttRootDevice + "/state").c_str(), 1, true, "{\"status\":\"offline\"}");
|
||||
}
|
||||
SerialPrint("i", F("MQTT"), F("Go to connection without login and password"));
|
||||
} else {
|
||||
SerialPrint("E", F("MQTT"), F("✖ Login or password missed"));
|
||||
@@ -105,6 +120,9 @@ void getMqttData() {
|
||||
mqttUser = jsonReadStr(settingsFlashJson, F("mqttUser"));
|
||||
mqttPass = jsonReadStr(settingsFlashJson, F("mqttPass"));
|
||||
mqttPrefix = jsonReadStr(settingsFlashJson, F("mqttPrefix"));
|
||||
if (jsonReadInt(settingsFlashJson, F("HOMEd_names"))){
|
||||
nameId = jsonReadStr(settingsFlashJson, F("name"));}
|
||||
else{nameId = getChipId();}
|
||||
mqttRootDevice = mqttPrefix + "/" + chipId;
|
||||
}
|
||||
|
||||
@@ -129,17 +147,33 @@ void mqttSubscribe() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(HOMEdDiscovery)
|
||||
HOMEdDiscovery->mqttSubscribeDiscovery();
|
||||
if(HADiscovery)
|
||||
HADiscovery->mqttSubscribeDiscovery();
|
||||
// оттправляем все статусы
|
||||
if(HOMEdDiscovery || HADiscovery)
|
||||
{
|
||||
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it)
|
||||
{
|
||||
if ((*it)->iAmLocal)
|
||||
{
|
||||
publishStatusMqtt((*it)->getID(), (*it)->getValue());
|
||||
(*it)->onMqttWsAppConnectEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mqttSubscribeExternal(String topic, bool usePrefix) {
|
||||
|
||||
// SerialPrint("i", F("MQTT"), mqttRootDevice);
|
||||
String _sb_topic = topic;
|
||||
if (usePrefix)
|
||||
{
|
||||
_sb_topic = mqttPrefix + "/" + topic;
|
||||
}
|
||||
mqtt.subscribe(_sb_topic.c_str());
|
||||
// SerialPrint("i", F("MQTT"), mqttRootDevice);
|
||||
String _sb_topic = topic;
|
||||
if (usePrefix)
|
||||
{
|
||||
_sb_topic = mqttPrefix + "/" + topic;
|
||||
}
|
||||
mqtt.subscribe(_sb_topic.c_str());
|
||||
|
||||
SerialPrint("i", F("MQTT"), ("subscribed external " + _sb_topic).c_str());
|
||||
}
|
||||
@@ -253,6 +287,10 @@ boolean publishChartMqtt(const String& topic, const String& data) {
|
||||
}
|
||||
|
||||
boolean publishStatusMqtt(const String& topic, const String& data) {
|
||||
if (HOMEdDiscovery)
|
||||
{
|
||||
HOMEdDiscovery->publishStatusHOMEd(topic, data);
|
||||
}
|
||||
String path = mqttRootDevice + "/" + topic + "/status";
|
||||
String json = "{}";
|
||||
jsonWriteStr(json, "status", data);
|
||||
@@ -305,14 +343,17 @@ bool publishChartFileToMqtt(String path, String id, int maxCount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void handleMqttStatus(bool send) {
|
||||
String stateStr = getStateStr(mqtt.state());
|
||||
// Serial.println(stateStr);
|
||||
jsonWriteStr_(errorsHeapJson, F("mqtt"), stateStr);
|
||||
if (!send) sendStringToWs("errors", errorsHeapJson, -1);
|
||||
}
|
||||
// void handleMqttStatus(bool send) {
|
||||
// String stateStr = getStateStr(mqtt.state());
|
||||
// // Serial.println(stateStr);
|
||||
// jsonWriteStr_(errorsHeapJson, F("mqtt"), stateStr);
|
||||
// if (!send) sendStringToWs("errors", errorsHeapJson, -1);
|
||||
// }
|
||||
|
||||
void handleMqttStatus(bool send, int state) {
|
||||
if (state == -1) {
|
||||
state = mqtt.state();
|
||||
}
|
||||
String stateStr = getStateStr(state);
|
||||
// Serial.println(stateStr);
|
||||
jsonWriteStr_(errorsHeapJson, F("mqtt"), stateStr);
|
||||
@@ -322,47 +363,47 @@ void handleMqttStatus(bool send, int state) {
|
||||
const String getStateStr(int e) {
|
||||
switch (e) {
|
||||
case -4: // Нет ответа от сервера
|
||||
return F("e1");
|
||||
break;
|
||||
return F("e1");
|
||||
break;
|
||||
case -3: // Соединение было разорвано
|
||||
return F("e2");
|
||||
break;
|
||||
return F("e2");
|
||||
break;
|
||||
case -2: // Ошибка соединения. Обычно возникает когда неверно указано название сервера MQTT
|
||||
return F("e3");
|
||||
break;
|
||||
return F("e3");
|
||||
break;
|
||||
case -1: // Клиент был отключен
|
||||
return F("e4");
|
||||
break;
|
||||
return F("e4");
|
||||
break;
|
||||
case 0: // подключено
|
||||
return F("e5");
|
||||
break;
|
||||
return F("e5");
|
||||
break;
|
||||
case 1: // Ошибка версии
|
||||
return F("e6");
|
||||
break;
|
||||
return F("e6");
|
||||
break;
|
||||
case 2: // Отклонен идентификатор
|
||||
return F("e7");
|
||||
break;
|
||||
return F("e7");
|
||||
break;
|
||||
case 3: // Не могу установить соединение
|
||||
return F("e8");
|
||||
break;
|
||||
return F("e8");
|
||||
break;
|
||||
case 4: // Неправильное имя пользователя/пароль
|
||||
return F("e9");
|
||||
break;
|
||||
return F("e9");
|
||||
break;
|
||||
case 5: // Не авторизован для подключения
|
||||
return F("e10");
|
||||
break;
|
||||
return F("e10");
|
||||
break;
|
||||
case 6: // Название сервера пустое
|
||||
return F("e11");
|
||||
break;
|
||||
return F("e11");
|
||||
break;
|
||||
case 7: // Имя пользователя или пароль пустые
|
||||
return F("e12");
|
||||
break;
|
||||
return F("e12");
|
||||
break;
|
||||
case 8: // Подключение в процессе
|
||||
return F("e13");
|
||||
break;
|
||||
default:
|
||||
return F("unk");
|
||||
break;
|
||||
return F("e13");
|
||||
break;
|
||||
default:
|
||||
return F("unk");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
src/NTP.cpp
24
src/NTP.cpp
@@ -1,14 +1,29 @@
|
||||
#include "NTP.h"
|
||||
|
||||
#if defined(LIBRETINY)
|
||||
#include "lwip/apps/sntp.h"
|
||||
#endif
|
||||
|
||||
#include "Global.h"
|
||||
#include "utils/SerialPrint.h"
|
||||
|
||||
void ntpInit() {
|
||||
#if defined(LIBRETINY)
|
||||
if (sntp_enabled()) {
|
||||
sntp_stop();
|
||||
}
|
||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||
sntp_setservername(0, jsonReadStr(settingsFlashJson, F("ntp")).c_str());
|
||||
sntp_setservername(1, "pool.ntp.org");
|
||||
sntp_setservername(2, "ru.pool.ntp.org");
|
||||
sntp_init();
|
||||
#endif
|
||||
synchTime();
|
||||
|
||||
ts.add(
|
||||
TIME, 1000, [&](void*) {
|
||||
unixTime = getSystemTime();
|
||||
//SerialPrint("I", F("NTP"), "TIME " + String(unixTime));
|
||||
if (unixTime < MIN_DATETIME) {
|
||||
isTimeSynch = false;
|
||||
// SerialPrint("E", "NTP", "Time not synched");
|
||||
@@ -44,7 +59,16 @@ void ntpInit() {
|
||||
}
|
||||
|
||||
void synchTime() {
|
||||
#if defined LIBRETINY
|
||||
// force resync
|
||||
if (sntp_enabled()) {
|
||||
sntp_stop();
|
||||
}
|
||||
sntp_init();
|
||||
|
||||
#else
|
||||
configTime(0, 0, "pool.ntp.org", "ru.pool.ntp.org", jsonReadStr(settingsFlashJson, F("ntp")).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
//событие смены даты
|
||||
|
||||
@@ -59,9 +59,29 @@ String ESP_getResetReason(void) {
|
||||
return ESP.getResetReason();
|
||||
}
|
||||
#endif
|
||||
#if defined(esp32s2_4mb) || defined(esp32s3_16mb) || defined(esp32c3m_4mb)
|
||||
#ifdef LIBRETINY
|
||||
String ESP_getResetReason(void) {
|
||||
return ESP32GetResetReason(0); // CPU 0
|
||||
return ESP.getResetReason();
|
||||
}
|
||||
#endif
|
||||
#if defined(esp32s2_4mb) || defined(esp32s3_16mb) || defined(esp32c3m_4mb) || defined(esp32c6_4mb) || defined(esp32c6_8mb)
|
||||
String ESP_getResetReason(void) {
|
||||
// return ESP32GetResetReason(0); // CPU 0
|
||||
esp_reset_reason_t esp_reason = esp_reset_reason();
|
||||
switch (esp_reason) {
|
||||
case ESP_RST_UNKNOWN: return "UNKNOWN";
|
||||
case ESP_RST_POWERON: return "POWER ON";
|
||||
case ESP_RST_EXT: return "EXTERNAL PIN";
|
||||
case ESP_RST_SW: return "SOFTWARE RESET";
|
||||
case ESP_RST_PANIC: return "EXCEPTION / PANIC";
|
||||
case ESP_RST_INT_WDT: return "INTERRUPT WATCHDOG";
|
||||
case ESP_RST_TASK_WDT: return "TASK WATCHDOG";
|
||||
case ESP_RST_WDT: return "WATCHDOGS";
|
||||
case ESP_RST_DEEPSLEEP: return "EXITING DEEP SLLEP MODE";
|
||||
case ESP_RST_BROWNOUT: return "BROWNOUT";
|
||||
case ESP_RST_SDIO: return "SDIO";
|
||||
default : return "NO MEAN";
|
||||
};
|
||||
}
|
||||
String ESP32GetResetReason(uint32_t cpu_no) {
|
||||
// tools\sdk\include\esp32\rom\rtc.h
|
||||
@@ -82,8 +102,8 @@ String ESP32GetResetReason(uint32_t cpu_no) {
|
||||
return F("Timer Group1 Watchdog reset digital core"); // 8
|
||||
case RTCWDT_SYS_RESET:
|
||||
return F("RTC Watchdog Reset digital core"); // 9
|
||||
case INTRUSION_RESET:
|
||||
return F("Instrusion tested to reset CPU"); // 10
|
||||
// case INTRUSION_RESET:
|
||||
// return F("Instrusion tested to reset CPU"); // 10
|
||||
case TG0WDT_CPU_RESET:
|
||||
return F("Time Group reset CPU"); // 11
|
||||
case RTC_SW_CPU_RESET:
|
||||
@@ -101,9 +121,24 @@ String ESP32GetResetReason(uint32_t cpu_no) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(esp32_4mb) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
#if defined(esp32_4mb) || defined(esp32_4mb3f) || defined(esp32_16mb) || defined(esp32cam_4mb)
|
||||
String ESP_getResetReason(void) {
|
||||
return ESP32GetResetReason(0); // CPU 0
|
||||
// return ESP32GetResetReason(0); // CPU 0
|
||||
esp_reset_reason_t esp_reason = esp_reset_reason();
|
||||
switch (esp_reason) {
|
||||
case ESP_RST_UNKNOWN: return "UNKNOWN";
|
||||
case ESP_RST_POWERON: return "POWER ON";
|
||||
case ESP_RST_EXT: return "EXTERNAL PIN";
|
||||
case ESP_RST_SW: return "SOFTWARE RESET";
|
||||
case ESP_RST_PANIC: return "EXCEPTION / PANIC";
|
||||
case ESP_RST_INT_WDT: return "INTERRUPT WATCHDOG";
|
||||
case ESP_RST_TASK_WDT: return "TASK WATCHDOG";
|
||||
case ESP_RST_WDT: return "WATCHDOGS";
|
||||
case ESP_RST_DEEPSLEEP: return "EXITING DEEP SLLEP MODE";
|
||||
case ESP_RST_BROWNOUT: return "BROWNOUT";
|
||||
case ESP_RST_SDIO: return "SDIO";
|
||||
default : return "NO MEAN";
|
||||
};
|
||||
}
|
||||
String ESP32GetResetReason(uint32_t cpu_no) {
|
||||
// tools\sdk\include\esp32\rom\rtc.h
|
||||
|
||||
@@ -89,6 +89,10 @@ void standWebServerInit() {
|
||||
// - second callback handles file upload at that location
|
||||
HTTP.on("/edit", HTTP_POST, replyOK, handleFileUpload);
|
||||
|
||||
HTTP.on("/localota", HTTP_GET, handleLocalOTA);
|
||||
|
||||
HTTP.on("/localota_handler", HTTP_GET, handleLocalOTA_Handler);
|
||||
|
||||
// Default handler for all URIs not defined above
|
||||
// Use it to read files from filesystem
|
||||
HTTP.onNotFound(handleNotFound);
|
||||
@@ -156,6 +160,15 @@ void handleStatus() {
|
||||
HTTP.send(200, "application/json", json);
|
||||
}
|
||||
|
||||
void handleLocalOTA() {
|
||||
String page = "<form action='/localota' method='POST'><label for='server'>Server Address:</label><input type='text' name='server' value='http://192.168.1.2:5500'><input type='submit' value='Update'></form>";
|
||||
HTTP.send(200, "text/html", page);}
|
||||
|
||||
void handleLocalOTA_Handler() {
|
||||
String serverValue = HTTP.arg("server");
|
||||
upgrade_firmware(3,serverValue);
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
String getContentType(String filename) {
|
||||
if (HTTP.hasArg("download")) {
|
||||
@@ -231,7 +244,12 @@ bool handleFileRead(String path) {
|
||||
return the path of the closest parent still existing
|
||||
*/
|
||||
String lastExistingParent(String path) {
|
||||
while (!path.isEmpty() && !FileFS.exists(path)) {
|
||||
#ifndef LIBRETINY
|
||||
while (!path.isEmpty() && !FileFS.exists(path))
|
||||
#else
|
||||
while (!path.length()==0 && !FileFS.exists(path))
|
||||
#endif
|
||||
{
|
||||
if (path.lastIndexOf('/') > 0) {
|
||||
path = path.substring(0, path.lastIndexOf('/'));
|
||||
} else {
|
||||
@@ -278,7 +296,7 @@ void handleFileUpload() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
#if defined ESP8266
|
||||
void deleteRecursive(String path) {
|
||||
File file = FileFS.open(path, "r");
|
||||
bool isDir = file.isDirectory();
|
||||
@@ -299,14 +317,14 @@ void deleteRecursive(String path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#if defined ESP32 || defined LIBRETINY
|
||||
struct treename {
|
||||
uint8_t type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
void deleteRecursive(String path) {
|
||||
fs::File dir = FileFS.open(path);
|
||||
fs::File dir = FileFS.open(path.c_str());
|
||||
|
||||
if (!dir.isDirectory()) {
|
||||
Serial.printf("%s is a file\n", path);
|
||||
@@ -321,7 +339,11 @@ void deleteRecursive(String path) {
|
||||
|
||||
while (entry = dir.openNextFile()) {
|
||||
if (entry.isDirectory()) {
|
||||
#if defined ESP32
|
||||
deleteRecursive(entry.path());
|
||||
#elif defined LIBRETINY
|
||||
deleteRecursive(entry.fullName());
|
||||
#endif
|
||||
} else {
|
||||
String tmpname = path + "/" + strdup(entry.name()); // buffer file name
|
||||
entry.close();
|
||||
@@ -342,10 +364,15 @@ void deleteRecursive(String path) {
|
||||
*/
|
||||
void handleFileDelete() {
|
||||
String path = HTTP.arg(0);
|
||||
#ifndef LIBRETINY
|
||||
if (path.isEmpty() || path == "/") {
|
||||
return replyBadRequest("BAD PATH");
|
||||
}
|
||||
|
||||
#else
|
||||
if (path.length()==0 || path == "/") {
|
||||
return replyBadRequest("BAD PATH");
|
||||
}
|
||||
#endif
|
||||
// DBG_OUTPUT_PORT.println(String("handleFileDelete: ") + path);
|
||||
if (!FileFS.exists(path)) {
|
||||
return replyNotFound(FPSTR(FILE_NOT_FOUND));
|
||||
@@ -368,10 +395,15 @@ void handleFileDelete() {
|
||||
*/
|
||||
void handleFileCreate() {
|
||||
String path = HTTP.arg("path");
|
||||
#ifndef LIBRETINY
|
||||
if (path.isEmpty()) {
|
||||
return replyBadRequest(F("PATH ARG MISSING"));
|
||||
}
|
||||
|
||||
#else
|
||||
if (path.length()==0) {
|
||||
return replyBadRequest(F("PATH ARG MISSING"));
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SPIFFS
|
||||
if (checkForUnsupportedPath(path).length() > 0) {
|
||||
return replyServerError(F("INVALID FILENAME"));
|
||||
@@ -386,7 +418,11 @@ void handleFileCreate() {
|
||||
}
|
||||
|
||||
String src = HTTP.arg("src");
|
||||
#ifndef LIBRETINY
|
||||
if (src.isEmpty()) {
|
||||
#else
|
||||
if (src.length()==0) {
|
||||
#endif
|
||||
// No source specified: creation
|
||||
// DBG_OUTPUT_PORT.println(String("handleFileCreate: ") + path);
|
||||
if (path.endsWith("/")) {
|
||||
@@ -404,6 +440,9 @@ void handleFileCreate() {
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
file.write(0);
|
||||
#endif
|
||||
#ifdef LIBRETINY
|
||||
file.write((uint8_t)0);
|
||||
#endif
|
||||
file.close();
|
||||
} else {
|
||||
@@ -509,7 +548,7 @@ void handleFileList() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#if defined ESP32
|
||||
void handleFileList() {
|
||||
if (!HTTP.hasArg("dir")) {
|
||||
HTTP.send(500, "text/plain", "BAD ARGS");
|
||||
@@ -517,15 +556,29 @@ void handleFileList() {
|
||||
}
|
||||
|
||||
String path = HTTP.arg("dir");
|
||||
// DBG_OUTPUT_PORT.println("handleFileList: " + path);
|
||||
|
||||
if (path != "/" && !FileFS.exists(path)) {
|
||||
return replyBadRequest("BAD PATH");
|
||||
}
|
||||
//path = "/build/";
|
||||
Serial.println("handleFileList: " + path);
|
||||
#if defined LIBRETINY
|
||||
File root = FileFS.open(path.c_str());
|
||||
//Dir root = FileFS.openDir(path);
|
||||
Serial.println("handleFileList FIRST OPEN Name: " + String(root.name()));
|
||||
#else
|
||||
File root = FileFS.open(path);
|
||||
#endif
|
||||
path = String();
|
||||
|
||||
String output = "[";
|
||||
if (root.isDirectory()) {
|
||||
Serial.println("handleFileList IS DIR: " + String(root.name()));
|
||||
//root.close();
|
||||
File file = root.openNextFile();
|
||||
Serial.println("handleFileList openNextFile: " + String(file.name()));
|
||||
|
||||
while (file) {
|
||||
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
@@ -549,6 +602,67 @@ void handleFileList() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined LIBRETINY
|
||||
void handleFileList() {
|
||||
if (!HTTP.hasArg("dir")) {
|
||||
HTTP.send(500, "text/plain", "BAD ARGS");
|
||||
return;
|
||||
}
|
||||
String path = HTTP.arg("dir");
|
||||
if (path != "/" && !FileFS.exists(path)) {
|
||||
return replyBadRequest("BAD PATH");
|
||||
}
|
||||
FileFS.open(path.c_str());
|
||||
lfs_dir_t dir;
|
||||
struct lfs_info info;
|
||||
int err = lfs_dir_open(FileFS.getFS(), &dir, path.c_str());
|
||||
if (err) {
|
||||
HTTP.send(500, "text/plain", "FAIL OPEN DIR");
|
||||
return;
|
||||
}
|
||||
String output = "[";
|
||||
while (true) {
|
||||
int res = lfs_dir_read(FileFS.getFS(), &dir, &info);
|
||||
if (res < 0) {
|
||||
lfs_dir_close(FileFS.getFS(), &dir);
|
||||
return ;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.printf("%s %d", info.name, info.type);
|
||||
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
output += "{\"type\":\"";
|
||||
// output += (file.isDirectory()) ? "dir" : "file";
|
||||
if (info.type == LFS_TYPE_DIR) {
|
||||
output += "dir";
|
||||
} else {
|
||||
output += F("file\",\"size\":\"");
|
||||
output += info.size;
|
||||
}
|
||||
|
||||
output += "\",\"name\":\"";
|
||||
output += String(info.name);
|
||||
output += "\"}";
|
||||
//file = root.openNextFile();
|
||||
|
||||
}
|
||||
|
||||
err = lfs_dir_close(FileFS.getFS(), &dir);
|
||||
if (err) {
|
||||
HTTP.send(500, "text/plain", "FAIL CLOSE DIR");
|
||||
return;
|
||||
}
|
||||
|
||||
output += "]";
|
||||
HTTP.send(200, "text/json", output);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
The "Not Found" handler catches all URI not explicitly declared in code
|
||||
First try to find and return the requested file from the filesystem,
|
||||
@@ -560,6 +674,9 @@ void handleNotFound() {
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
String uri = WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks
|
||||
#endif
|
||||
#ifdef LIBRETINY
|
||||
String uri = WebServer::urlDecode(HTTP.uri()); // required to read paths with blanks
|
||||
#endif
|
||||
if (handleFileRead(uri)) {
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
updateFirm update;
|
||||
|
||||
void upgrade_firmware(int type, String path) {
|
||||
if (path == ""){
|
||||
path = getBinPath();
|
||||
}
|
||||
putUserDataToRam();
|
||||
// сбросим файл статуса последнего обновления
|
||||
writeFile("ota.json", "{}");
|
||||
@@ -36,6 +39,7 @@ void upgrade_firmware(int type, String path) {
|
||||
|
||||
bool upgradeFS(String path) {
|
||||
bool ret = false;
|
||||
#ifndef LIBRETINY
|
||||
WiFiClient wifiClient;
|
||||
SerialPrint("!!!", F("Update"), "Start upgrade FS... " + path);
|
||||
|
||||
@@ -57,21 +61,27 @@ bool upgradeFS(String path) {
|
||||
// если FS обновилась успешно
|
||||
if (retFS == HTTP_UPDATE_OK) {
|
||||
SerialPrint("!!!", F("Update"), F("FS upgrade done!"));
|
||||
//HTTP.send(200, "text/plain", "FS upgrade done!");
|
||||
saveUpdeteStatus("fs", UPDATE_COMPLETED);
|
||||
ret = true;
|
||||
} else {
|
||||
saveUpdeteStatus("fs", UPDATE_FAILED);
|
||||
if (retFS == HTTP_UPDATE_FAILED) {
|
||||
SerialPrint("E", F("Update"), "HTTP_UPDATE_FAILED");
|
||||
String page = "<html><body>Ошибка обновления FS!<br>FS Update failed!<br><a href='/'>Home</a></body></html>";
|
||||
HTTP.send(200, "text/html; charset=UTF-8", page);
|
||||
} else if (retFS == HTTP_UPDATE_NO_UPDATES) {
|
||||
SerialPrint("E", F("Update"), "HTTP_UPDATE_NO_UPDATES");
|
||||
SerialPrint("E", F("Update"), "HTTP_UPDATE_NO_UPDATES! DELETE /localota !!!");
|
||||
//HTTP.send(200, "text/plain", "NO_UPDATES");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool upgradeBuild(String path) {
|
||||
bool ret = false;
|
||||
#ifndef LIBRETINY
|
||||
WiFiClient wifiClient;
|
||||
SerialPrint("!!!", F("Update"), "Start upgrade BUILD... " + path);
|
||||
|
||||
@@ -92,16 +102,23 @@ bool upgradeBuild(String path) {
|
||||
// если BUILD обновился успешно
|
||||
if (retBuild == HTTP_UPDATE_OK) {
|
||||
SerialPrint("!!!", F("Update"), F("BUILD upgrade done!"));
|
||||
String page = "<html><body>Обновление BUILD выполнено!<br>Build upgrade done!<br><a href='/'>Home</a></body></html>";
|
||||
HTTP.send(200, "text/html; charset=UTF-8", page);
|
||||
saveUpdeteStatus("build", UPDATE_COMPLETED);
|
||||
ret = true;
|
||||
} else {
|
||||
saveUpdeteStatus("build", UPDATE_FAILED);
|
||||
if (retBuild == HTTP_UPDATE_FAILED) {
|
||||
SerialPrint("E", F("Update"), "HTTP_UPDATE_FAILED");
|
||||
String page = "<html><body>Ошибка обновления прошивки!<br>Firmware update failed!<br><a href='/'>Home</a></body></html>";
|
||||
HTTP.send(200, "text/html; charset=UTF-8", page);
|
||||
} else if (retBuild == HTTP_UPDATE_NO_UPDATES) {
|
||||
SerialPrint("E", F("Update"), "HTTP_UPDATE_NO_UPDATES");
|
||||
String page = "<html><body>Нет обновлений!<br>No updates!<br><a href='/'>Home</a></body></html>";
|
||||
HTTP.send(200, "text/html; charset=UTF-8", page);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -111,23 +128,37 @@ void restartEsp() {
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
// теперь путь к обнавленю прошивки мы получаем из веб интерфейса
|
||||
// const String getBinPath(String file) {
|
||||
// String path = "error";
|
||||
// int targetVersion = 0;
|
||||
// String serverip;
|
||||
// if (jsonRead(errorsHeapJson, F("chver"), targetVersion)) {
|
||||
// if (targetVersion >= 400) {
|
||||
// if (jsonRead(settingsFlashJson, F("serverip"), serverip)) {
|
||||
// if (serverip != "") {
|
||||
// path = jsonReadStr(settingsFlashJson, F("serverip")) + "/iotm/" + String(FIRMWARE_NAME) + "/" + String(targetVersion) + "/" + file;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// SerialPrint("i", F("Update"), "path: " + path);
|
||||
// return path;
|
||||
// }
|
||||
//теперь путь к обнавленю прошивки мы получаем из веб интерфейса
|
||||
const String getBinPath() {
|
||||
String path = "error";
|
||||
int targetVersion = 400; //HACKFUCK local OTA version in PrepareServer.py
|
||||
String serverip;
|
||||
if (jsonRead(errorsHeapJson, F("chver"), targetVersion)) {
|
||||
if (targetVersion >= 400)
|
||||
{
|
||||
if (jsonRead(settingsFlashJson, F("serverip"), serverip))
|
||||
{
|
||||
if (serverip != "")
|
||||
{
|
||||
path = jsonReadStr(settingsFlashJson, F("serverip")) + "/iotm/" + String(FIRMWARE_NAME) + "/" + String(targetVersion) + "/" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetVersion >= 400)
|
||||
{
|
||||
if (jsonRead(settingsFlashJson, F("serverlocal"), serverip)) {
|
||||
if (serverip != "")
|
||||
{
|
||||
path = jsonReadStr(settingsFlashJson, F("serverlocal")) + "/iotm/" + String(FIRMWARE_NAME) + "/" + String(targetVersion) + "/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SerialPrint("i", F("Update"), "server local: " + path);
|
||||
return path;
|
||||
}
|
||||
|
||||
// https://t.me/IoTmanager/128814/164752 - убрал ограничение
|
||||
void putUserDataToRam() {
|
||||
|
||||
@@ -7,6 +7,10 @@ void standWebSocketsInit() {
|
||||
standWebSocket.begin();
|
||||
standWebSocket.onEvent(webSocketEvent);
|
||||
SerialPrint("i", "WS", "WS server initialized");
|
||||
for (size_t i = 0; i < WEBSOCKETS_CLIENT_MAX; i++)
|
||||
{
|
||||
ws_clients[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
|
||||
@@ -17,6 +21,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
|
||||
|
||||
case WStype_DISCONNECTED: {
|
||||
Serial.printf("[%u] Disconnected!\n", num);
|
||||
standWebSocket.disconnect(num);
|
||||
} break;
|
||||
|
||||
case WStype_CONNECTED: {
|
||||
@@ -54,7 +59,11 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
|
||||
//----------------------------------------------------------------------//
|
||||
// Страница веб интерфейса dashboard
|
||||
//----------------------------------------------------------------------//
|
||||
|
||||
if (headerStr == "p|") {
|
||||
standWebSocket.sendTXT(num, "p|");
|
||||
//Serial.printf("Ping client: %u\n", num);
|
||||
ws_clients[num]=1;
|
||||
}
|
||||
// публикация всех виджетов
|
||||
if (headerStr == "/|") {
|
||||
sendFileToWsByFrames("/layout.json", "layout", "", num, WEB_SOCKETS_FRAME_SIZE);
|
||||
@@ -166,7 +175,9 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
|
||||
if (headerStr == "/scan|") {
|
||||
std::vector<String> jArray;
|
||||
jsonReadArray(settingsFlashJson, "routerssid", jArray);
|
||||
#ifdef ESP8266
|
||||
RouterFind(jArray);
|
||||
#endif
|
||||
sendStringToWs("ssidli", ssidListHeapJson, num);
|
||||
}
|
||||
|
||||
@@ -378,6 +389,7 @@ void sendFileToWsByFrames(const String& filename, const String& header, const St
|
||||
|
||||
auto path = filepath(filename);
|
||||
auto file = FileFS.open(path, "r");
|
||||
//SerialPrint("I", "sendFileToWsByFrames", ("reed file: ")+ path);
|
||||
if (!file) {
|
||||
SerialPrint("E", "FS", F("reed file error"));
|
||||
return;
|
||||
@@ -425,16 +437,25 @@ void sendFileToWsByFrames(const String& filename, const String& header, const St
|
||||
continuation = true;
|
||||
}
|
||||
|
||||
// Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz:
|
||||
// " + String(size) + " fin: " + String(fin) + " cnt: " +
|
||||
// String(continuation));
|
||||
|
||||
// Serial.println(String(i) + ") " + "ws: " + String(client_id) + " fr sz: "
|
||||
// + String(size) + " fin: " + String(fin) + " cnt: " +
|
||||
// String(continuation));
|
||||
#ifdef ASYNC_WEB_SOCKETS
|
||||
if (client_id == -1) {
|
||||
//ws.broadcastBIN(frameBuf, size, fin, continuation);
|
||||
ws.binaryAll(frameBuf, size);
|
||||
} else {
|
||||
//ws.sendBIN(client_id, frameBuf, size, fin, continuation);
|
||||
ws.binary(client_id,frameBuf, size);
|
||||
}
|
||||
#elif defined (STANDARD_WEB_SOCKETS)
|
||||
if (client_id == -1) {
|
||||
standWebSocket.broadcastBIN(frameBuf, size, fin, continuation);
|
||||
|
||||
} else {
|
||||
standWebSocket.sendBIN(client_id, frameBuf, size, fin, continuation);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -444,7 +465,12 @@ void sendFileToWsByFrames(const String& filename, const String& header, const St
|
||||
}
|
||||
|
||||
void sendStringToWs(const String& header, String& payload, int client_id) {
|
||||
if ((!getNumAPClients() && !isNetworkActive()) || !getNumWSClients()) {
|
||||
#ifdef LIBRETINY
|
||||
if (/* (!getNumAPClients() && !isNetworkActive()) || */ !getNumWSClients()) {
|
||||
#else
|
||||
if ( (!getNumAPClients() && !isNetworkActive()) || !getNumWSClients()) {
|
||||
#endif
|
||||
// SerialPrint("E", "sendStringToWs", "getNumAPClients: " + String(getNumAPClients()) + "isNetworkActive: " + String(isNetworkActive() + "getNumWSClients: " + String(getNumWSClients())));
|
||||
// standWebSocket.disconnect(); // это и ниже надо сделать при -
|
||||
// standWebSocket.close(); // - отключении AP И WiFi(STA), надо менять ядро WiFi. Сейчас не закрывается сессия клиента при пропаже AP И WiFi(STA)
|
||||
return;
|
||||
@@ -457,17 +483,32 @@ void sendStringToWs(const String& header, String& payload, int client_id) {
|
||||
|
||||
String msg = header + "|0012|" + payload;
|
||||
size_t totalSize = msg.length();
|
||||
|
||||
// SerialPrint("E", "sendStringToWs", msg);
|
||||
char dataArray[totalSize];
|
||||
msg.toCharArray(dataArray, totalSize + 1);
|
||||
#ifdef ASYNC_WEB_SOCKETS
|
||||
if (client_id == -1) {
|
||||
ws.binaryAll((uint8_t*)dataArray, totalSize);
|
||||
} else {
|
||||
ws.binary(client_id, (uint8_t*)dataArray, totalSize);
|
||||
}
|
||||
#elif defined (STANDARD_WEB_SOCKETS)
|
||||
if (client_id == -1) {
|
||||
standWebSocket.broadcastBIN((uint8_t*)dataArray, totalSize);
|
||||
} else {
|
||||
standWebSocket.sendBIN(client_id, (uint8_t*)dataArray, totalSize);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void sendDeviceList(uint8_t num) {
|
||||
void disconnectWSClient(uint8_t client_id)
|
||||
{
|
||||
standWebSocket.disconnect(client_id);
|
||||
Serial.printf("[WS] Client %u -disconnected\n", client_id);
|
||||
}
|
||||
|
||||
void sendDeviceList(uint8_t num)
|
||||
{
|
||||
if (jsonReadInt(settingsFlashJson, F("udps")) != 0) {
|
||||
// если включен автопоиск то отдаем список из оперативной памяти
|
||||
SerialPrint("i", "FS", "heap list");
|
||||
@@ -478,5 +519,8 @@ void sendDeviceList(uint8_t num) {
|
||||
SerialPrint("i", "FS", "flash list");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASYNC_WEB_SOCKETS
|
||||
int getNumWSClients() { return ws.count(); }
|
||||
#elif defined (STANDARD_WEB_SOCKETS)
|
||||
int getNumWSClients() { return standWebSocket.connectedClients(false); }
|
||||
#endif
|
||||
31
src/classes/IoTDiscovery.cpp
Normal file
31
src/classes/IoTDiscovery.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "Global.h"
|
||||
#include "classes/IoTDiscovery.h"
|
||||
|
||||
IoTDiscovery::IoTDiscovery(const String ¶meters) : IoTItem(parameters)
|
||||
{
|
||||
/* int _tx, _rx, _speed, _line;
|
||||
jsonRead(parameters, "rx", _rx);
|
||||
jsonRead(parameters, "tx", _tx);
|
||||
jsonRead(parameters, "speed", _speed);
|
||||
jsonRead(parameters, "line", _line);
|
||||
*/
|
||||
//ChipId = getChipId();
|
||||
}
|
||||
|
||||
void IoTDiscovery::publishStatusHOMEd(const String &topic, const String &data) {}
|
||||
void IoTDiscovery::getlayoutHA() {}
|
||||
void IoTDiscovery::getlayoutHOMEd() {}
|
||||
void IoTDiscovery::deleteFromHOMEd() {}
|
||||
void IoTDiscovery::mqttSubscribeDiscovery(){}
|
||||
|
||||
boolean IoTDiscovery::publishRetain(const String &topic, const String &data)
|
||||
{
|
||||
if (mqtt.beginPublish(topic.c_str(), data.length(), true))
|
||||
{
|
||||
mqtt.print(data);
|
||||
return mqtt.endPublish();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IoTDiscovery::~IoTDiscovery() {}
|
||||
@@ -9,7 +9,7 @@ IoTGpio::~IoTGpio(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef LIBRETINY
|
||||
void IoTGpio::pinMode(int pin, uint8_t mode) {
|
||||
int pinH = pin/100;
|
||||
if (_drivers[pinH]) _drivers[pinH]->pinMode(pin - pinH*100, mode);
|
||||
@@ -21,7 +21,19 @@ void IoTGpio::digitalWrite(int pin, uint8_t val) {
|
||||
if (_drivers[pinH]) _drivers[pinH]->digitalWrite(pin - pinH*100, val);
|
||||
else ::digitalWrite(pin, val);
|
||||
}
|
||||
#else
|
||||
void IoTGpio::pinMode(int pin, uint8_t mode) {
|
||||
int pinH = pin/100;
|
||||
if (_drivers[pinH]) _drivers[pinH]->pinMode(pin - pinH*100, mode);
|
||||
else ::pinMode(pin, (PinMode)mode);
|
||||
}
|
||||
|
||||
void IoTGpio::digitalWrite(int pin, uint8_t val) {
|
||||
int pinH = pin/100;
|
||||
if (_drivers[pinH]) _drivers[pinH]->digitalWrite(pin - pinH*100, val);
|
||||
else ::digitalWrite(pin, (PinStatus)val);
|
||||
}
|
||||
#endif
|
||||
int IoTGpio::digitalRead(int pin) {
|
||||
int pinH = pin/100;
|
||||
if (_drivers[pinH]) return _drivers[pinH]->digitalRead(pin - pinH*100);
|
||||
@@ -51,7 +63,11 @@ void IoTGpio::analogWrite(int pin, int val) {
|
||||
void IoTGpio::digitalInvert(int pin) {
|
||||
int pinH = pin/100;
|
||||
if (_drivers[pinH]) _drivers[pinH]->digitalInvert(pin - pinH*100);
|
||||
else ::digitalWrite(pin, 1 - ::digitalRead(pin));
|
||||
#ifdef LIBRETINY
|
||||
else ::digitalWrite(pin, (PinStatus)(1 - ::digitalRead(pin)));
|
||||
#else
|
||||
else ::digitalWrite(pin, (1 - ::digitalRead(pin)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -258,6 +258,14 @@ IoTBench *IoTItem::getBenchmarkLoad()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
IoTDiscovery *IoTItem::getHOMEdDiscovery()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
IoTDiscovery *IoTItem::getHADiscovery()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
unsigned long IoTItem::getRtcUnixTime()
|
||||
{
|
||||
return 0;
|
||||
@@ -281,7 +289,7 @@ unsigned long IoTItem::getRtcUnixTime()
|
||||
|
||||
//=========================================================================================================================================
|
||||
|
||||
IoTItem* myIoTItem;
|
||||
// IoTItem* myIoTItem; // экономим память, используется в одном месте
|
||||
|
||||
// поиск элемента модуля в существующей конфигурации
|
||||
IoTItem* findIoTItem(const String& name) {
|
||||
|
||||
@@ -342,7 +342,8 @@ enum SysOp {
|
||||
sysop_getIP,
|
||||
sysop_mqttPub,
|
||||
sysop_getUptime,
|
||||
sysop_mqttIsConnect
|
||||
sysop_mqttIsConnect,
|
||||
sysop_wifiIsConnect
|
||||
};
|
||||
|
||||
IoTValue sysExecute(SysOp command, std::vector<IoTValue> ¶m) {
|
||||
@@ -414,11 +415,11 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue> ¶m) {
|
||||
case sysop_deepSleep:
|
||||
if (param.size()) {
|
||||
Serial.printf("Ушел спать на %d сек...", (int)param[0].valD);
|
||||
#ifdef ESP32
|
||||
#if defined(ESP32)
|
||||
esp_sleep_enable_timer_wakeup(param[0].valD * 1000000);
|
||||
delay(1000);
|
||||
esp_deep_sleep_start();
|
||||
#else
|
||||
#elif defined(ESP8266)
|
||||
ESP.deepSleep(param[0].valD * 1000000);
|
||||
#endif
|
||||
}
|
||||
@@ -435,7 +436,7 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue> ¶m) {
|
||||
if (param.size() == 2) {
|
||||
// Serial.printf("Call from sysExecute %s %s\n", param[0].valS.c_str(), param[1].valS.c_str());
|
||||
String tmpStr = param[1].valS;
|
||||
if (param[1].isDecimal) tmpStr = param[1].valD;
|
||||
if (param[1].isDecimal) tmpStr = String(param[1].valD);
|
||||
value.valD = mqtt.publish(param[0].valS.c_str(), tmpStr.c_str(), false);
|
||||
}
|
||||
break;
|
||||
@@ -446,6 +447,9 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue> ¶m) {
|
||||
case sysop_mqttIsConnect:
|
||||
value.valD = mqttIsConnect();
|
||||
break;
|
||||
case sysop_wifiIsConnect:
|
||||
value.valD = isNetworkActive();
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -502,6 +506,8 @@ class SysCallExprAST : public ExprAST {
|
||||
operation = sysop_getUptime;
|
||||
else if (Callee == F("mqttIsConnect"))
|
||||
operation = sysop_mqttIsConnect;
|
||||
else if (Callee == F("wifiIsConnect"))
|
||||
operation = sysop_wifiIsConnect;
|
||||
else
|
||||
operation = sysop_notfound;
|
||||
}
|
||||
@@ -658,7 +664,7 @@ int IoTScenario::gettok() {
|
||||
LastChar = getLastChar();
|
||||
|
||||
if (isalpha(LastChar) || LastChar == '_') { // идентификатор: [a-zA-Z][a-zA-Z0-9]*
|
||||
IdentifierStr = (char)LastChar;
|
||||
IdentifierStr = String((char)LastChar);
|
||||
while (isalnum((LastChar = getLastChar())) || LastChar == '_') {
|
||||
IdentifierStr += (char)LastChar;
|
||||
}
|
||||
@@ -701,7 +707,16 @@ int IoTScenario::gettok() {
|
||||
IdentifierStr = "";
|
||||
LastChar = getLastChar();
|
||||
while (LastChar != '"' && LastChar != EOF) {
|
||||
IdentifierStr += (char)LastChar;
|
||||
if (LastChar == '\\') { // обработка экранированных символов в строке
|
||||
LastChar = getLastChar();
|
||||
if (LastChar == '"') {
|
||||
IdentifierStr += '"';
|
||||
} else if (LastChar == 'n') {
|
||||
IdentifierStr += '\n';
|
||||
}
|
||||
} else {
|
||||
IdentifierStr += (char)LastChar;
|
||||
}
|
||||
LastChar = getLastChar();
|
||||
}
|
||||
LastChar = getLastChar();
|
||||
|
||||
@@ -5,43 +5,15 @@ void* getAPI_Loging(String subtype, String params);
|
||||
void* getAPI_LogingDaily(String subtype, String params);
|
||||
void* getAPI_IoTMath(String subtype, String params);
|
||||
void* getAPI_owmWeather(String subtype, String params);
|
||||
void* getAPI_Ping(String subtype, String params);
|
||||
void* getAPI_Timer(String subtype, String params);
|
||||
void* getAPI_Variable(String subtype, String params);
|
||||
void* getAPI_VButton(String subtype, String params);
|
||||
void* getAPI_A02Distance(String subtype, String params);
|
||||
void* getAPI_Acs712(String subtype, String params);
|
||||
void* getAPI_AhtXX(String subtype, String params);
|
||||
void* getAPI_AnalogAdc(String subtype, String params);
|
||||
void* getAPI_BL0937(String subtype, String params);
|
||||
void* getAPI_Bme280(String subtype, String params);
|
||||
void* getAPI_Bmp280(String subtype, String params);
|
||||
void* getAPI_Dht1122(String subtype, String params);
|
||||
void* getAPI_Ds18b20(String subtype, String params);
|
||||
void* getAPI_Impulse(String subtype, String params);
|
||||
void* getAPI_MQgas(String subtype, String params);
|
||||
void* getAPI_Pzem004_v2(String subtype, String params);
|
||||
void* getAPI_RTC(String subtype, String params);
|
||||
void* getAPI_S8(String subtype, String params);
|
||||
void* getAPI_Sht20(String subtype, String params);
|
||||
void* getAPI_Sht30(String subtype, String params);
|
||||
void* getAPI_Sonar(String subtype, String params);
|
||||
void* getAPI_UART(String subtype, String params);
|
||||
void* getAPI_AnalogBtn(String subtype, String params);
|
||||
void* getAPI_ButtonIn(String subtype, String params);
|
||||
void* getAPI_ButtonOut(String subtype, String params);
|
||||
void* getAPI_Buzzer(String subtype, String params);
|
||||
void* getAPI_Encoder(String subtype, String params);
|
||||
void* getAPI_IoTServo(String subtype, String params);
|
||||
void* getAPI_Mcp23017(String subtype, String params);
|
||||
void* getAPI_Mp3(String subtype, String params);
|
||||
void* getAPI_Multitouch(String subtype, String params);
|
||||
void* getAPI_Pcf8574(String subtype, String params);
|
||||
void* getAPI_Pwm8266(String subtype, String params);
|
||||
void* getAPI_TelegramLT(String subtype, String params);
|
||||
void* getAPI_DwinI(String subtype, String params);
|
||||
void* getAPI_Lcd2004(String subtype, String params);
|
||||
void* getAPI_Oled64(String subtype, String params);
|
||||
|
||||
void* getAPI(String subtype, String params) {
|
||||
void* tmpAPI;
|
||||
@@ -50,42 +22,14 @@ if ((tmpAPI = getAPI_Loging(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_LogingDaily(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_IoTMath(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_owmWeather(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Ping(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Timer(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Variable(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_VButton(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_A02Distance(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Acs712(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_AhtXX(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_AnalogAdc(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_BL0937(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Bme280(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Bmp280(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Dht1122(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Ds18b20(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Impulse(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_MQgas(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Pzem004_v2(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_RTC(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_S8(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Sht20(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Sht30(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Sonar(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_UART(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_AnalogBtn(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_ButtonIn(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_ButtonOut(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Buzzer(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Encoder(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_IoTServo(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Mcp23017(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Mp3(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Multitouch(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Pcf8574(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Pwm8266(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_TelegramLT(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_DwinI(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Lcd2004(subtype, params)) != nullptr) return tmpAPI;
|
||||
if ((tmpAPI = getAPI_Oled64(subtype, params)) != nullptr) return tmpAPI;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -40,36 +40,12 @@
|
||||
"btn-uploadUI": "Формирует автоматически графический интерфейс на базе конфигурации и выгружает в экран. Занимает продолжительное время! (в разработке)"
|
||||
}
|
||||
},
|
||||
"defActive": true,
|
||||
"defActive": false,
|
||||
"usedLibs": {
|
||||
"esp32_4mb": [
|
||||
"esp32*": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp32_4mb3f": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp32cam_4mb": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8266_4mb": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8266_1mb": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8266_1mb_ota": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8266_2mb": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8266_2mb_ota": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8285_1mb": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
],
|
||||
"esp8285_1mb_ota": [
|
||||
"esp82*": [
|
||||
"plerup/EspSoftwareSerial"
|
||||
]
|
||||
}
|
||||
|
||||
1309
src/modules/display/GyverLAMP/GyverLAMP.cpp
Normal file
1309
src/modules/display/GyverLAMP/GyverLAMP.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9
src/modules/display/GyverLAMP/config.h
Normal file
9
src/modules/display/GyverLAMP/config.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
// матрица
|
||||
#define WIDTH 16 // ширина матрицы
|
||||
#define HEIGHT 16 // высота матрицы
|
||||
#define SEGMENTS 1 // диодов в одном "пикселе" (для создания матрицы из кусков ленты)
|
||||
#define NUM_LEDS WIDTH *HEIGHT *SEGMENTS
|
||||
// лента
|
||||
#define LED_COUNT NUM_LEDS // число светодиодов в кольце/ленте
|
||||
#define LED_DT 13 // пин, куда подключен DIN ленты
|
||||
1833
src/modules/display/GyverLAMP/effects.h
Normal file
1833
src/modules/display/GyverLAMP/effects.h
Normal file
File diff suppressed because it is too large
Load Diff
770
src/modules/display/GyverLAMP/matrix.h
Normal file
770
src/modules/display/GyverLAMP/matrix.h
Normal file
@@ -0,0 +1,770 @@
|
||||
#include "utility.h"
|
||||
|
||||
byte hue;
|
||||
boolean loadingFlag = true;
|
||||
// **************** НАСТРОЙКИ ЭФФЕКТОВ ****************
|
||||
// эффект "синусоиды" - ОТКЛЮЧЕН
|
||||
#define WAVES_AMOUNT 2 // количество синусоид
|
||||
|
||||
// эффект "шарики"
|
||||
#define BALLS_AMOUNT 3 // количество "шариков"
|
||||
#define CLEAR_PATH 1 // очищать путь
|
||||
#define BALL_TRACK 1 // (0 / 1) - вкл/выкл следы шариков
|
||||
#define DRAW_WALLS 0 // режим с рисованием препятствий для шаров (не работает на ESP и STM32)
|
||||
#define TRACK_STEP 70 // длина хвоста шарика (чем больше цифра, тем хвост короче)
|
||||
|
||||
// эффект "квадратик"
|
||||
#define BALL_SIZE 3 // размер шара
|
||||
#define RANDOM_COLOR 1 // случайный цвет при отскоке
|
||||
|
||||
// эффект "огонь"
|
||||
#define SPARKLES 1 // вылетающие угольки вкл выкл
|
||||
#define HUE_ADD 0 // добавка цвета в огонь (от 0 до 230) - меняет весь цвет пламени
|
||||
|
||||
// эффект "кометы"
|
||||
#define TAIL_STEP 100 // длина хвоста кометы
|
||||
#define SATURATION 150 // насыщенность кометы (от 0 до 255)
|
||||
#define STAR_DENSE 60 // количество (шанс появления) комет
|
||||
|
||||
// эффект "конфетти"
|
||||
#define DENSE 3 // плотность конфетти
|
||||
#define BRIGHT_STEP 70 // шаг уменьшения яркости
|
||||
|
||||
// эффект "снег"
|
||||
#define SNOW_DENSE 10 // плотность снегопада
|
||||
|
||||
// эффект "Светляки"
|
||||
#define LIGHTERS_AM 35 // количество светляков
|
||||
|
||||
uint32_t globalColor = 0xffffff; // Цвет рисования при запуске белый
|
||||
unsigned char matrixValue[8][16];
|
||||
unsigned char line[WIDTH];
|
||||
int pcnt = 0;
|
||||
int effectSpeed = _speed; // скрость изменения эффекта
|
||||
uint8_t USE_SEGMENTS = 1;
|
||||
uint8_t BorderWidth = 0;
|
||||
uint8_t dir_mx, seg_num, seg_size, seg_offset;
|
||||
uint16_t XY(uint8_t, uint8_t); // __attribute__ ((weak));
|
||||
|
||||
// эффекты матрицы
|
||||
|
||||
// *********** "дыхание" яркостью ***********
|
||||
boolean brightnessDirection;
|
||||
byte breathBrightness; // Яркость эффекта "Дыхание"
|
||||
byte globalBrightness = _brightness;
|
||||
void brightnessRoutine()
|
||||
{
|
||||
if (brightnessDirection)
|
||||
{
|
||||
breathBrightness += 2;
|
||||
if (breathBrightness > globalBrightness - 1)
|
||||
{
|
||||
brightnessDirection = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
breathBrightness -= 2;
|
||||
if (breathBrightness < 1)
|
||||
{
|
||||
brightnessDirection = true;
|
||||
}
|
||||
}
|
||||
FastLED.setBrightness(breathBrightness);
|
||||
}
|
||||
|
||||
// *********** снегопад 2.0 ***********
|
||||
void snowRoutine()
|
||||
{
|
||||
|
||||
// сдвигаем всё вниз
|
||||
for (byte x = 0; x < WIDTH; x++)
|
||||
{
|
||||
for (byte y = 0; y < HEIGHT - 1; y++)
|
||||
{
|
||||
drawPixelXY(x, y, getPixColorXY(x, y + 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (byte x = 0; x < WIDTH; x++)
|
||||
{
|
||||
// заполняем случайно верхнюю строку
|
||||
// а также не даём двум блокам по вертикали вместе быть
|
||||
if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, SNOW_DENSE) == 0))
|
||||
drawPixelXY(x, HEIGHT - 1, 0xE0FFFF - 0x101010 * random(0, 4));
|
||||
else
|
||||
drawPixelXY(x, HEIGHT - 1, 0x000000);
|
||||
}
|
||||
}
|
||||
|
||||
// ***************************** БЛУДНЫЙ КУБИК *****************************
|
||||
int coordB[2];
|
||||
int8_t vectorB[2];
|
||||
CRGB ballColor;
|
||||
|
||||
void ballRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
for (byte i = 0; i < 2; i++)
|
||||
{
|
||||
coordB[i] = WIDTH / 2 * 10;
|
||||
vectorB[i] = random(8, 20);
|
||||
ballColor = CHSV(random(0, 9) * 28, 255, 255);
|
||||
}
|
||||
|
||||
loadingFlag = false;
|
||||
}
|
||||
for (byte i = 0; i < 2; i++)
|
||||
{
|
||||
coordB[i] += vectorB[i];
|
||||
if (coordB[i] < 0)
|
||||
{
|
||||
coordB[i] = 0;
|
||||
vectorB[i] = -vectorB[i];
|
||||
if (RANDOM_COLOR)
|
||||
ballColor = CHSV(random(0, 9) * 28, 255, 255);
|
||||
// vectorB[i] += random(0, 6) - 3;
|
||||
}
|
||||
}
|
||||
if (coordB[0] > (WIDTH - BALL_SIZE) * 10)
|
||||
{
|
||||
coordB[0] = (WIDTH - BALL_SIZE) * 10;
|
||||
vectorB[0] = -vectorB[0];
|
||||
if (RANDOM_COLOR)
|
||||
ballColor = CHSV(random(0, 9) * 28, 255, 255);
|
||||
// vectorB[0] += random(0, 6) - 3;
|
||||
}
|
||||
if (coordB[1] > (HEIGHT - BALL_SIZE) * 10)
|
||||
{
|
||||
coordB[1] = (HEIGHT - BALL_SIZE) * 10;
|
||||
vectorB[1] = -vectorB[1];
|
||||
if (RANDOM_COLOR)
|
||||
ballColor = CHSV(random(0, 9) * 28, 255, 255);
|
||||
// vectorB[1] += random(0, 6) - 3;
|
||||
}
|
||||
FastLED.clear();
|
||||
for (byte i = 0; i < BALL_SIZE; i++)
|
||||
for (byte j = 0; j < BALL_SIZE; j++)
|
||||
leds[getPixelNumber(coordB[0] / 10 + i, coordB[1] / 10 + j)] = ballColor;
|
||||
}
|
||||
|
||||
// *********** радуга заливка ***********
|
||||
void rainbowRoutine()
|
||||
{
|
||||
|
||||
hue += 3;
|
||||
for (byte i = 0; i < WIDTH; i++)
|
||||
{
|
||||
CHSV thisColor = CHSV((byte)(hue + i * float(255 / WIDTH)), 255, 255);
|
||||
for (byte j = 0; j < HEIGHT; j++)
|
||||
drawPixelXY(i, j, thisColor); // leds[getPixelNumber(i, j)] = thisColor;
|
||||
}
|
||||
}
|
||||
|
||||
// *********** радуга дигональная ***********
|
||||
void rainbowDiagonalRoutine()
|
||||
{
|
||||
|
||||
hue += 3;
|
||||
for (byte x = 0; x < WIDTH; x++)
|
||||
{
|
||||
for (byte y = 0; y < HEIGHT; y++)
|
||||
{
|
||||
CHSV thisColor = CHSV((byte)(hue + (float)(WIDTH / HEIGHT * x + y) * (float)(255 / 100)), 255, 255);
|
||||
drawPixelXY(x, y, thisColor); // leds[getPixelNumber(i, j)] = thisColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *********** радуга активных светодиодов (рисунка) ***********
|
||||
void rainbowColorsRoutine()
|
||||
{
|
||||
hue++;
|
||||
for (byte i = 0; i < WIDTH; i++)
|
||||
{
|
||||
CHSV thisColor = CHSV((byte)(hue + i * float(255 / WIDTH)), 255, 255);
|
||||
for (byte j = 0; j < HEIGHT; j++)
|
||||
if (getPixColor(getPixelNumber(i, j)) > 0)
|
||||
drawPixelXY(i, j, thisColor);
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************** ОГОНЬ ******************************
|
||||
// ********************** огонь **********************
|
||||
// these values are substracetd from the generated values to give a shape to the animation
|
||||
const unsigned char valueMask[8][16] PROGMEM = {
|
||||
{32, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 0, 0, 0, 0, 32},
|
||||
{64, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 64},
|
||||
{96, 32, 0, 0, 0, 0, 32, 96, 96, 32, 0, 0, 0, 0, 32, 96},
|
||||
{128, 64, 32, 0, 0, 32, 64, 128, 128, 64, 32, 0, 0, 32, 64, 128},
|
||||
{160, 96, 64, 32, 32, 64, 96, 160, 160, 96, 64, 32, 32, 64, 96, 160},
|
||||
{192, 128, 96, 64, 64, 96, 128, 192, 192, 128, 96, 64, 64, 96, 128, 192},
|
||||
{255, 160, 128, 96, 96, 128, 160, 255, 255, 160, 128, 96, 96, 128, 160, 255},
|
||||
{255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255}};
|
||||
|
||||
// these are the hues for the fire,
|
||||
// should be between 0 (red) to about 25 (yellow)
|
||||
const unsigned char hueMask[8][16] PROGMEM = {
|
||||
{1, 11, 19, 25, 25, 22, 11, 1, 1, 11, 19, 25, 25, 22, 11, 1},
|
||||
{1, 8, 13, 19, 25, 19, 8, 1, 1, 8, 13, 19, 25, 19, 8, 1},
|
||||
{1, 8, 13, 16, 19, 16, 8, 1, 1, 8, 13, 16, 19, 16, 8, 1},
|
||||
{1, 5, 11, 13, 13, 13, 5, 1, 1, 5, 11, 13, 13, 13, 5, 1},
|
||||
{1, 5, 11, 11, 11, 11, 5, 1, 1, 5, 11, 11, 11, 11, 5, 1},
|
||||
{0, 1, 5, 8, 8, 5, 1, 0, 0, 1, 5, 8, 8, 5, 1, 0},
|
||||
{0, 0, 1, 5, 5, 1, 0, 0, 0, 0, 1, 5, 5, 1, 0, 0},
|
||||
{0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0}};
|
||||
// Randomly generate the next line (matrix row)
|
||||
|
||||
void generateLine()
|
||||
{
|
||||
for (uint8_t x = 0; x < WIDTH; x++)
|
||||
{
|
||||
line[x] = random(64, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// shift all values in the matrix up one row
|
||||
|
||||
void shiftUp()
|
||||
{
|
||||
for (uint8_t y = HEIGHT - 1; y > 0; y--)
|
||||
{
|
||||
for (uint8_t x = 0; x < WIDTH; x++)
|
||||
{
|
||||
uint8_t newX = x;
|
||||
if (x > 15)
|
||||
newX = x % 16;
|
||||
if (y > 7)
|
||||
continue;
|
||||
matrixValue[y][newX] = matrixValue[y - 1][newX];
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t x = 0; x < WIDTH; x++)
|
||||
{
|
||||
uint8_t newX = x;
|
||||
if (x > 15)
|
||||
newX = x % 16;
|
||||
matrixValue[0][newX] = line[newX];
|
||||
}
|
||||
}
|
||||
|
||||
// draw a frame, interpolating between 2 "key frames"
|
||||
// @param pcnt percentage of interpolation
|
||||
|
||||
void drawFrame(int pcnt)
|
||||
{
|
||||
int nextv;
|
||||
|
||||
// each row interpolates with the one before it
|
||||
for (unsigned char y = HEIGHT - 1; y > 0; y--)
|
||||
{
|
||||
for (unsigned char x = 0; x < WIDTH; x++)
|
||||
{
|
||||
uint8_t newX = x;
|
||||
if (x > 15)
|
||||
newX = x % 16;
|
||||
if (y < 8)
|
||||
{
|
||||
nextv =
|
||||
(((100.0 - pcnt) * matrixValue[y][newX] + pcnt * matrixValue[y - 1][newX]) / 100.0) - pgm_read_byte(&(valueMask[y][newX]));
|
||||
|
||||
CRGB color = CHSV(
|
||||
HUE_ADD + pgm_read_byte(&(hueMask[y][newX])), // H
|
||||
255, // S
|
||||
(uint8_t)max(0, nextv) // V
|
||||
);
|
||||
|
||||
leds[getPixelNumber(x, y)] = color;
|
||||
}
|
||||
else if (y == 8 && SPARKLES)
|
||||
{
|
||||
if (random(0, 20) == 0 && getPixColorXY(x, y - 1) != 0)
|
||||
drawPixelXY(x, y, getPixColorXY(x, y - 1));
|
||||
else
|
||||
drawPixelXY(x, y, 0);
|
||||
}
|
||||
else if (SPARKLES)
|
||||
{
|
||||
|
||||
// старая версия для яркости
|
||||
if (getPixColorXY(x, y - 1) > 0)
|
||||
drawPixelXY(x, y, getPixColorXY(x, y - 1));
|
||||
else
|
||||
drawPixelXY(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first row interpolates with the "next" line
|
||||
for (unsigned char x = 0; x < WIDTH; x++)
|
||||
{
|
||||
uint8_t newX = x;
|
||||
if (x > 15)
|
||||
newX = x % 16;
|
||||
CRGB color = CHSV(
|
||||
HUE_ADD + pgm_read_byte(&(hueMask[0][newX])), // H
|
||||
255, // S
|
||||
(uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V
|
||||
);
|
||||
// leds[getPixelNumber(newX, 0)] = color; // На форуме пишут что это ошибка - вместо newX должно быть x, иначе
|
||||
leds[getPixelNumber(x, 0)] = color; // на матрицах шире 16 столбцов нижний правый угол неработает
|
||||
}
|
||||
}
|
||||
void fireRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
|
||||
loadingFlag = false;
|
||||
FastLED.clear();
|
||||
generateLine();
|
||||
memset(matrixValue, 0, sizeof(matrixValue));
|
||||
}
|
||||
if (pcnt >= 100)
|
||||
{
|
||||
shiftUp();
|
||||
generateLine();
|
||||
pcnt = 0;
|
||||
}
|
||||
drawFrame(pcnt);
|
||||
pcnt += 30;
|
||||
}
|
||||
|
||||
// **************** МАТРИЦА *****************
|
||||
void matrixRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
loadingFlag = false;
|
||||
|
||||
FastLED.clear();
|
||||
}
|
||||
for (byte x = 0; x < WIDTH; x++)
|
||||
{
|
||||
// заполняем случайно верхнюю строку
|
||||
uint32_t thisColor = getPixColorXY(x, HEIGHT - 1);
|
||||
if (thisColor == 0)
|
||||
drawPixelXY(x, HEIGHT - 1, 0x00FF00 * (random(0, 10) == 0));
|
||||
else if (thisColor < 0x002000)
|
||||
drawPixelXY(x, HEIGHT - 1, 0);
|
||||
else
|
||||
drawPixelXY(x, HEIGHT - 1, thisColor - 0x002000);
|
||||
}
|
||||
|
||||
// сдвигаем всё вниз
|
||||
for (byte x = 0; x < WIDTH; x++)
|
||||
{
|
||||
for (byte y = 0; y < HEIGHT - 1; y++)
|
||||
{
|
||||
drawPixelXY(x, y, getPixColorXY(x, y + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ********************* ЗВЕЗДОПАД ******************
|
||||
void fadePixel(byte i, byte j, byte step)
|
||||
{ // новый фейдер
|
||||
int pixelNum = getPixelNumber(i, j);
|
||||
if (getPixColor(pixelNum) == 0)
|
||||
return;
|
||||
|
||||
if (leds[pixelNum].r >= 30 ||
|
||||
leds[pixelNum].g >= 30 ||
|
||||
leds[pixelNum].b >= 30)
|
||||
{
|
||||
leds[pixelNum].fadeToBlackBy(step);
|
||||
}
|
||||
else
|
||||
{
|
||||
leds[pixelNum] = 0;
|
||||
}
|
||||
}
|
||||
// функция плавного угасания цвета для всех пикселей
|
||||
void fader(byte step)
|
||||
{
|
||||
for (byte i = 0; i < WIDTH; i++)
|
||||
{
|
||||
for (byte j = 0; j < HEIGHT; j++)
|
||||
{
|
||||
fadePixel(i, j, step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void starfallRoutine()
|
||||
{
|
||||
|
||||
// заполняем головами комет левую и верхнюю линию
|
||||
for (byte i = HEIGHT / 2; i < HEIGHT; i++)
|
||||
{
|
||||
if (getPixColorXY(0, i) == 0 && (random(0, STAR_DENSE) == 0) && getPixColorXY(0, i + 1) == 0 && getPixColorXY(0, i - 1) == 0)
|
||||
leds[getPixelNumber(0, i)] = CHSV(random(0, 200), SATURATION, 255);
|
||||
}
|
||||
for (byte i = 0; i < WIDTH / 2; i++)
|
||||
{
|
||||
if (getPixColorXY(i, HEIGHT - 1) == 0 && (random(0, STAR_DENSE) == 0) && getPixColorXY(i + 1, HEIGHT - 1) == 0 && getPixColorXY(i - 1, HEIGHT - 1) == 0)
|
||||
leds[getPixelNumber(i, HEIGHT - 1)] = CHSV(random(0, 200), SATURATION, 255);
|
||||
}
|
||||
|
||||
// сдвигаем по диагонали
|
||||
for (byte y = 0; y < HEIGHT - 1; y++)
|
||||
{
|
||||
for (byte x = WIDTH - 1; x > 0; x--)
|
||||
{
|
||||
drawPixelXY(x, y, getPixColorXY(x - 1, y + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// уменьшаем яркость левой и верхней линии, формируем "хвосты"
|
||||
for (byte i = HEIGHT / 2; i < HEIGHT; i++)
|
||||
{
|
||||
fadePixel(0, i, TAIL_STEP);
|
||||
}
|
||||
for (byte i = 0; i < WIDTH / 2; i++)
|
||||
{
|
||||
fadePixel(i, HEIGHT - 1, TAIL_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
// рандомные гаснущие вспышки
|
||||
void sparklesRoutine()
|
||||
{
|
||||
|
||||
for (byte i = 0; i < DENSE; i++)
|
||||
{
|
||||
byte x = random(0, WIDTH);
|
||||
byte y = random(0, HEIGHT);
|
||||
if (getPixColorXY(x, y) == 0)
|
||||
leds[getPixelNumber(x, y)] = CHSV(random(0, 255), 255, 255);
|
||||
}
|
||||
fader(BRIGHT_STEP);
|
||||
}
|
||||
|
||||
// ----------------------------- СВЕТЛЯКИ ------------------------------
|
||||
int lightersPos[2][LIGHTERS_AM];
|
||||
int8_t lightersSpeed[2][LIGHTERS_AM];
|
||||
CHSV lightersColor[LIGHTERS_AM];
|
||||
byte loopCounter;
|
||||
|
||||
int angle[LIGHTERS_AM];
|
||||
int speedV[LIGHTERS_AM];
|
||||
int8_t angleSpeed[LIGHTERS_AM];
|
||||
|
||||
void lightersRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
loadingFlag = false;
|
||||
randomSeed(millis());
|
||||
for (byte i = 0; i < LIGHTERS_AM; i++)
|
||||
{
|
||||
lightersPos[0][i] = random(0, WIDTH * 10);
|
||||
lightersPos[1][i] = random(0, HEIGHT * 10);
|
||||
lightersSpeed[0][i] = random(-10, 10);
|
||||
lightersSpeed[1][i] = random(-10, 10);
|
||||
lightersColor[i] = CHSV(random(0, 255), 255, 255);
|
||||
}
|
||||
}
|
||||
FastLED.clear();
|
||||
if (++loopCounter > 20)
|
||||
loopCounter = 0;
|
||||
for (byte i = 0; i < map(LIGHTERS_AM, 0, 255, 5, 150); i++)
|
||||
{
|
||||
if (loopCounter == 0)
|
||||
{ // меняем скорость каждые 255 отрисовок
|
||||
lightersSpeed[0][i] += random(-3, 4);
|
||||
lightersSpeed[1][i] += random(-3, 4);
|
||||
lightersSpeed[0][i] = constrain(lightersSpeed[0][i], -20, 20);
|
||||
lightersSpeed[1][i] = constrain(lightersSpeed[1][i], -20, 20);
|
||||
}
|
||||
|
||||
lightersPos[0][i] += lightersSpeed[0][i];
|
||||
lightersPos[1][i] += lightersSpeed[1][i];
|
||||
|
||||
if (lightersPos[0][i] < 0)
|
||||
lightersPos[0][i] = (WIDTH - 1) * 10;
|
||||
if (lightersPos[0][i] >= WIDTH * 10)
|
||||
lightersPos[0][i] = 0;
|
||||
|
||||
if (lightersPos[1][i] < 0)
|
||||
{
|
||||
lightersPos[1][i] = 0;
|
||||
lightersSpeed[1][i] = -lightersSpeed[1][i];
|
||||
}
|
||||
if (lightersPos[1][i] >= (HEIGHT - 1) * 10)
|
||||
{
|
||||
lightersPos[1][i] = (HEIGHT - 1) * 10;
|
||||
lightersSpeed[1][i] = -lightersSpeed[1][i];
|
||||
}
|
||||
drawPixelXY(lightersPos[0][i] / 10, lightersPos[1][i] / 10, lightersColor[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------- ПЕЙНТБОЛ -------------
|
||||
|
||||
void lightBallsRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
loadingFlag = false;
|
||||
|
||||
FastLED.clear(); // очистить
|
||||
dir_mx = WIDTH > HEIGHT ? 0 : 1; // 0 - квадратные сегменты расположены горизонтально, 1 - вертикально
|
||||
seg_num = dir_mx == 0 ? (WIDTH / HEIGHT) : (HEIGHT / WIDTH); // вычисляем количество сегментов, умещающихся на матрице
|
||||
seg_size = dir_mx == 0 ? HEIGHT : WIDTH; // Размер квадратного сегмента (высота и ширина равны)
|
||||
seg_offset = ((dir_mx == 0 ? WIDTH : HEIGHT) - seg_size * seg_num) / (seg_num + 1); // смещение от края матрицы и между сегментами
|
||||
BorderWidth = 0;
|
||||
}
|
||||
|
||||
// Apply some blurring to whatever's already on the matrix
|
||||
// Note that we never actually clear the matrix, we just constantly
|
||||
// blur it repeatedly. Since the blurring is 'lossy', there's
|
||||
// an automatic trend toward black -- by design.
|
||||
uint8_t blurAmount = dim8_raw(beatsin8(2, 64, 100));
|
||||
blur2d(leds, WIDTH, HEIGHT, blurAmount);
|
||||
|
||||
// The color of each point shifts over time, each at a different speed.
|
||||
uint32_t ms = millis();
|
||||
int16_t idx;
|
||||
|
||||
byte cnt = map(effectSpeed, 0, 255, 1, 4);
|
||||
|
||||
if (USE_SEGMENTS != 0)
|
||||
{
|
||||
// Для неквадратных - вычленяем квадратные сегменты, которые равномерно распределяем по ширине / высоте матрицы
|
||||
uint8_t i = beatsin8(91, 0, seg_size - BorderWidth - 1);
|
||||
uint8_t j = beatsin8(109, 0, seg_size - BorderWidth - 1);
|
||||
uint8_t k = beatsin8(73, 0, seg_size - BorderWidth - 1);
|
||||
uint8_t m = beatsin8(123, 0, seg_size - BorderWidth - 1);
|
||||
|
||||
uint8_t d1 = ms / 29;
|
||||
uint8_t d2 = ms / 41;
|
||||
uint8_t d3 = ms / 73;
|
||||
uint8_t d4 = ms / 97;
|
||||
|
||||
for (uint8_t ii = 0; ii < seg_num; ii++)
|
||||
{
|
||||
delay(0); // Для предотвращения ESP8266 Watchdog Timer
|
||||
uint8_t cx = dir_mx == 0 ? (seg_offset * (ii + 1) + seg_size * ii) : 0;
|
||||
uint8_t cy = dir_mx == 0 ? 0 : (seg_offset * (ii + 1) + seg_size * ii);
|
||||
uint8_t color_shift = ii * 50;
|
||||
if (cnt <= 1)
|
||||
{
|
||||
idx = XY(i + cx, j + cy);
|
||||
leds[idx] += CHSV(color_shift + d1, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 2)
|
||||
{
|
||||
idx = XY(j + cx, k + cy);
|
||||
leds[idx] += CHSV(color_shift + d2, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 3)
|
||||
{
|
||||
idx = XY(k + cx, m + cy);
|
||||
leds[idx] += CHSV(color_shift + d3, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 4)
|
||||
{
|
||||
idx = XY(m + cx, i + cy);
|
||||
leds[idx] += CHSV(color_shift + d4, 200U, 255U);
|
||||
}
|
||||
|
||||
// При соединении матрицы из угла вверх или вниз почему-то слева и справа узора остаются полосы, которые
|
||||
// не гаснут обычным blur - гасим полоски левой и правой стороны дополнительно.
|
||||
// При соединении из угла влево или вправо или на неквадратных матрицах такого эффекта не наблюдается
|
||||
for (byte i2 = cy; i2 < cy + seg_size; i2++)
|
||||
{
|
||||
fadePixel(cx + BorderWidth, i2, 15);
|
||||
fadePixel(cx + seg_size - BorderWidth - 1, i2, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t i = beatsin8(91, BorderWidth, WIDTH - BorderWidth - 1);
|
||||
uint8_t j = beatsin8(109, BorderWidth, HEIGHT - BorderWidth - 1);
|
||||
uint8_t k = beatsin8(73, BorderWidth, WIDTH - BorderWidth - 1);
|
||||
uint8_t m = beatsin8(123, BorderWidth, HEIGHT - BorderWidth - 1);
|
||||
|
||||
if (cnt <= 1)
|
||||
{
|
||||
idx = XY(i, j);
|
||||
leds[idx] += CHSV(ms / 29, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 2)
|
||||
{
|
||||
idx = XY(k, j);
|
||||
leds[idx] += CHSV(ms / 41, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 3)
|
||||
{
|
||||
idx = XY(k, m);
|
||||
leds[idx] += CHSV(ms / 73, 200U, 255U);
|
||||
}
|
||||
if (cnt <= 4)
|
||||
{
|
||||
idx = XY(i, m);
|
||||
leds[idx] += CHSV(ms / 97, 200U, 255U);
|
||||
}
|
||||
|
||||
if (WIDTH == HEIGHT)
|
||||
{
|
||||
// При соединении матрицы из угла вверх или вниз почему-то слева и справа узора остаются полосы, которые
|
||||
// не гаснут обычным blur - гасим полоски левой и правой стороны дополнительно.
|
||||
// При соединении из угла влево или вправо или на неквадратных матрицах такого эффекта не наблюдается
|
||||
for (byte i = 0; i < HEIGHT; i++)
|
||||
{
|
||||
fadePixel(0, i, 15);
|
||||
fadePixel(WIDTH - 1, i, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------- ВОДОВОРОТ -------------
|
||||
|
||||
void swirlRoutine()
|
||||
{
|
||||
if (loadingFlag)
|
||||
{
|
||||
loadingFlag = false;
|
||||
|
||||
FastLED.clear(); // очистить
|
||||
dir_mx = WIDTH > HEIGHT ? 0 : 1; // 0 - квадратные сегменты расположены горизонтально, 1 - вертикально
|
||||
seg_num = dir_mx == 0 ? (WIDTH / HEIGHT) : (HEIGHT / WIDTH); // вычисляем количество сегментов, умещающихся на матрице
|
||||
seg_size = dir_mx == 0 ? HEIGHT : WIDTH; // Размер квадратного сегмента (высота и ширина равны)
|
||||
seg_offset = ((dir_mx == 0 ? WIDTH : HEIGHT) - seg_size * seg_num) / (seg_num + 1); // смещение от края матрицы и между сегментами
|
||||
BorderWidth = seg_num == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
// Apply some blurring to whatever's already on the matrix
|
||||
// Note that we never actually clear the matrix, we just constantly
|
||||
// blur it repeatedly. Since the blurring is 'lossy', there's
|
||||
// an automatic trend toward black -- by design.
|
||||
uint8_t blurAmount = dim8_raw(beatsin8(2, 64, 100));
|
||||
blur2d(leds, WIDTH, HEIGHT, blurAmount);
|
||||
|
||||
uint32_t ms = millis();
|
||||
int16_t idx;
|
||||
|
||||
if (USE_SEGMENTS != 0)
|
||||
{
|
||||
// Use two out-of-sync sine waves
|
||||
uint8_t i = beatsin8(41, 0, seg_size - BorderWidth - 1);
|
||||
uint8_t j = beatsin8(27, 0, seg_size - BorderWidth - 1);
|
||||
|
||||
// Also calculate some reflections
|
||||
uint8_t ni = (seg_size - 1) - i;
|
||||
uint8_t nj = (seg_size - 1) - j;
|
||||
|
||||
uint8_t d1 = ms / 11;
|
||||
uint8_t d2 = ms / 13;
|
||||
uint8_t d3 = ms / 17;
|
||||
uint8_t d4 = ms / 29;
|
||||
uint8_t d5 = ms / 37;
|
||||
uint8_t d6 = ms / 41;
|
||||
|
||||
for (uint8_t ii = 0; ii < seg_num; ii++)
|
||||
{
|
||||
delay(0); // Для предотвращения ESP8266 Watchdog Timer
|
||||
uint8_t cx = dir_mx == 0 ? (seg_offset * (ii + 1) + seg_size * ii) : 0;
|
||||
uint8_t cy = dir_mx == 0 ? 0 : (seg_offset * (ii + 1) + seg_size * ii);
|
||||
uint8_t color_shift = ii * 50;
|
||||
|
||||
// The color of each point shifts over time, each at a different speed.
|
||||
idx = XY(i + cx, j + cy);
|
||||
leds[idx] += CHSV(color_shift + d1, 200, 192);
|
||||
idx = XY(ni + cx, nj + cy);
|
||||
leds[idx] += CHSV(color_shift + d2, 200, 192);
|
||||
idx = XY(i + cx, nj + cy);
|
||||
leds[idx] += CHSV(color_shift + d3, 200, 192);
|
||||
idx = XY(ni + cx, j + cy);
|
||||
leds[idx] += CHSV(color_shift + d4, 200, 192);
|
||||
idx = XY(j + cx, i + cy);
|
||||
leds[idx] += CHSV(color_shift + d5, 200, 192);
|
||||
idx = XY(nj + cx, ni + cy);
|
||||
leds[idx] += CHSV(color_shift + d6, 200, 192);
|
||||
|
||||
// При соединении матрицы из угла вверх или вниз почему-то слева и справа узора остаются полосы, которые
|
||||
// не гаснут обычным blur - гасим полоски левой и правой стороны дополнительно.
|
||||
// При соединении из угла влево или вправо или на неквадратных матрицах такого эффекта не наблюдается
|
||||
for (byte i2 = cy; i2 < cy + seg_size; i2++)
|
||||
{
|
||||
fadePixel(cx, i2, 15);
|
||||
fadePixel(cx + BorderWidth, i2, 15);
|
||||
fadePixel(cx + seg_size - 1, i2, 15);
|
||||
fadePixel(cx + seg_size - BorderWidth - 1, i2, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use two out-of-sync sine waves
|
||||
uint8_t i = beatsin8(41, BorderWidth, WIDTH - BorderWidth - 1);
|
||||
uint8_t j = beatsin8(27, BorderWidth, HEIGHT - BorderWidth - 1);
|
||||
|
||||
// Also calculate some reflections
|
||||
uint8_t ni = (WIDTH - 1) - i;
|
||||
uint8_t nj = (HEIGHT - 1) - j;
|
||||
|
||||
// The color of each point shifts over time, each at a different speed.
|
||||
idx = XY(i, j);
|
||||
leds[idx] += CHSV(ms / 11, 200, 192);
|
||||
idx = XY(ni, nj);
|
||||
leds[idx] += CHSV(ms / 13, 200, 192);
|
||||
idx = XY(i, nj);
|
||||
leds[idx] += CHSV(ms / 17, 200, 192);
|
||||
idx = XY(ni, j);
|
||||
leds[idx] += CHSV(ms / 29, 200, 192);
|
||||
|
||||
if (HEIGHT == WIDTH)
|
||||
{
|
||||
// для квадратных матриц - 6 точек создают более красивую картину
|
||||
idx = XY(j, i);
|
||||
leds[idx] += CHSV(ms / 37, 200, 192);
|
||||
idx = XY(nj, ni);
|
||||
leds[idx] += CHSV(ms / 41, 200, 192);
|
||||
|
||||
// При соединении матрицы из угла вверх или вниз почему-то слева и справа узора остаются полосы, которые
|
||||
// не гаснут обычным blur - гасим полоски левой и правой стороны дополнительно.
|
||||
// При соединении из угла влево или вправо или на неквадратных матрицах такого эффекта не наблюдается
|
||||
for (byte i = 0; i < HEIGHT; i++)
|
||||
{
|
||||
fadePixel(0, i, 15);
|
||||
fadePixel(WIDTH - 1, i, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t XY(uint8_t x, uint8_t y)
|
||||
{
|
||||
return getPixelNumber(x, y);
|
||||
}
|
||||
|
||||
//--------------------крутящаяся радуга матрица------------------
|
||||
|
||||
void rainbow_loop_matrix()
|
||||
{ //-m3-LOOP HSV RAINBOW
|
||||
idex++;
|
||||
ihue = ihue + thisstep;
|
||||
if (idex >= LED_COUNT)
|
||||
{
|
||||
idex = 0;
|
||||
}
|
||||
if (ihue > 255)
|
||||
{
|
||||
ihue = 0;
|
||||
}
|
||||
|
||||
for (byte i = 0; i < WIDTH; i++)
|
||||
{
|
||||
CHSV thisColor = CHSV(ihue, thissat, 255);
|
||||
for (byte j = 0; j < HEIGHT; j++)
|
||||
drawPixelXY(i, j, thisColor); // leds[getPixelNumber(i, j)] = thisColor;
|
||||
}
|
||||
LEDS.show();
|
||||
if (safeDelay(thisdelay))
|
||||
return;
|
||||
}
|
||||
40
src/modules/display/GyverLAMP/modinfo.json
Normal file
40
src/modules/display/GyverLAMP/modinfo.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"menuSection": "screens",
|
||||
"configItem": [
|
||||
{
|
||||
"global": 0,
|
||||
"name": "GyverLAMP",
|
||||
"type": "Reading",
|
||||
"subtype": "GyverLAMP",
|
||||
"id": "GyverLAMP",
|
||||
"widget": "range",
|
||||
"page": "Кнопки",
|
||||
"descr": "GyverLAMP",
|
||||
"needSave": 0,
|
||||
"brightness": "10",
|
||||
"speed": 30,
|
||||
"dalay": 10000
|
||||
}
|
||||
],
|
||||
"about": {
|
||||
"authorName": "",
|
||||
"authorContact": "",
|
||||
"authorGit": "",
|
||||
"exampleURL": "",
|
||||
"specialThanks": "",
|
||||
"moduleName": "GyverLAMP",
|
||||
"moduleVersion": "1",
|
||||
"moduleDesc": "xxx",
|
||||
"propInfo": {},
|
||||
"funcInfo": []
|
||||
},
|
||||
"defActive": false,
|
||||
"usedLibs": {
|
||||
"esp32*": [
|
||||
"fastled/FastLED@^3.5.0"
|
||||
],
|
||||
"esp82*": [
|
||||
"fastled/FastLED@^3.5.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
92
src/modules/display/GyverLAMP/utility.h
Normal file
92
src/modules/display/GyverLAMP/utility.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "config.h"
|
||||
#define MATRIX_TYPE 0
|
||||
// #define NUM_LEDS LED_COUNT
|
||||
|
||||
// **************** НАСТРОЙКА МАТРИЦЫ ****************
|
||||
#if (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 0)
|
||||
#define _WIDTH WIDTH
|
||||
#define THIS_X x
|
||||
#define THIS_Y y
|
||||
|
||||
#elif (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 1)
|
||||
#define _WIDTH HEIGHT
|
||||
#define THIS_X y
|
||||
#define THIS_Y x
|
||||
|
||||
#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 0)
|
||||
#define _WIDTH WIDTH
|
||||
#define THIS_X x
|
||||
#define THIS_Y (HEIGHT - y - 1)
|
||||
|
||||
#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 3)
|
||||
#define _WIDTH HEIGHT
|
||||
#define THIS_X (HEIGHT - y - 1)
|
||||
#define THIS_Y x
|
||||
|
||||
#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 2)
|
||||
#define _WIDTH WIDTH
|
||||
#define THIS_X (WIDTH - x - 1)
|
||||
#define THIS_Y (HEIGHT - y - 1)
|
||||
|
||||
#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 3)
|
||||
#define _WIDTH HEIGHT
|
||||
#define THIS_X (HEIGHT - y - 1)
|
||||
#define THIS_Y (WIDTH - x - 1)
|
||||
|
||||
#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 2)
|
||||
#define _WIDTH WIDTH
|
||||
#define THIS_X (WIDTH - x - 1)
|
||||
#define THIS_Y y
|
||||
|
||||
#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 1)
|
||||
#define _WIDTH HEIGHT
|
||||
#define THIS_X y
|
||||
#define THIS_Y (WIDTH - x - 1)
|
||||
|
||||
#else
|
||||
#define _WIDTH WIDTH
|
||||
#define THIS_X x
|
||||
#define THIS_Y y
|
||||
#pragma message "Wrong matrix parameters! Set to default"
|
||||
|
||||
#endif
|
||||
|
||||
// получить номер пикселя в ленте по координатам
|
||||
uint16_t getPixelNumber(int8_t x, int8_t y)
|
||||
{
|
||||
if ((THIS_Y % 2 == 0) || MATRIX_TYPE)
|
||||
{ // если чётная строка
|
||||
return (THIS_Y * _WIDTH + THIS_X);
|
||||
}
|
||||
else
|
||||
{ // если нечётная строка
|
||||
return (THIS_Y * _WIDTH + _WIDTH - THIS_X - 1);
|
||||
}
|
||||
}
|
||||
// функция отрисовки точки по координатам X Y
|
||||
void drawPixelXY(int8_t x, int8_t y, CRGB color)
|
||||
{
|
||||
|
||||
if (x < 0 || x > WIDTH - 1 || y < 0 || y > HEIGHT - 1)
|
||||
return;
|
||||
int thisPixel = getPixelNumber(x, y) * SEGMENTS;
|
||||
for (byte i = 0; i < SEGMENTS; i++)
|
||||
{
|
||||
leds[thisPixel + i] = color;
|
||||
}
|
||||
//FastLED.show();
|
||||
}
|
||||
// функция получения цвета пикселя по его номеру
|
||||
uint32_t getPixColor(int thisSegm)
|
||||
{
|
||||
int thisPixel = thisSegm * SEGMENTS;
|
||||
if (thisPixel < 0 || thisPixel > NUM_LEDS - 1)
|
||||
return 0;
|
||||
return (((uint32_t)leds[thisPixel].r << 16) | ((long)leds[thisPixel].g << 8) | (long)leds[thisPixel].b);
|
||||
}
|
||||
|
||||
// функция получения цвета пикселя в матрице по его координатам
|
||||
uint32_t getPixColorXY(int8_t x, int8_t y)
|
||||
{
|
||||
return getPixColor(getPixelNumber(x, y));
|
||||
}
|
||||
@@ -117,7 +117,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"defActive": true,
|
||||
"defActive": false,
|
||||
"usedLibs": {
|
||||
"esp32*": [
|
||||
"https://github.com/robotclass/RobotClass_LiquidCrystal_I2C",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,15 @@
|
||||
* @file NexUpload.h
|
||||
* The definition of class NexUpload.
|
||||
*
|
||||
* 1 - Removed all the Arduino code and replaced it by ESP-IDF
|
||||
* 2 - Removed hard-coded UART configuration, see ESPNexUpload constructor
|
||||
* 3 - Removed statusMessage and the function _printInfoLine
|
||||
* 4 - Removed call-back functionality
|
||||
* 5 - Removed one out of two upload functions
|
||||
* 6 - BugFix in upload function
|
||||
* @author Machiel Mastenbroek (machiel.mastenbroek@gmail.com)
|
||||
* @date 2022/08/14
|
||||
* @version 0.6.0
|
||||
*
|
||||
* 1 - BugFix when display baudrate is diffrent from initial ESP baudrate
|
||||
* 2 - Improved debug information
|
||||
@@ -52,25 +61,27 @@
|
||||
|
||||
#ifndef __ESPNEXUPLOAD_H__
|
||||
#define __ESPNEXUPLOAD_H__
|
||||
#include <functional>
|
||||
//#include <iostream>
|
||||
#include <string.h> /* printf, scanf, NULL */
|
||||
|
||||
//#include <inttypes.h>
|
||||
#include "esp_log.h"
|
||||
//#include "freertos/FreeRTOS.h"
|
||||
//#include "freertos/task.h"
|
||||
//#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
//#include "hal/uart_types.h"
|
||||
#include <Arduino.h>
|
||||
#include <StreamString.h>
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <SoftwareSerial.h>
|
||||
#else
|
||||
#include <HardwareSerial.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#endif
|
||||
#define CONFIG_NEX_UART_RECV_BUFFER_SIZE 256
|
||||
|
||||
/**
|
||||
* @addtogroup CoreAPI
|
||||
* @{
|
||||
*/
|
||||
|
||||
// callback template definition
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
|
||||
/**
|
||||
*
|
||||
* Provides the API for nextion to upload the ftf file.
|
||||
@@ -78,21 +89,18 @@ typedef std::function<void(void)> THandlerFunction;
|
||||
class ESPNexUpload
|
||||
{
|
||||
public: /* methods */
|
||||
// callback template definition
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param uint32_t upload_baudrate - set upload baudrate.
|
||||
*/
|
||||
ESPNexUpload(uint32_t upload_baudrate, int line, int rx, int tx);
|
||||
ESPNexUpload(uart_port_t uart_num, uint32_t baud_rate, gpio_num_t tx_io_num, gpio_num_t rx_io_num);
|
||||
|
||||
/**
|
||||
* destructor.
|
||||
*
|
||||
*/
|
||||
~ESPNexUpload() {}
|
||||
~ESPNexUpload(){}
|
||||
|
||||
/**
|
||||
* Connect to Nextion over serial
|
||||
@@ -106,14 +114,7 @@ public: /* methods */
|
||||
*
|
||||
* @return true if success, false for failure.
|
||||
*/
|
||||
bool prepareUpload(uint32_t file_size);
|
||||
|
||||
/**
|
||||
* set Update Progress Callback. (What to do during update progress)
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void setUpdateProgressCallback(THandlerFunction value);
|
||||
bool prepareUpload(uint32_t file_size, bool oldProt);
|
||||
|
||||
/**
|
||||
* start update tft file to nextion.
|
||||
@@ -124,32 +125,29 @@ public: /* methods */
|
||||
*/
|
||||
bool upload(const uint8_t *file_buf, size_t buf_size);
|
||||
|
||||
/**
|
||||
* start update tft file to nextion.
|
||||
*
|
||||
* @param Stream &myFile
|
||||
* @return true if success, false for failure.
|
||||
*/
|
||||
bool upload(Stream &myFile);
|
||||
|
||||
/**
|
||||
* Send reset command to Nextion over serial
|
||||
*
|
||||
* @return none.
|
||||
*/
|
||||
void softReset(void);
|
||||
void softReset(void);
|
||||
|
||||
/**
|
||||
* Send reset, end serial, reset _sent_packets & update status message
|
||||
*
|
||||
* @return none.
|
||||
*/
|
||||
void end(void);
|
||||
|
||||
public: /* data */
|
||||
String statusMessage = "";
|
||||
void end(void);
|
||||
|
||||
private: /* methods */
|
||||
/*
|
||||
* Semaphore construction to prevent double UART actions
|
||||
*
|
||||
*/
|
||||
void uart_mutex_lock(void) {do {} while (xSemaphoreTake(_upload_uart_lock, portMAX_DELAY) != pdPASS);};
|
||||
void uart_mutex_unlock(void) {xSemaphoreGive(_upload_uart_lock);};
|
||||
|
||||
/*
|
||||
* get communicate baudrate.
|
||||
*
|
||||
@@ -165,7 +163,7 @@ private: /* methods */
|
||||
*
|
||||
* @return true if success, false for failure.
|
||||
*/
|
||||
bool _searchBaudrate(uint32_t baudrate);
|
||||
bool _searchBaudrate(int baudrate);
|
||||
|
||||
/*
|
||||
* set download baudrate.
|
||||
@@ -179,65 +177,58 @@ private: /* methods */
|
||||
/*
|
||||
* set Nextion running mode.
|
||||
*
|
||||
* Undocumented feature of the Nextion protocol.
|
||||
* It's used by the 'upload to Nextion device' feature of the Nextion Editor V0.58
|
||||
*
|
||||
* The nextion display doesn't send any response
|
||||
*
|
||||
* Undocumented feature of the Nextion protocol.
|
||||
* It's used by the 'upload to Nextion device' feature of the Nextion Editor V0.58
|
||||
*
|
||||
* The nextion display doesn't send any response
|
||||
*
|
||||
*/
|
||||
void _setRunningMode(void);
|
||||
|
||||
/*
|
||||
* Test UART nextion connection availability
|
||||
*
|
||||
* @param input - echo string,
|
||||
*
|
||||
* @return true when the 'echo string' that is send is equal to the received string
|
||||
*
|
||||
* This test is used by the 'upload to Nextion device' feature of the Nextion Editor V0.58
|
||||
*
|
||||
* @param input - echo string,
|
||||
*
|
||||
* @return true when the 'echo string' that is send is equal to the received string
|
||||
*
|
||||
* This test is used by the 'upload to Nextion device' feature of the Nextion Editor V0.58
|
||||
*
|
||||
*/
|
||||
bool _echoTest(String input);
|
||||
bool _echoTest(std::string input);
|
||||
|
||||
/*
|
||||
* This function get the sleep and dim value from the Nextion display.
|
||||
*
|
||||
* If sleep = 1 meaning: sleep is enabled
|
||||
* If sleep = 1 meaning: sleep is enabled
|
||||
* action : sleep will be disabled
|
||||
* If dim = 0, meaning: the display backlight is turned off
|
||||
* action : dim will be set to 100 (percent)
|
||||
*
|
||||
* If dim = 0, meaning: the display backlight is turned off
|
||||
* action : dim will be set to 100 (percent)
|
||||
*
|
||||
*/
|
||||
bool _handlingSleepAndDim(void);
|
||||
|
||||
/*
|
||||
* This function (debug) print the Nextion response to a human readable string
|
||||
*
|
||||
* @param esp_request - true: request message from esp to nextion
|
||||
* false: response message from nextion to esp
|
||||
*
|
||||
* @param input - string to print
|
||||
*
|
||||
* @param esp_request - true: request message from esp to nextion
|
||||
* false: response message from nextion to esp
|
||||
*
|
||||
* @param input - string to print
|
||||
*
|
||||
*/
|
||||
void _printSerialData(bool esp_request, String input);
|
||||
|
||||
/*
|
||||
* This function print a prefix debug line
|
||||
*
|
||||
* @param line: optional debug/ info line
|
||||
*/
|
||||
void _printInfoLine(String line = "");
|
||||
void _printSerialData(bool esp_request, std::string input);
|
||||
|
||||
/*
|
||||
* Send command to Nextion.
|
||||
*
|
||||
* @param cmd - the string of command.
|
||||
* @param tail - end the string with tripple 0xFF byte
|
||||
* @param null_head - start the string with a single 0x00 byte
|
||||
* @param tail - end the string with tripple 0xFF byte
|
||||
* @param null_head - start the string with a single 0x00 byte
|
||||
*
|
||||
* @return none.
|
||||
*/
|
||||
void sendCommand(const char *cmd, bool tail = true, bool null_head = false);
|
||||
void sendCommand(const char* cmd, bool tail = true, bool null_head = false);
|
||||
|
||||
/*
|
||||
* Receive string data.
|
||||
@@ -249,7 +240,7 @@ private: /* methods */
|
||||
* @return the length of string buffer.
|
||||
*
|
||||
*/
|
||||
uint16_t recvRetString(String &string, uint32_t timeout = 500, bool recv_flag = false);
|
||||
uint16_t recvRetString(std::string &string, uint32_t timeout = 500,bool recv_flag = false);
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -261,25 +252,72 @@ private: /* methods */
|
||||
* @return time in us length of string buffer.
|
||||
*
|
||||
*/
|
||||
uint32_t calculateTransmissionTimeMs(String message);
|
||||
uint32_t calculateTransmissionTimeMs(std::string message);
|
||||
|
||||
void nexSerialBegin(uint32_t upload_baudrate, int line, int rx, int tx);
|
||||
/*
|
||||
* Setup UART for communication with display
|
||||
*
|
||||
* @param uart_num - UART number
|
||||
* @param baud_rate - baud rate speed
|
||||
* @param tx_io_num - GPIO TX pin
|
||||
* @param rx_io_num - GPIO RX pin
|
||||
*
|
||||
*/
|
||||
void setBaudrate(uart_port_t uart_num, uint32_t baud_rate, gpio_num_t tx_io_num, gpio_num_t rx_io_num);
|
||||
|
||||
private: /* data */
|
||||
uint32_t _baudrate; /* nextion serail baudrate */
|
||||
uint32_t _undownloadByte; /* undownload byte of tft file */
|
||||
uint32_t _upload_baudrate; /* upload baudrate */
|
||||
uint16_t _sent_packets = 0; /* upload baudrate */
|
||||
uint8_t _rx;
|
||||
uint8_t _tx;
|
||||
uint8_t _line;
|
||||
THandlerFunction _updateProgressCallback;
|
||||
/*
|
||||
* Check is UART is avaialble
|
||||
*/
|
||||
uint32_t uartAvailable();
|
||||
|
||||
#ifdef ESP8266
|
||||
SoftwareSerial* nexSerial;
|
||||
#else
|
||||
Stream* nexSerial;
|
||||
#endif
|
||||
/*
|
||||
* Read one RX byte
|
||||
*
|
||||
* @return one received UART byte
|
||||
*/
|
||||
uint8_t uartRead();
|
||||
|
||||
/*
|
||||
* Write one TX byte
|
||||
*
|
||||
* @param c - one byte
|
||||
*
|
||||
*/
|
||||
void uartWrite(uint8_t c);
|
||||
|
||||
/*
|
||||
* Write char string
|
||||
*
|
||||
* @param data - char string of data to send
|
||||
* @param len - length of the string
|
||||
*
|
||||
*/
|
||||
void uartWriteBuf(const char * data, size_t len);
|
||||
|
||||
/*
|
||||
* Clear TX UART buffer
|
||||
*/
|
||||
void uartFlushTxOnly();
|
||||
|
||||
private: /* data */
|
||||
bool _oldProtv11;
|
||||
uint32_t _baudrate; /* nextion serail baudrate */
|
||||
uint32_t _undownloadByte; /* undownload byte of tft file */
|
||||
uart_port_t _upload_uart_num; /* upload uart port number */
|
||||
uint32_t _upload_baudrate; /* upload baudrate */
|
||||
gpio_num_t _upload_tx_io_num; /* upload gpio TX */
|
||||
gpio_num_t _upload_rx_io_num; /* upload gpio RX */
|
||||
xSemaphoreHandle _upload_uart_lock; /* semaphore to prevent double UART actions */
|
||||
bool _upload_uart_has_peek; /* UART RX peek flag */
|
||||
uint8_t _upload_uart_peek_byte; /* UART RX peek byte */
|
||||
//uint16_t _sent_packets = 0; /* _sent_packets till 4096 bytes */
|
||||
uint32_t _sent_packets_total = 0; /* total number of uploaded display firmware bytes */
|
||||
bool _uart_diver_installed; /* flag, if true UART is installed */
|
||||
|
||||
std::string str_snprintf(const char *fmt, size_t len, ...);
|
||||
/// Format the byte array \p data of length \p len in pretty-printed, human-readable hex.
|
||||
std::string format_hex_pretty(const uint8_t *data, size_t length);
|
||||
static char format_hex_pretty_char(uint8_t v);
|
||||
};
|
||||
/**
|
||||
* @}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user