mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-04-08 18:19:25 +03:00
Merge pull request #1 from IoTManagerProject/platformio
Изменения от Юры
This commit is contained in:
45
.vscode/settings.json
vendored
45
.vscode/settings.json
vendored
@@ -18,6 +18,49 @@
|
|||||||
"bitset": "cpp",
|
"bitset": "cpp",
|
||||||
"chrono": "cpp",
|
"chrono": "cpp",
|
||||||
"algorithm": "cpp",
|
"algorithm": "cpp",
|
||||||
"random": "cpp"
|
"random": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"cerrno": "cpp",
|
||||||
|
"cfloat": "cpp",
|
||||||
|
"climits": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"ios": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"locale": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stack": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"cstdbool": "cpp",
|
||||||
|
"typeinfo": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
//Здесь хранятся все настройки прошивки
|
|
||||||
|
|
||||||
#define firmware_version "2.3.4"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Firmware settings
|
* Здесь хранятся все настройки прошивки
|
||||||
*/
|
*/
|
||||||
|
#define firmware_version "2.3.4"
|
||||||
|
#define NUM_BUTTONS 6
|
||||||
#define mb_4_of_memory 1
|
#define mb_4_of_memory 1
|
||||||
#define wifi_mqtt_reconnecting 20000
|
#define wifi_mqtt_reconnecting 20000
|
||||||
#define blink_pin 2
|
#define blink_pin 2
|
||||||
#define tank_level_times_to_send 10 //после скольки выстрелов делать отправку данных
|
#define tank_level_times_to_send 10 //после скольки выстрелов делать отправку данных
|
||||||
#define statistics_update 1000 * 60 * 60 * 2
|
#define statistics_update 1000 * 60 * 60 * 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optional
|
||||||
|
*/
|
||||||
//#define OTA_enable
|
//#define OTA_enable
|
||||||
//#define MDNS_enable
|
//#define MDNS_enable
|
||||||
//#define WS_enable
|
//#define WS_enable
|
||||||
|
|||||||
18
include/ESP32_Spec.h
Normal file
18
include/ESP32_Spec.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <AsyncUDP.h>
|
||||||
|
#include <ESP32Servo.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <HTTPUpdate.h>
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <analogWrite.h>
|
||||||
|
|
||||||
|
#ifdef MDNS_enable
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern AsyncUDP udp;
|
||||||
|
#endif
|
||||||
16
include/ESP8266_Spec.h
Normal file
16
include/ESP8266_Spec.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#include <ESP8266HTTPUpdateServer.h>
|
||||||
|
#include <ESP8266httpUpdate.h>
|
||||||
|
#include <Servo.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
#ifdef MDNS_enable
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern WiFiUDP Udp;
|
||||||
|
|
||||||
|
#endif
|
||||||
181
include/Global.h
181
include/Global.h
@@ -1,74 +1,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//=========ПОДКЛЮЧЕНИЕ ОБЩИХ БИБЛИОТЕК===============
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <Bounce2.h>
|
#include <ESP8266HTTPUpdateServer.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
extern AsyncWebServer server;
|
|
||||||
#include <Adafruit_BME280.h>
|
|
||||||
#include <Adafruit_BMP280.h>
|
|
||||||
#include <DHTesp.h>
|
|
||||||
#include <DallasTemperature.h>
|
|
||||||
#include <FS.h>
|
|
||||||
#include <OneWire.h>
|
|
||||||
#include <PubSubClient.h>
|
|
||||||
#include <SPIFFSEditor.h>
|
#include <SPIFFSEditor.h>
|
||||||
#include <StringCommand.h>
|
|
||||||
#include <TickerScheduler.h>
|
|
||||||
#include <UpTime.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "Consts.h"
|
#include "Consts.h"
|
||||||
|
#include "ESP32_Spec.h"
|
||||||
|
#include "ESP8266_Spec.h"
|
||||||
#include "GyverFilters.h"
|
#include "GyverFilters.h"
|
||||||
//==============ESP8266 БИБЛИОТЕКИ===============
|
#include "UptimeInterval.h"
|
||||||
#ifdef ESP8266
|
#include "Utils\JsonUtils.h"
|
||||||
#include <ESP8266HTTPClient.h>
|
#include "Utils\StringUtils.h"
|
||||||
#include <ESP8266HTTPUpdateServer.h>
|
#include "Utils\TimeUtils.h"
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESP8266httpUpdate.h>
|
|
||||||
ESP8266HTTPUpdateServer httpUpdater;
|
|
||||||
#include <WiFiUdp.h>
|
|
||||||
WiFiUDP Udp;
|
|
||||||
#include <Servo.h>
|
|
||||||
#ifdef MDNS_enable
|
|
||||||
#include <ESP8266mDNS.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
//==============ESP32 БИБЛИОТЕКИ===============
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#include <AsyncUDP.h>
|
|
||||||
#include <ESP32Servo.h>
|
|
||||||
#include <HTTPClient.h>
|
|
||||||
#include <HTTPUpdate.h>
|
|
||||||
#include <SPIFFS.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <analogWrite.h>
|
|
||||||
extern AsyncUDP udp;
|
|
||||||
#ifdef MDNS_enable
|
|
||||||
#include <ESPmDNS.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
//=========ПОДКЛЮЧЕНИЕ ОБЩИХ БИБЛИОТЕК===============
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Adafruit_BMP280.h>
|
||||||
|
#include <Bounce2.h>
|
||||||
|
#include <DHTesp.h>
|
||||||
|
#include <DallasTemperature.h>
|
||||||
|
#include <OneWire.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <StringCommand.h>
|
||||||
|
#include <TickerScheduler.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <time.h>
|
||||||
#ifdef OTA_enable
|
#ifdef OTA_enable
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Servo myServo1;
|
|
||||||
extern Servo myServo2;
|
|
||||||
|
|
||||||
//==============================Objects.h(без данных)==================================
|
|
||||||
|
|
||||||
#ifdef WS_enable
|
|
||||||
extern AsyncWebSocket ws;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//extern AsyncEventSource events;
|
|
||||||
|
|
||||||
extern TickerScheduler ts;
|
|
||||||
|
|
||||||
enum { ROUTER_SEARCHING,
|
enum { ROUTER_SEARCHING,
|
||||||
WIFI_MQTT_CONNECTION_CHECK,
|
WIFI_MQTT_CONNECTION_CHECK,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
@@ -88,51 +50,22 @@ enum { ROUTER_SEARCHING,
|
|||||||
UDP_DB,
|
UDP_DB,
|
||||||
TEST };
|
TEST };
|
||||||
|
|
||||||
extern WiFiClient espClient;
|
/*
|
||||||
|
* Global vars
|
||||||
|
*/
|
||||||
|
extern TickerScheduler ts;
|
||||||
|
|
||||||
|
#ifdef WS_enable
|
||||||
|
extern AsyncWebSocket ws;
|
||||||
|
//extern AsyncEventSource events;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern PubSubClient client_mqtt;
|
extern PubSubClient client_mqtt;
|
||||||
|
|
||||||
extern StringCommand sCmd;
|
extern StringCommand sCmd;
|
||||||
|
|
||||||
extern AsyncWebServer server;
|
extern AsyncWebServer server;
|
||||||
|
|
||||||
//AsyncWebSocket ws;
|
|
||||||
|
|
||||||
//AsyncEventSource events;
|
|
||||||
|
|
||||||
#define NUM_BUTTONS 6
|
|
||||||
extern boolean but[NUM_BUTTONS];
|
|
||||||
extern Bounce *buttons;
|
|
||||||
|
|
||||||
extern GMedian<10, int> medianFilter;
|
|
||||||
|
|
||||||
extern OneWire *oneWire;
|
|
||||||
extern DallasTemperature sensors;
|
extern DallasTemperature sensors;
|
||||||
|
|
||||||
extern DHTesp dht;
|
|
||||||
|
|
||||||
extern Adafruit_BMP280 bmp;
|
|
||||||
extern Adafruit_Sensor *bmp_temp;
|
|
||||||
extern Adafruit_Sensor *bmp_pressure;
|
|
||||||
|
|
||||||
extern Adafruit_BME280 bme;
|
|
||||||
extern Adafruit_Sensor *bme_temp;
|
|
||||||
extern Adafruit_Sensor *bme_pressure;
|
|
||||||
extern Adafruit_Sensor *bme_humidity;
|
|
||||||
|
|
||||||
extern uptime_interval myUpTime;
|
|
||||||
|
|
||||||
///////////////////////////////////// Global vars ////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern boolean udp_busy;
|
|
||||||
extern unsigned int udp_port;
|
|
||||||
extern IPAddress udp_multicastIP;
|
|
||||||
extern String received_ip;
|
|
||||||
extern String received_udp_line;
|
|
||||||
extern int udp_period;
|
|
||||||
|
|
||||||
extern boolean just_load;
|
extern boolean just_load;
|
||||||
extern const char *hostName;
|
|
||||||
|
|
||||||
extern String configSetupJson; //все настройки
|
extern String configSetupJson; //все настройки
|
||||||
extern String configLiveJson; //все данные с датчиков (связан с mqtt)
|
extern String configLiveJson; //все данные с датчиков (связан с mqtt)
|
||||||
@@ -164,13 +97,8 @@ extern String bme280A_value_name;
|
|||||||
extern String logging_value_names_list;
|
extern String logging_value_names_list;
|
||||||
extern int enter_to_logging_counter;
|
extern int enter_to_logging_counter;
|
||||||
|
|
||||||
extern String current_time;
|
|
||||||
|
|
||||||
extern int scenario_line_status[40];
|
extern int scenario_line_status[40];
|
||||||
|
|
||||||
extern int wifi_lost_error;
|
|
||||||
extern int mqtt_lost_error;
|
|
||||||
|
|
||||||
extern String last_version;
|
extern String last_version;
|
||||||
|
|
||||||
extern boolean upgrade_url;
|
extern boolean upgrade_url;
|
||||||
@@ -182,24 +110,9 @@ extern boolean i2c_scanning;
|
|||||||
|
|
||||||
extern int sensors_reading_map[15];
|
extern int sensors_reading_map[15];
|
||||||
|
|
||||||
///////////////////////////////////// Functions////////////////////////////////////////////////////////////////////
|
/*
|
||||||
|
* Global functions
|
||||||
// StringUtils
|
*/
|
||||||
extern uint8_t hexStringToUint8(String hex);
|
|
||||||
extern uint16_t hexStringToUint16(String hex);
|
|
||||||
extern String selectToMarkerLast(String str, String found);
|
|
||||||
extern String selectToMarker(String str, String found);
|
|
||||||
extern String deleteAfterDelimiter(String str, String found);
|
|
||||||
extern String deleteBeforeDelimiter(String str, String found);
|
|
||||||
extern String deleteBeforeDelimiterTo(String str, String found);
|
|
||||||
extern String selectFromMarkerToMarker(String str, String found, int number);
|
|
||||||
|
|
||||||
// JsonUtils
|
|
||||||
extern String jsonReadStr(String &json, String name);
|
|
||||||
extern int jsonReadInt(String &json, String name);
|
|
||||||
extern String jsonWriteInt(String &json, String name, int volume);
|
|
||||||
extern String jsonWriteStr(String &json, String name, String volume);
|
|
||||||
extern String jsonWriteFloat(String &json, String name, float volume);
|
|
||||||
|
|
||||||
// Cmd
|
// Cmd
|
||||||
extern void CMD_init();
|
extern void CMD_init();
|
||||||
@@ -256,7 +169,7 @@ extern void clean_log_date();
|
|||||||
extern void choose_log_date_and_send();
|
extern void choose_log_date_and_send();
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
void getMemoryLoad(String text);
|
extern void getMemoryLoad(String text);
|
||||||
extern void saveConfig();
|
extern void saveConfig();
|
||||||
extern String getURL(const String &urls);
|
extern String getURL(const String &urls);
|
||||||
|
|
||||||
@@ -292,7 +205,6 @@ extern void eventGen(String event_name, String number);
|
|||||||
extern String add_set(String param_name);
|
extern String add_set(String param_name);
|
||||||
|
|
||||||
//Sensors
|
//Sensors
|
||||||
// И как раз тут хорошо просто в Sensors.h это пихать - а не в один здоровенный ФАЙЛ
|
|
||||||
extern void sensors_init();
|
extern void sensors_init();
|
||||||
|
|
||||||
extern void levelPr();
|
extern void levelPr();
|
||||||
@@ -340,40 +252,27 @@ extern void timerStop_();
|
|||||||
extern void delTimer(String number);
|
extern void delTimer(String number);
|
||||||
extern int readTimer(int number);
|
extern int readTimer(int number);
|
||||||
|
|
||||||
//TimeUtils
|
|
||||||
extern void Time_Init();
|
|
||||||
extern int timeToMin(String Time);
|
|
||||||
extern String GetDataDigital();
|
|
||||||
extern String GetDate();
|
|
||||||
extern String GetTimeWOsec();
|
|
||||||
extern String GetTime();
|
|
||||||
extern String GetTimeUnix();
|
|
||||||
extern void reconfigTime();
|
|
||||||
extern void saveConfig();
|
|
||||||
extern String GetTimeUnix();
|
|
||||||
extern void time_check();
|
|
||||||
|
|
||||||
//Upgrade
|
//Upgrade
|
||||||
extern void initUpgrade();
|
extern void initUpgrade();
|
||||||
|
|
||||||
//widget
|
// widget
|
||||||
extern void createWidget(String widget_name, String page_name, String page_number, String file, String topic);
|
extern void createWidget(String widget_name, String page_name, String page_number, String file, String topic);
|
||||||
extern void createWidgetParam(String widget_name, String page_name, String page_number, String file, String topic, String name1, String param1, String name2, String param2, String name3, String param3);
|
extern void createWidgetParam(String widget_name, String page_name, String page_number, String file, String topic, String name1, String param1, String name2, String param2, String name3, String param3);
|
||||||
extern void choose_widget_and_create(String widget_name, String page_name, String page_number, String type, String topik);
|
extern void choose_widget_and_create(String widget_name, String page_name, String page_number, String type, String topik);
|
||||||
extern void createChart(String widget_name, String page_name, String page_number, String file, String topic, String maxCount);
|
extern void createChart(String widget_name, String page_name, String page_number, String file, String topic, String maxCount);
|
||||||
|
|
||||||
// Push
|
// PushingBox
|
||||||
extern void Push_init();
|
extern void pushControl();
|
||||||
|
|
||||||
// UDP
|
// UDP
|
||||||
extern void UDP_init();
|
extern void UDP_init();
|
||||||
extern void do_udp_data_parse();
|
extern void do_udp_data_parse();
|
||||||
extern void do_mqtt_send_settings_to_udp();
|
extern void do_mqtt_send_settings_to_udp();
|
||||||
|
|
||||||
// WebServer
|
// WebServer
|
||||||
extern void Web_server_init();
|
extern void Web_server_init();
|
||||||
|
|
||||||
//iot_firmware
|
// iot_firmware
|
||||||
extern void not_async_actions();
|
|
||||||
extern void handleCMD_loop();
|
extern void handleCMD_loop();
|
||||||
extern void handleButton();
|
extern void handleButton();
|
||||||
extern void handleScenario();
|
extern void handleScenario();
|
||||||
@@ -381,8 +280,8 @@ extern void handleUdp();
|
|||||||
extern void do_upgrade_url();
|
extern void do_upgrade_url();
|
||||||
extern void do_upgrade();
|
extern void do_upgrade();
|
||||||
|
|
||||||
//uptime
|
// Init
|
||||||
extern void handle_uptime();
|
|
||||||
extern void handle_statistics();
|
|
||||||
extern void uptime_init();
|
extern void uptime_init();
|
||||||
|
|
||||||
|
// Web
|
||||||
extern void web_init();
|
extern void web_init();
|
||||||
32
include/UptimeInterval.h
Normal file
32
include/UptimeInterval.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class UptimeInterval {
|
||||||
|
public:
|
||||||
|
UptimeInterval(unsigned long interval, boolean postpone = true) : _interval{interval} {
|
||||||
|
reset(postpone);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean check() {
|
||||||
|
if (_next <= get()) {
|
||||||
|
_next += _interval;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(bool postpone = true) {
|
||||||
|
_next = (postpone ? _uptime_seconds + _interval : _uptime_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long get() {
|
||||||
|
unsigned long _uptime_seconds = millis() / 1000;
|
||||||
|
return _uptime_seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned long _uptime_seconds;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long _interval, _next;
|
||||||
|
};
|
||||||
13
include/Utils/JsonUtils.h
Normal file
13
include/Utils/JsonUtils.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
String jsonReadStr(String& json, String name);
|
||||||
|
|
||||||
|
int jsonReadInt(String& json, String name);
|
||||||
|
|
||||||
|
String jsonWriteStr(String& json, String name, String volume);
|
||||||
|
|
||||||
|
String jsonWriteInt(String& json, String name, int volume);
|
||||||
|
|
||||||
|
String jsonWriteFloat(String& json, String name, float volume);
|
||||||
19
include/Utils/StringUtils.h
Normal file
19
include/Utils/StringUtils.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
uint8_t hexStringToUint8(String hex);
|
||||||
|
|
||||||
|
uint16_t hexStringToUint16(String hex);
|
||||||
|
|
||||||
|
String selectToMarkerLast(String str, String found);
|
||||||
|
|
||||||
|
String selectToMarker(String str, String found);
|
||||||
|
|
||||||
|
String deleteAfterDelimiter(String str, String found);
|
||||||
|
|
||||||
|
String deleteBeforeDelimiter(String str, String found);
|
||||||
|
|
||||||
|
String deleteBeforeDelimiterTo(String str, String found);
|
||||||
|
|
||||||
|
String selectFromMarkerToMarker(String str, String found, int number);
|
||||||
26
include/Utils/TimeUtils.h
Normal file
26
include/Utils/TimeUtils.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
void Time_Init();
|
||||||
|
|
||||||
|
void time_check();
|
||||||
|
|
||||||
|
void reconfigTime();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Получение текущего времени
|
||||||
|
*/
|
||||||
|
String GetTime();
|
||||||
|
|
||||||
|
String GetTimeUnix();
|
||||||
|
|
||||||
|
String GetTimeWOsec();
|
||||||
|
|
||||||
|
String GetDate();
|
||||||
|
|
||||||
|
String GetDataDigital();
|
||||||
|
|
||||||
|
int timeToMin(String Time);
|
||||||
|
|
||||||
|
const String prettyMillis(unsigned long time_ms = millis());
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
0.01 2019-01-14
|
|
||||||
- initial version
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
all: README examples/UpTime_tick/README examples/UpTime_synopsis/README
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f README README.bak \
|
|
||||||
examples/UpTime_tick/README examples/UpTime_tick/README.bak \
|
|
||||||
examples/UpTime_synopsis/README examples/UpTime_synopsis/README.bak
|
|
||||||
|
|
||||||
README: UpTime.h
|
|
||||||
pod2readme $< $@ && rm -f $@.bak
|
|
||||||
|
|
||||||
examples/UpTime_tick/README: examples/UpTime_tick/UpTime_tick.ino
|
|
||||||
pod2readme $< $@ && rm -f $@.bak
|
|
||||||
|
|
||||||
examples/UpTime_synopsis/README: examples/UpTime_synopsis/UpTime_synopsis.ino
|
|
||||||
pod2readme $< $@ && rm -f $@.bak
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
NAME
|
|
||||||
|
|
||||||
UpTime.h - Arduino uptime and events in seconds
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <UpTime.h> // https://github.com/jozef/Arduino-UpTime
|
|
||||||
|
|
||||||
uptime_interval fire2(2);
|
|
||||||
uptime_interval fire5(5,UPTIME_RIGHT_AWAY);
|
|
||||||
|
|
||||||
void setup () {
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop () {
|
|
||||||
Serial.println("uptime: "+uptime_as_string()+" or "+uptime()+"s");
|
|
||||||
if (fire2.check()) Serial.println("2s elapsed");
|
|
||||||
if (fire5.check()) Serial.println("5s elapsed");
|
|
||||||
delay(1400);
|
|
||||||
}
|
|
||||||
|
|
||||||
will output:
|
|
||||||
|
|
||||||
uptime: 00:00:00 or 0s
|
|
||||||
5s elapsed
|
|
||||||
uptime: 00:00:01 or 1s
|
|
||||||
uptime: 00:00:02 or 2s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:04 or 4s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:05 or 5s
|
|
||||||
5s elapsed
|
|
||||||
uptime: 00:00:07 or 7s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:08 or 8s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:09 or 9s
|
|
||||||
uptime: 00:00:11 or 11s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
…
|
|
||||||
uptime: 04:41:23 or 16883s
|
|
||||||
uptime: 04:41:25 or 16885s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
uptime: 04:41:26 or 16886s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 04:41:28 or 16888s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 04:41:29 or 16889s
|
|
||||||
uptime: 04:41:30 or 16890s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
|
|
||||||
Uptime class is made to to track uptime of Arduino in seconds. The
|
|
||||||
uptime() or check() functions has to be called at least once for 0xFFFF
|
|
||||||
seconds (once in 18h) to work. Seconds will be counted even after
|
|
||||||
Arduinos millis() overrun and the seconds of unsigned long are enough
|
|
||||||
to not overrun sooner then in 136+ years. Once 0xFFFF0000 seconds is
|
|
||||||
elapsed, will trigger reset so that Arduino program clearly starts all
|
|
||||||
over again.
|
|
||||||
|
|
||||||
METHODS
|
|
||||||
|
|
||||||
bool check()
|
|
||||||
|
|
||||||
Returns true/false if the interval elapset.
|
|
||||||
|
|
||||||
void reset(bool postpone = true)
|
|
||||||
|
|
||||||
Will reset the time to count from current moment in until interval. If
|
|
||||||
postpone is set to false, check() will return true with next call.
|
|
||||||
|
|
||||||
INSTALL
|
|
||||||
|
|
||||||
git clone https://github.com/jozef/Arduino-UpTime sketchbook/libraries/UpTime
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
|
|
||||||
examples/UpTime_tick/UpTime_synopsis.ino
|
|
||||||
|
|
||||||
synopsis section example
|
|
||||||
|
|
||||||
examples/UpTime_tick/UpTime_tick.ino
|
|
||||||
|
|
||||||
print formatted and raw uptime in seconds und 4x interval
|
|
||||||
|
|
||||||
LICENSE
|
|
||||||
|
|
||||||
This is free software, licensed under the MIT License.
|
|
||||||
|
|
||||||
AUTHOR
|
|
||||||
|
|
||||||
Jozef Kutej
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* see UpTime.h */
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <UpTime.h>
|
|
||||||
|
|
||||||
unsigned long _uptime_seconds = 0;
|
|
||||||
void (*time_to_die)(void) = 0; // reset Arduino after 136+ years
|
|
||||||
|
|
||||||
unsigned long uptime() {
|
|
||||||
unsigned int cur_second = millis() / 1000;
|
|
||||||
unsigned int _uptime_seconds_uint = _uptime_seconds;
|
|
||||||
|
|
||||||
while (_uptime_seconds_uint != cur_second) {
|
|
||||||
_uptime_seconds++;
|
|
||||||
_uptime_seconds_uint++;
|
|
||||||
if (_uptime_seconds > 0xFFFF0000) time_to_die();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _uptime_seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
uptime_interval::uptime_interval(unsigned int inte, bool postpone) : interval(inte) {
|
|
||||||
reset(postpone);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uptime_interval::check() {
|
|
||||||
if (next <= uptime()) {
|
|
||||||
next += interval;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uptime_interval::reset(bool postpone) {
|
|
||||||
next = (postpone ? _uptime_seconds + interval : _uptime_seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _uptime_two_dig(uint8_t x) {
|
|
||||||
if (x > 9) {
|
|
||||||
return String(x);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "0"+String(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String uptime_as_string() {
|
|
||||||
unsigned long tmp_uptime = uptime();
|
|
||||||
unsigned long seconds;
|
|
||||||
unsigned long minutes;
|
|
||||||
unsigned long hours;
|
|
||||||
unsigned long days;
|
|
||||||
seconds = tmp_uptime % 60;
|
|
||||||
tmp_uptime = tmp_uptime / 60;
|
|
||||||
|
|
||||||
minutes = tmp_uptime % 60;
|
|
||||||
tmp_uptime = tmp_uptime / 60;
|
|
||||||
hours = tmp_uptime % 24;
|
|
||||||
days = tmp_uptime / 24;
|
|
||||||
|
|
||||||
return (days ? String(days)+'d'+' ' : "")
|
|
||||||
+ _uptime_two_dig(hours)
|
|
||||||
+ ':' + _uptime_two_dig(minutes)
|
|
||||||
+ ':' + _uptime_two_dig(seconds);
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
/* VERSION 0.01; 14.1.2019; see below for description and documentation */
|
|
||||||
#ifndef UpTime_h
|
|
||||||
#define UpTime_h
|
|
||||||
|
|
||||||
#define UPTIME_RIGHT_AWAY false
|
|
||||||
|
|
||||||
unsigned long uptime();
|
|
||||||
String uptime_as_string();
|
|
||||||
|
|
||||||
class uptime_interval {
|
|
||||||
private:
|
|
||||||
unsigned long next;
|
|
||||||
unsigned int interval;
|
|
||||||
public:
|
|
||||||
uptime_interval(unsigned int inte, bool postpone = true);
|
|
||||||
bool check();
|
|
||||||
void reset(bool postpone = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
UpTime.h - Arduino uptime and events in seconds
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <UpTime.h> // https://github.com/jozef/Arduino-UpTime
|
|
||||||
|
|
||||||
uptime_interval fire2(2);
|
|
||||||
uptime_interval fire5(5,UPTIME_RIGHT_AWAY);
|
|
||||||
|
|
||||||
void setup () {
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop () {
|
|
||||||
Serial.println("uptime: "+uptime_as_string()+" or "+uptime()+"s");
|
|
||||||
if (fire2.check()) Serial.println("2s elapsed");
|
|
||||||
if (fire5.check()) Serial.println("5s elapsed");
|
|
||||||
delay(1400);
|
|
||||||
}
|
|
||||||
|
|
||||||
will output:
|
|
||||||
|
|
||||||
uptime: 00:00:00 or 0s
|
|
||||||
5s elapsed
|
|
||||||
uptime: 00:00:01 or 1s
|
|
||||||
uptime: 00:00:02 or 2s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:04 or 4s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:05 or 5s
|
|
||||||
5s elapsed
|
|
||||||
uptime: 00:00:07 or 7s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:08 or 8s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 00:00:09 or 9s
|
|
||||||
uptime: 00:00:11 or 11s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
…
|
|
||||||
uptime: 04:41:23 or 16883s
|
|
||||||
uptime: 04:41:25 or 16885s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
uptime: 04:41:26 or 16886s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 04:41:28 or 16888s
|
|
||||||
2s elapsed
|
|
||||||
uptime: 04:41:29 or 16889s
|
|
||||||
uptime: 04:41:30 or 16890s
|
|
||||||
2s elapsed
|
|
||||||
5s elapsed
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Uptime class is made to to track uptime of Arduino in seconds. The uptime()
|
|
||||||
or check() functions has to be called at least once for 0xFFFF seconds
|
|
||||||
(once in 18h) to work. Seconds will be counted even after Arduinos
|
|
||||||
millis() overrun and the seconds of unsigned long are enough to not overrun
|
|
||||||
sooner then in 136+ years. Once 0xFFFF0000 seconds is elapsed, will trigger
|
|
||||||
reset so that Arduino program clearly starts all over again.
|
|
||||||
|
|
||||||
=head1 METHODS
|
|
||||||
|
|
||||||
=head2 bool check()
|
|
||||||
|
|
||||||
Returns true/false if the interval elapset.
|
|
||||||
|
|
||||||
=head2 void reset(bool postpone = true)
|
|
||||||
|
|
||||||
Will reset the time to count from current moment in until interval. If
|
|
||||||
C<postpone> is set to false, check() will return true with next call.
|
|
||||||
|
|
||||||
=head1 INSTALL
|
|
||||||
|
|
||||||
git clone https://github.com/jozef/Arduino-UpTime sketchbook/libraries/UpTime
|
|
||||||
|
|
||||||
=head1 EXAMPLES
|
|
||||||
|
|
||||||
=head2 examples/UpTime_tick/UpTime_synopsis.ino
|
|
||||||
|
|
||||||
synopsis section example
|
|
||||||
|
|
||||||
=head2 examples/UpTime_tick/UpTime_tick.ino
|
|
||||||
|
|
||||||
print formatted and raw uptime in seconds und 4x interval
|
|
||||||
|
|
||||||
=head1 LICENSE
|
|
||||||
|
|
||||||
This is free software, licensed under the MIT License.
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Jozef Kutej
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
DESCRIPTION
|
|
||||||
|
|
||||||
synopsis section example from UpTime.h
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
synopsis section example from UpTime.h
|
|
||||||
|
|
||||||
=cut
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <UpTime.h> // https://github.com/jozef/Arduino-UpTime
|
|
||||||
|
|
||||||
uptime_interval fire2(2);
|
|
||||||
uptime_interval fire5(5,UPTIME_RIGHT_AWAY);
|
|
||||||
|
|
||||||
void setup () {
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop () {
|
|
||||||
Serial.println("uptime: "+uptime_as_string()+" or "+uptime()+"s");
|
|
||||||
if (fire2.check()) Serial.println("2s elapsed");
|
|
||||||
if (fire5.check()) Serial.println("5s elapsed");
|
|
||||||
delay(1400);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
NAME
|
|
||||||
|
|
||||||
UpTime_tick.ino - print formatted and raw uptime in seconds und 4x
|
|
||||||
interval
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
|
|
||||||
On serial port will print current uptime in seconds with 4 interval
|
|
||||||
checks. Each loop has random 0-5s delay. Intervals will be printed once
|
|
||||||
elapsed.
|
|
||||||
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
UpTime_tick.ino - print formatted and raw uptime in seconds und 4x interval
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
On serial port will print current uptime in seconds with 4 interval checks.
|
|
||||||
Each loop has random 0-5s delay. Intervals will be printed once elapsed.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <UpTime.h> // https://github.com/jozef/Arduino-UpTime
|
|
||||||
|
|
||||||
uptime_interval fire2(2);
|
|
||||||
uptime_interval fire5(5);
|
|
||||||
uptime_interval fire10(10, UPTIME_RIGHT_AWAY);
|
|
||||||
uptime_interval fire60(60, UPTIME_RIGHT_AWAY);
|
|
||||||
|
|
||||||
void setup () {
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (Serial.available()) { Serial.read(); }
|
|
||||||
randomSeed(analogRead(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop () {
|
|
||||||
Serial.print("uptime: ");
|
|
||||||
Serial.println(uptime_as_string());
|
|
||||||
|
|
||||||
if (fire2.check()) {
|
|
||||||
Serial.println("fire 2s");
|
|
||||||
}
|
|
||||||
if (fire5.check()) {
|
|
||||||
Serial.println("fire 5s");
|
|
||||||
}
|
|
||||||
if (fire10.check()) {
|
|
||||||
Serial.println("fire 10s");
|
|
||||||
}
|
|
||||||
if (fire60.check()) {
|
|
||||||
Serial.println("fire 60s");
|
|
||||||
}
|
|
||||||
|
|
||||||
int rand_delay = random(5000);
|
|
||||||
Serial.print("delay(");
|
|
||||||
Serial.print(rand_delay);
|
|
||||||
Serial.println(")");
|
|
||||||
delay(rand_delay);
|
|
||||||
}
|
|
||||||
36
lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh
vendored
Normal file
36
lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export ARDUINO_ESP32_PATH="$ARDUINO_USR_PATH/hardware/espressif/esp32"
|
||||||
|
if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
|
||||||
|
echo "Installing ESP32 Arduino Core ..."
|
||||||
|
script_init_path="$PWD"
|
||||||
|
mkdir -p "$ARDUINO_USR_PATH/hardware/espressif"
|
||||||
|
cd "$ARDUINO_USR_PATH/hardware/espressif"
|
||||||
|
|
||||||
|
echo "Installing Python Serial ..."
|
||||||
|
pip install pyserial > /dev/null
|
||||||
|
|
||||||
|
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||||
|
echo "Installing Python Requests ..."
|
||||||
|
pip install requests > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
|
||||||
|
echo "Linking Core..."
|
||||||
|
ln -s $GITHUB_WORKSPACE esp32
|
||||||
|
else
|
||||||
|
echo "Cloning Core Repository..."
|
||||||
|
git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updating Submodules ..."
|
||||||
|
cd esp32
|
||||||
|
git submodule update --init --recursive > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Installing Platform Tools ..."
|
||||||
|
cd tools && python get.py
|
||||||
|
cd $script_init_path
|
||||||
|
|
||||||
|
echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
29
lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh
vendored
Normal file
29
lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Installing ESP8266 Arduino Core ..."
|
||||||
|
script_init_path="$PWD"
|
||||||
|
mkdir -p "$ARDUINO_USR_PATH/hardware/esp8266com"
|
||||||
|
cd "$ARDUINO_USR_PATH/hardware/esp8266com"
|
||||||
|
|
||||||
|
echo "Installing Python Serial ..."
|
||||||
|
pip install pyserial > /dev/null
|
||||||
|
|
||||||
|
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||||
|
echo "Installing Python Requests ..."
|
||||||
|
pip install requests > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Cloning Core Repository ..."
|
||||||
|
git clone https://github.com/esp8266/Arduino.git esp8266 > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Updating submodules ..."
|
||||||
|
cd esp8266
|
||||||
|
git submodule update --init --recursive > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Installing Platform Tools ..."
|
||||||
|
cd tools
|
||||||
|
python get.py > /dev/null
|
||||||
|
cd $script_init_path
|
||||||
|
|
||||||
|
echo "ESP8266 Arduino has been installed in '$ARDUINO_USR_PATH/hardware/esp8266com'"
|
||||||
|
echo ""
|
||||||
228
lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh
vendored
Normal file
228
lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh
vendored
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#OSTYPE: 'linux-gnu', ARCH: 'x86_64' => linux64
|
||||||
|
#OSTYPE: 'msys', ARCH: 'x86_64' => win32
|
||||||
|
#OSTYPE: 'darwin18', ARCH: 'i386' => macos
|
||||||
|
|
||||||
|
OSBITS=`arch`
|
||||||
|
if [[ "$OSTYPE" == "linux"* ]]; then
|
||||||
|
export OS_IS_LINUX="1"
|
||||||
|
ARCHIVE_FORMAT="tar.xz"
|
||||||
|
if [[ "$OSBITS" == "i686" ]]; then
|
||||||
|
OS_NAME="linux32"
|
||||||
|
elif [[ "$OSBITS" == "x86_64" ]]; then
|
||||||
|
OS_NAME="linux64"
|
||||||
|
elif [[ "$OSBITS" == "armv7l" || "$OSBITS" == "aarch64" ]]; then
|
||||||
|
OS_NAME="linuxarm"
|
||||||
|
else
|
||||||
|
OS_NAME="$OSTYPE-$OSBITS"
|
||||||
|
echo "Unknown OS '$OS_NAME'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
export OS_IS_MACOS="1"
|
||||||
|
ARCHIVE_FORMAT="zip"
|
||||||
|
OS_NAME="macosx"
|
||||||
|
elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
|
||||||
|
export OS_IS_WINDOWS="1"
|
||||||
|
ARCHIVE_FORMAT="zip"
|
||||||
|
OS_NAME="windows"
|
||||||
|
else
|
||||||
|
OS_NAME="$OSTYPE-$OSBITS"
|
||||||
|
echo "Unknown OS '$OS_NAME'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
export OS_NAME
|
||||||
|
|
||||||
|
ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp"
|
||||||
|
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
|
||||||
|
|
||||||
|
if [ "$OS_IS_MACOS" == "1" ]; then
|
||||||
|
export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java"
|
||||||
|
export ARDUINO_USR_PATH="$HOME/Documents/Arduino"
|
||||||
|
elif [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||||
|
export ARDUINO_IDE_PATH="$HOME/arduino_ide"
|
||||||
|
export ARDUINO_USR_PATH="$HOME/Documents/Arduino"
|
||||||
|
else
|
||||||
|
export ARDUINO_IDE_PATH="$HOME/arduino_ide"
|
||||||
|
export ARDUINO_USR_PATH="$HOME/Arduino"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$ARDUINO_IDE_PATH" ]; then
|
||||||
|
echo "Installing Arduino IDE on $OS_NAME ..."
|
||||||
|
echo "Downloading 'arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
|
||||||
|
if [ "$OS_IS_LINUX" == "1" ]; then
|
||||||
|
wget -O "arduino.$ARCHIVE_FORMAT" "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||||
|
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
|
||||||
|
tar xf "arduino.$ARCHIVE_FORMAT" > /dev/null
|
||||||
|
mv arduino-nightly "$ARDUINO_IDE_PATH"
|
||||||
|
else
|
||||||
|
curl -o "arduino.$ARCHIVE_FORMAT" -L "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||||
|
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
|
||||||
|
unzip "arduino.$ARCHIVE_FORMAT" > /dev/null
|
||||||
|
if [ "$OS_IS_MACOS" == "1" ]; then
|
||||||
|
mv "Arduino.app" "/Applications/Arduino.app"
|
||||||
|
else
|
||||||
|
mv arduino-nightly "$ARDUINO_IDE_PATH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -rf "arduino.$ARCHIVE_FORMAT"
|
||||||
|
|
||||||
|
mkdir -p "$ARDUINO_USR_PATH/libraries"
|
||||||
|
mkdir -p "$ARDUINO_USR_PATH/hardware"
|
||||||
|
|
||||||
|
echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
function build_sketch(){ # build_sketch <fqbn> <path-to-ino> <build-flags> [extra-options]
|
||||||
|
if [ "$#" -lt 2 ]; then
|
||||||
|
echo "ERROR: Illegal number of parameters"
|
||||||
|
echo "USAGE: build_sketch <fqbn> <path-to-ino> <build-flags> [extra-options]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local fqbn="$1"
|
||||||
|
local sketch="$2"
|
||||||
|
local build_flags="$3"
|
||||||
|
local xtra_opts="$4"
|
||||||
|
local win_opts=""
|
||||||
|
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||||
|
local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"`
|
||||||
|
local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"`
|
||||||
|
win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||||
|
mkdir -p "$ARDUINO_BUILD_DIR"
|
||||||
|
mkdir -p "$ARDUINO_CACHE_DIR"
|
||||||
|
$ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \
|
||||||
|
-fqbn=$fqbn \
|
||||||
|
-warnings="all" \
|
||||||
|
-tools "$ARDUINO_IDE_PATH/tools-builder" \
|
||||||
|
-tools "$ARDUINO_IDE_PATH/tools" \
|
||||||
|
-built-in-libraries "$ARDUINO_IDE_PATH/libraries" \
|
||||||
|
-hardware "$ARDUINO_IDE_PATH/hardware" \
|
||||||
|
-hardware "$ARDUINO_USR_PATH/hardware" \
|
||||||
|
-libraries "$ARDUINO_USR_PATH/libraries" \
|
||||||
|
-build-cache "$ARDUINO_CACHE_DIR" \
|
||||||
|
-build-path "$ARDUINO_BUILD_DIR" \
|
||||||
|
-prefs=compiler.cpp.extra_flags="$build_flags" \
|
||||||
|
$win_opts $xtra_opts "$sketch"
|
||||||
|
}
|
||||||
|
|
||||||
|
function count_sketches() # count_sketches <examples-path>
|
||||||
|
{
|
||||||
|
local examples="$1"
|
||||||
|
rm -rf sketches.txt
|
||||||
|
if [ ! -d "$examples" ]; then
|
||||||
|
touch sketches.txt
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local sketches=$(find $examples -name *.ino)
|
||||||
|
local sketchnum=0
|
||||||
|
for sketch in $sketches; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchdirname=$(basename $sketchdir)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||||
|
continue
|
||||||
|
fi;
|
||||||
|
if [[ -f "$sketchdir/.test.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo $sketch >> sketches.txt
|
||||||
|
sketchnum=$(($sketchnum + 1))
|
||||||
|
done
|
||||||
|
return $sketchnum
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total-chunks> [extra-options]
|
||||||
|
{
|
||||||
|
local fqbn=$1
|
||||||
|
local examples=$2
|
||||||
|
local chunk_idex=$3
|
||||||
|
local chunks_num=$4
|
||||||
|
local xtra_opts=$5
|
||||||
|
|
||||||
|
if [ "$#" -lt 2 ]; then
|
||||||
|
echo "ERROR: Illegal number of parameters"
|
||||||
|
echo "USAGE: build_sketches <fqbn> <examples-path> [<chunk> <total-chunks>] [extra-options]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
chunk_idex="0"
|
||||||
|
chunks_num="1"
|
||||||
|
xtra_opts=$3
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$chunks_num" -le 0 ]; then
|
||||||
|
echo "ERROR: Chunks count must be positive number"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||||
|
echo "ERROR: Chunk index must be less than chunks count"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
count_sketches "$examples"
|
||||||
|
local sketchcount=$?
|
||||||
|
set -e
|
||||||
|
local sketches=$(cat sketches.txt)
|
||||||
|
rm -rf sketches.txt
|
||||||
|
|
||||||
|
local chunk_size=$(( $sketchcount / $chunks_num ))
|
||||||
|
local all_chunks=$(( $chunks_num * $chunk_size ))
|
||||||
|
if [ "$all_chunks" -lt "$sketchcount" ]; then
|
||||||
|
chunk_size=$(( $chunk_size + 1 ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
local start_index=$(( $chunk_idex * $chunk_size ))
|
||||||
|
if [ "$sketchcount" -le "$start_index" ]; then
|
||||||
|
echo "Skipping job"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||||
|
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||||
|
end_index=$sketchcount
|
||||||
|
fi
|
||||||
|
|
||||||
|
local start_num=$(( $start_index + 1 ))
|
||||||
|
echo "Found $sketchcount Sketches";
|
||||||
|
echo "Chunk Count : $chunks_num"
|
||||||
|
echo "Chunk Size : $chunk_size"
|
||||||
|
echo "Start Sketch: $start_num"
|
||||||
|
echo "End Sketch : $end_index"
|
||||||
|
|
||||||
|
local sketchnum=0
|
||||||
|
for sketch in $sketches; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchdirname=$(basename $sketchdir)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|
||||||
|
|| [ -f "$sketchdir/.test.skip" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
sketchnum=$(($sketchnum + 1))
|
||||||
|
if [ "$sketchnum" -le "$start_index" ] \
|
||||||
|
|| [ "$sketchnum" -gt "$end_index" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
local sketchBuildFlags=""
|
||||||
|
if [ -f "$sketchdir/.test.build_flags" ]; then
|
||||||
|
while read line; do
|
||||||
|
sketchBuildFlags="$sketchBuildFlags $line"
|
||||||
|
done < "$sketchdir/.test.build_flags"
|
||||||
|
fi
|
||||||
|
build_sketch "$fqbn" "$sketch" "$sketchBuildFlags" "$xtra_opts"
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
140
lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh
vendored
Normal file
140
lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Installing Python Wheel ..."
|
||||||
|
pip install wheel > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Installing PlatformIO ..."
|
||||||
|
pip install -U platformio > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "PlatformIO has been installed"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
|
||||||
|
function build_pio_sketch(){ # build_pio_sketch <board> <path-to-ino> <build-flags>
|
||||||
|
if [ "$#" -lt 3 ]; then
|
||||||
|
echo "ERROR: Illegal number of parameters"
|
||||||
|
echo "USAGE: build_pio_sketch <board> <path-to-ino> <build-flags>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local board="$1"
|
||||||
|
local sketch="$2"
|
||||||
|
local buildFlags="$3"
|
||||||
|
local sketch_dir=$(dirname "$sketch")
|
||||||
|
echo ""
|
||||||
|
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||||
|
python -m platformio ci -l '.' --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv" --project-option="build_flags=$buildFlags"
|
||||||
|
}
|
||||||
|
|
||||||
|
function count_sketches() # count_sketches <examples-path>
|
||||||
|
{
|
||||||
|
local examples="$1"
|
||||||
|
rm -rf sketches.txt
|
||||||
|
if [ ! -d "$examples" ]; then
|
||||||
|
touch sketches.txt
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local sketches=$(find $examples -name *.ino)
|
||||||
|
local sketchnum=0
|
||||||
|
for sketch in $sketches; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchdirname=$(basename $sketchdir)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||||
|
continue
|
||||||
|
fi;
|
||||||
|
if [[ -f "$sketchdir/.test.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo $sketch >> sketches.txt
|
||||||
|
sketchnum=$(($sketchnum + 1))
|
||||||
|
done
|
||||||
|
return $sketchnum
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_pio_sketches() # build_pio_sketches <board> <examples-path> <chunk> <total-chunks>
|
||||||
|
{
|
||||||
|
if [ "$#" -lt 2 ]; then
|
||||||
|
echo "ERROR: Illegal number of parameters"
|
||||||
|
echo "USAGE: build_pio_sketches <board> <examples-path> [<chunk> <total-chunks>]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local board=$1
|
||||||
|
local examples=$2
|
||||||
|
local chunk_idex=$3
|
||||||
|
local chunks_num=$4
|
||||||
|
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
chunk_idex="0"
|
||||||
|
chunks_num="1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$chunks_num" -le 0 ]; then
|
||||||
|
echo "ERROR: Chunks count must be positive number"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||||
|
echo "ERROR: Chunk index must be less than chunks count"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
count_sketches "$examples"
|
||||||
|
local sketchcount=$?
|
||||||
|
set -e
|
||||||
|
local sketches=$(cat sketches.txt)
|
||||||
|
rm -rf sketches.txt
|
||||||
|
|
||||||
|
local chunk_size=$(( $sketchcount / $chunks_num ))
|
||||||
|
local all_chunks=$(( $chunks_num * $chunk_size ))
|
||||||
|
if [ "$all_chunks" -lt "$sketchcount" ]; then
|
||||||
|
chunk_size=$(( $chunk_size + 1 ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
local start_index=$(( $chunk_idex * $chunk_size ))
|
||||||
|
if [ "$sketchcount" -le "$start_index" ]; then
|
||||||
|
echo "Skipping job"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||||
|
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||||
|
end_index=$sketchcount
|
||||||
|
fi
|
||||||
|
|
||||||
|
local start_num=$(( $start_index + 1 ))
|
||||||
|
echo "Found $sketchcount Sketches";
|
||||||
|
echo "Chunk Count : $chunks_num"
|
||||||
|
echo "Chunk Size : $chunk_size"
|
||||||
|
echo "Start Sketch: $start_num"
|
||||||
|
echo "End Sketch : $end_index"
|
||||||
|
|
||||||
|
local sketchnum=0
|
||||||
|
for sketch in $sketches; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchdirname=$(basename $sketchdir)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|
||||||
|
|| [ -f "$sketchdir/.test.skip" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
local sketchBuildFlags=""
|
||||||
|
if [ -f "$sketchdir/.test.build_flags" ]; then
|
||||||
|
while read line; do
|
||||||
|
sketchBuildFlags="$sketchBuildFlags $line"
|
||||||
|
done < "$sketchdir/.test.build_flags"
|
||||||
|
fi
|
||||||
|
sketchnum=$(($sketchnum + 1))
|
||||||
|
if [ "$sketchnum" -le "$start_index" ] \
|
||||||
|
|| [ "$sketchnum" -gt "$end_index" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
build_pio_sketch "$board" "$sketch" "$sketchBuildFlags"
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
71
lib/ESPAsyncWebServer/.github/scripts/on-push.sh
vendored
Normal file
71
lib/ESPAsyncWebServer/.github/scripts/on-push.sh
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -z "$TRAVIS_BUILD_DIR" ]; then
|
||||||
|
export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR"
|
||||||
|
export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG"
|
||||||
|
elif [ -z "$GITHUB_WORKSPACE" ]; then
|
||||||
|
export GITHUB_WORKSPACE="$PWD"
|
||||||
|
export GITHUB_REPOSITORY="me-no-dev/ESPAsyncWebServer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_PLATFORM="$1"
|
||||||
|
CHUNK_INDEX=$2
|
||||||
|
CHUNKS_CNT=$3
|
||||||
|
BUILD_PIO=0
|
||||||
|
if [ "$#" -lt 1 ]; then
|
||||||
|
TARGET_PLATFORM="esp32"
|
||||||
|
fi
|
||||||
|
if [ "$#" -lt 3 ] || [ "$CHUNKS_CNT" -le 0 ]; then
|
||||||
|
CHUNK_INDEX=0
|
||||||
|
CHUNKS_CNT=1
|
||||||
|
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then
|
||||||
|
CHUNK_INDEX=$CHUNKS_CNT
|
||||||
|
elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
|
||||||
|
BUILD_PIO=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$BUILD_PIO" -eq 0 ]; then
|
||||||
|
# ArduinoIDE Test
|
||||||
|
source ./.github/scripts/install-arduino-ide.sh
|
||||||
|
|
||||||
|
echo "Installing ESPAsyncWebServer ..."
|
||||||
|
cp -rf "$GITHUB_WORKSPACE" "$ARDUINO_USR_PATH/libraries/ESPAsyncWebServer"
|
||||||
|
echo "Installing ArduinoJson ..."
|
||||||
|
git clone https://github.com/bblanchon/ArduinoJson "$ARDUINO_USR_PATH/libraries/ArduinoJson" > /dev/null 2>&1
|
||||||
|
|
||||||
|
if [[ "$TARGET_PLATFORM" == "esp32" ]]; then
|
||||||
|
echo "Installing AsyncTCP ..."
|
||||||
|
git clone https://github.com/me-no-dev/AsyncTCP "$ARDUINO_USR_PATH/libraries/AsyncTCP" > /dev/null 2>&1
|
||||||
|
FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
|
||||||
|
source ./.github/scripts/install-arduino-core-esp32.sh
|
||||||
|
echo "BUILDING ESP32 EXAMPLES"
|
||||||
|
else
|
||||||
|
echo "Installing ESPAsyncTCP ..."
|
||||||
|
git clone https://github.com/me-no-dev/ESPAsyncTCP "$ARDUINO_USR_PATH/libraries/ESPAsyncTCP" > /dev/null 2>&1
|
||||||
|
FQBN="esp8266com:esp8266:generic:eesz=4M1M,ip=lm2f"
|
||||||
|
source ./.github/scripts/install-arduino-core-esp8266.sh
|
||||||
|
echo "BUILDING ESP8266 EXAMPLES"
|
||||||
|
fi
|
||||||
|
build_sketches "$FQBN" "$GITHUB_WORKSPACE/examples" "$CHUNK_INDEX" "$CHUNKS_CNT"
|
||||||
|
else
|
||||||
|
# PlatformIO Test
|
||||||
|
source ./.github/scripts/install-platformio.sh
|
||||||
|
|
||||||
|
python -m platformio lib --storage-dir "$GITHUB_WORKSPACE" install
|
||||||
|
echo "Installing ArduinoJson ..."
|
||||||
|
python -m platformio lib -g install https://github.com/bblanchon/ArduinoJson.git > /dev/null 2>&1
|
||||||
|
if [[ "$TARGET_PLATFORM" == "esp32" ]]; then
|
||||||
|
BOARD="esp32dev"
|
||||||
|
echo "Installing AsyncTCP ..."
|
||||||
|
python -m platformio lib -g install https://github.com/me-no-dev/AsyncTCP.git > /dev/null 2>&1
|
||||||
|
echo "BUILDING ESP32 EXAMPLES"
|
||||||
|
else
|
||||||
|
BOARD="esp12e"
|
||||||
|
echo "Installing ESPAsyncTCP ..."
|
||||||
|
python -m platformio lib -g install https://github.com/me-no-dev/ESPAsyncTCP.git > /dev/null 2>&1
|
||||||
|
echo "BUILDING ESP8266 EXAMPLES"
|
||||||
|
fi
|
||||||
|
build_pio_sketches "$BOARD" "$GITHUB_WORKSPACE/examples"
|
||||||
|
fi
|
||||||
31
lib/ESPAsyncWebServer/.github/stale.yml
vendored
Normal file
31
lib/ESPAsyncWebServer/.github/stale.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Configuration for probot-stale - https://github.com/probot/stale
|
||||||
|
|
||||||
|
daysUntilStale: 60
|
||||||
|
daysUntilClose: 14
|
||||||
|
limitPerRun: 30
|
||||||
|
staleLabel: stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
- "to be implemented"
|
||||||
|
- "for reference"
|
||||||
|
- "move to PR"
|
||||||
|
- "enhancement"
|
||||||
|
|
||||||
|
only: issues
|
||||||
|
onlyLabels: []
|
||||||
|
exemptProjects: false
|
||||||
|
exemptMilestones: false
|
||||||
|
exemptAssignees: false
|
||||||
|
|
||||||
|
markComment: >
|
||||||
|
[STALE_SET] This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed in 14 days if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
|
||||||
|
unmarkComment: >
|
||||||
|
[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.
|
||||||
|
|
||||||
|
closeComment: >
|
||||||
|
[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.
|
||||||
|
|
||||||
34
lib/ESPAsyncWebServer/.github/workflows/push.yml
vendored
Normal file
34
lib/ESPAsyncWebServer/.github/workflows/push.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: ESP Async Web Server CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- release/*
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build-arduino:
|
||||||
|
name: Arduino for ${{ matrix.board }} on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
board: [esp32, esp8266]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Build Tests
|
||||||
|
run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 0 1
|
||||||
|
|
||||||
|
build-pio:
|
||||||
|
name: PlatformIO for ${{ matrix.board }} on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
board: [esp32, esp8266]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Build Tests
|
||||||
|
run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 1 1
|
||||||
2
lib/ESPAsyncWebServer/.gitignore
vendored
Normal file
2
lib/ESPAsyncWebServer/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
46
lib/ESPAsyncWebServer/.travis.yml
Normal file
46
lib/ESPAsyncWebServer/.travis.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: python
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: false
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
|
||||||
|
- name: "Build Arduino ESP32"
|
||||||
|
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||||
|
stage: build
|
||||||
|
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32
|
||||||
|
|
||||||
|
- name: "Build Arduino ESP8266"
|
||||||
|
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||||
|
stage: build
|
||||||
|
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266
|
||||||
|
|
||||||
|
- name: "Build Platformio ESP32"
|
||||||
|
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||||
|
stage: build
|
||||||
|
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32 1 1
|
||||||
|
|
||||||
|
- name: "Build Platformio ESP8266"
|
||||||
|
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||||
|
stage: build
|
||||||
|
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266 1 1
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: change
|
||||||
|
on_failure: change
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- https://webhooks.gitter.im/e/60e65d0c78ea0a920347
|
||||||
|
on_success: change # options: [always|never|change] default: always
|
||||||
|
on_failure: always # options: [always|never|change] default: always
|
||||||
|
on_start: never # options: [always|never|change] default: always
|
||||||
17
lib/ESPAsyncWebServer/CMakeLists.txt
Normal file
17
lib/ESPAsyncWebServer/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
set(COMPONENT_SRCDIRS
|
||||||
|
"src"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS
|
||||||
|
"src"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(COMPONENT_REQUIRES
|
||||||
|
"arduino-esp32"
|
||||||
|
"AsyncTCP"
|
||||||
|
)
|
||||||
|
|
||||||
|
register_component()
|
||||||
|
|
||||||
|
target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DESP32)
|
||||||
|
target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti)
|
||||||
1521
lib/ESPAsyncWebServer/README.md
Normal file
1521
lib/ESPAsyncWebServer/README.md
Normal file
File diff suppressed because it is too large
Load Diff
1
lib/ESPAsyncWebServer/_config.yml
Normal file
1
lib/ESPAsyncWebServer/_config.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
theme: jekyll-theme-cayman
|
||||||
3
lib/ESPAsyncWebServer/component.mk
Normal file
3
lib/ESPAsyncWebServer/component.mk
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
COMPONENT_ADD_INCLUDEDIRS := src
|
||||||
|
COMPONENT_SRCDIRS := src
|
||||||
|
CXXFLAGS += -fno-rtti
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <DNSServer.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#endif
|
||||||
|
#include "ESPAsyncWebServer.h"
|
||||||
|
|
||||||
|
DNSServer dnsServer;
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
class CaptiveRequestHandler : public AsyncWebHandler {
|
||||||
|
public:
|
||||||
|
CaptiveRequestHandler() {}
|
||||||
|
virtual ~CaptiveRequestHandler() {}
|
||||||
|
|
||||||
|
bool canHandle(AsyncWebServerRequest *request){
|
||||||
|
//request->addInterestingHeader("ANY");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRequest(AsyncWebServerRequest *request) {
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("text/html");
|
||||||
|
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
||||||
|
response->print("<p>This is out captive portal front page.</p>");
|
||||||
|
response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
|
||||||
|
response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
|
||||||
|
response->print("</body></html>");
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
//your other setup stuff...
|
||||||
|
WiFi.softAP("esp-captive");
|
||||||
|
dnsServer.start(53, "*", WiFi.softAPIP());
|
||||||
|
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
|
||||||
|
//more handlers...
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <FS.h>
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <SPIFFSEditor.h>
|
||||||
|
|
||||||
|
// SKETCH BEGIN
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
AsyncWebSocket ws("/ws");
|
||||||
|
AsyncEventSource events("/events");
|
||||||
|
|
||||||
|
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
|
||||||
|
if(type == WS_EVT_CONNECT){
|
||||||
|
Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
|
||||||
|
client->printf("Hello Client %u :)", client->id());
|
||||||
|
client->ping();
|
||||||
|
} else if(type == WS_EVT_DISCONNECT){
|
||||||
|
Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id());
|
||||||
|
} else if(type == WS_EVT_ERROR){
|
||||||
|
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
|
||||||
|
} else if(type == WS_EVT_PONG){
|
||||||
|
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
|
||||||
|
} else if(type == WS_EVT_DATA){
|
||||||
|
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||||
|
String msg = "";
|
||||||
|
if(info->final && info->index == 0 && info->len == len){
|
||||||
|
//the whole message is in a single frame and we got all of it's data
|
||||||
|
Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
|
||||||
|
|
||||||
|
if(info->opcode == WS_TEXT){
|
||||||
|
for(size_t i=0; i < info->len; i++) {
|
||||||
|
msg += (char) data[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char buff[3];
|
||||||
|
for(size_t i=0; i < info->len; i++) {
|
||||||
|
sprintf(buff, "%02x ", (uint8_t) data[i]);
|
||||||
|
msg += buff ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.printf("%s\n",msg.c_str());
|
||||||
|
|
||||||
|
if(info->opcode == WS_TEXT)
|
||||||
|
client->text("I got your text message");
|
||||||
|
else
|
||||||
|
client->binary("I got your binary message");
|
||||||
|
} else {
|
||||||
|
//message is comprised of multiple frames or the frame is split into multiple packets
|
||||||
|
if(info->index == 0){
|
||||||
|
if(info->num == 0)
|
||||||
|
Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
|
||||||
|
Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
|
||||||
|
|
||||||
|
if(info->opcode == WS_TEXT){
|
||||||
|
for(size_t i=0; i < len; i++) {
|
||||||
|
msg += (char) data[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char buff[3];
|
||||||
|
for(size_t i=0; i < len; i++) {
|
||||||
|
sprintf(buff, "%02x ", (uint8_t) data[i]);
|
||||||
|
msg += buff ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.printf("%s\n",msg.c_str());
|
||||||
|
|
||||||
|
if((info->index + len) == info->len){
|
||||||
|
Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
|
||||||
|
if(info->final){
|
||||||
|
Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
|
||||||
|
if(info->message_opcode == WS_TEXT)
|
||||||
|
client->text("I got your text message");
|
||||||
|
else
|
||||||
|
client->binary("I got your binary message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* ssid = "*******";
|
||||||
|
const char* password = "*******";
|
||||||
|
const char * hostName = "esp-async";
|
||||||
|
const char* http_username = "admin";
|
||||||
|
const char* http_password = "admin";
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.setDebugOutput(true);
|
||||||
|
WiFi.mode(WIFI_AP_STA);
|
||||||
|
WiFi.softAP(hostName);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.printf("STA: Failed!\n");
|
||||||
|
WiFi.disconnect(false);
|
||||||
|
delay(1000);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send OTA events to the browser
|
||||||
|
ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); });
|
||||||
|
ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); });
|
||||||
|
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
char p[32];
|
||||||
|
sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
|
||||||
|
events.send(p, "ota");
|
||||||
|
});
|
||||||
|
ArduinoOTA.onError([](ota_error_t error) {
|
||||||
|
if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
|
||||||
|
else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota");
|
||||||
|
else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota");
|
||||||
|
else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota");
|
||||||
|
else if(error == OTA_END_ERROR) events.send("End Failed", "ota");
|
||||||
|
});
|
||||||
|
ArduinoOTA.setHostname(hostName);
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
MDNS.addService("http","tcp",80);
|
||||||
|
|
||||||
|
SPIFFS.begin();
|
||||||
|
|
||||||
|
ws.onEvent(onWsEvent);
|
||||||
|
server.addHandler(&ws);
|
||||||
|
|
||||||
|
events.onConnect([](AsyncEventSourceClient *client){
|
||||||
|
client->send("hello!",NULL,millis(),1000);
|
||||||
|
});
|
||||||
|
server.addHandler(&events);
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password));
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
server.addHandler(new SPIFFSEditor(http_username,http_password));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", String(ESP.getFreeHeap()));
|
||||||
|
});
|
||||||
|
|
||||||
|
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm");
|
||||||
|
|
||||||
|
server.onNotFound([](AsyncWebServerRequest *request){
|
||||||
|
Serial.printf("NOT_FOUND: ");
|
||||||
|
if(request->method() == HTTP_GET)
|
||||||
|
Serial.printf("GET");
|
||||||
|
else if(request->method() == HTTP_POST)
|
||||||
|
Serial.printf("POST");
|
||||||
|
else if(request->method() == HTTP_DELETE)
|
||||||
|
Serial.printf("DELETE");
|
||||||
|
else if(request->method() == HTTP_PUT)
|
||||||
|
Serial.printf("PUT");
|
||||||
|
else if(request->method() == HTTP_PATCH)
|
||||||
|
Serial.printf("PATCH");
|
||||||
|
else if(request->method() == HTTP_HEAD)
|
||||||
|
Serial.printf("HEAD");
|
||||||
|
else if(request->method() == HTTP_OPTIONS)
|
||||||
|
Serial.printf("OPTIONS");
|
||||||
|
else
|
||||||
|
Serial.printf("UNKNOWN");
|
||||||
|
Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
|
||||||
|
|
||||||
|
if(request->contentLength()){
|
||||||
|
Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
|
||||||
|
Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
int headers = request->headers();
|
||||||
|
int i;
|
||||||
|
for(i=0;i<headers;i++){
|
||||||
|
AsyncWebHeader* h = request->getHeader(i);
|
||||||
|
Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int params = request->params();
|
||||||
|
for(i=0;i<params;i++){
|
||||||
|
AsyncWebParameter* p = request->getParam(i);
|
||||||
|
if(p->isFile()){
|
||||||
|
Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
|
||||||
|
} else if(p->isPost()){
|
||||||
|
Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
|
} else {
|
||||||
|
Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request->send(404);
|
||||||
|
});
|
||||||
|
server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
|
if(!index)
|
||||||
|
Serial.printf("UploadStart: %s\n", filename.c_str());
|
||||||
|
Serial.printf("%s", (const char*)data);
|
||||||
|
if(final)
|
||||||
|
Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
|
||||||
|
});
|
||||||
|
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
|
||||||
|
if(!index)
|
||||||
|
Serial.printf("BodyStart: %u\n", total);
|
||||||
|
Serial.printf("%s", (const char*)data);
|
||||||
|
if(index + len == total)
|
||||||
|
Serial.printf("BodyEnd: %u\n", total);
|
||||||
|
});
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
ArduinoOTA.handle();
|
||||||
|
ws.cleanupClients();
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*.js.gz
|
||||||
|
/.exclude.files
|
||||||
BIN
lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz
Normal file
BIN
lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
131
lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm
Normal file
131
lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<!--
|
||||||
|
FSWebServer - Example Index Page
|
||||||
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the ESP8266WebServer library for Arduino environment.
|
||||||
|
|
||||||
|
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
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||||
|
<title>WebSocketTester</title>
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
body {
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dbg, #input_div, #input_el {
|
||||||
|
font-family: monaco;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 13px;
|
||||||
|
color: #AAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dbg, #input_div {
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
padding-left:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input_el {
|
||||||
|
width:98%;
|
||||||
|
background-color: rgba(0,0,0,0);
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
#input_el:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var ws = null;
|
||||||
|
function ge(s){ return document.getElementById(s);}
|
||||||
|
function ce(s){ return document.createElement(s);}
|
||||||
|
function stb(){ window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight); }
|
||||||
|
function sendBlob(str){
|
||||||
|
var buf = new Uint8Array(str.length);
|
||||||
|
for (var i = 0; i < str.length; ++i) buf[i] = str.charCodeAt(i);
|
||||||
|
ws.send(buf);
|
||||||
|
}
|
||||||
|
function addMessage(m){
|
||||||
|
var msg = ce("div");
|
||||||
|
msg.innerText = m;
|
||||||
|
ge("dbg").appendChild(msg);
|
||||||
|
stb();
|
||||||
|
}
|
||||||
|
function startSocket(){
|
||||||
|
ws = new WebSocket('ws://'+document.location.host+'/ws',['arduino']);
|
||||||
|
ws.binaryType = "arraybuffer";
|
||||||
|
ws.onopen = function(e){
|
||||||
|
addMessage("Connected");
|
||||||
|
};
|
||||||
|
ws.onclose = function(e){
|
||||||
|
addMessage("Disconnected");
|
||||||
|
};
|
||||||
|
ws.onerror = function(e){
|
||||||
|
console.log("ws error", e);
|
||||||
|
addMessage("Error");
|
||||||
|
};
|
||||||
|
ws.onmessage = function(e){
|
||||||
|
var msg = "";
|
||||||
|
if(e.data instanceof ArrayBuffer){
|
||||||
|
msg = "BIN:";
|
||||||
|
var bytes = new Uint8Array(e.data);
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
msg += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = "TXT:"+e.data;
|
||||||
|
}
|
||||||
|
addMessage(msg);
|
||||||
|
};
|
||||||
|
ge("input_el").onkeydown = function(e){
|
||||||
|
stb();
|
||||||
|
if(e.keyCode == 13 && ge("input_el").value != ""){
|
||||||
|
ws.send(ge("input_el").value);
|
||||||
|
ge("input_el").value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function startEvents(){
|
||||||
|
var es = new EventSource('/events');
|
||||||
|
es.onopen = function(e) {
|
||||||
|
addMessage("Events Opened");
|
||||||
|
};
|
||||||
|
es.onerror = function(e) {
|
||||||
|
if (e.target.readyState != EventSource.OPEN) {
|
||||||
|
addMessage("Events Closed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
es.onmessage = function(e) {
|
||||||
|
addMessage("Event: " + e.data);
|
||||||
|
};
|
||||||
|
es.addEventListener('ota', function(e) {
|
||||||
|
addMessage("Event[ota]: " + e.data);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
function onBodyLoad(){
|
||||||
|
startSocket();
|
||||||
|
startEvents();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="body" onload="onBodyLoad()">
|
||||||
|
<pre id="dbg"></pre>
|
||||||
|
<div id="input_div">
|
||||||
|
$<input type="text" value="" id="input_el">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
-DASYNCWEBSERVER_REGEX=1
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// A simple server implementation with regex routes:
|
||||||
|
// * serve static messages
|
||||||
|
// * read GET and POST parameters
|
||||||
|
// * handle missing pages / 404s
|
||||||
|
//
|
||||||
|
|
||||||
|
// Add buildflag ASYNCWEBSERVER_REGEX to enable the regex support
|
||||||
|
|
||||||
|
// For platformio: platformio.ini:
|
||||||
|
// build_flags =
|
||||||
|
// -DASYNCWEBSERVER_REGEX
|
||||||
|
|
||||||
|
// For arduino IDE: create/update platform.local.txt
|
||||||
|
// Windows: C:\Users\(username)\AppData\Local\Arduino15\packages\espxxxx\hardware\espxxxx\{version}\platform.local.txt
|
||||||
|
// Linux: ~/.arduino15/packages/espxxxx/hardware/espxxxx/{version}/platform.local.txt
|
||||||
|
//
|
||||||
|
// compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
const char* ssid = "YOUR_SSID";
|
||||||
|
const char* password = "YOUR_PASSWORD";
|
||||||
|
|
||||||
|
const char* PARAM_MESSAGE = "message";
|
||||||
|
|
||||||
|
void notFound(AsyncWebServerRequest *request) {
|
||||||
|
request->send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.printf("WiFi Failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", "Hello, world");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a GET request to <IP>/sensor/<number>
|
||||||
|
server.on("^\\/sensor\\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||||
|
String sensorNumber = request->pathArg(0);
|
||||||
|
request->send(200, "text/plain", "Hello, sensor: " + sensorNumber);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a GET request to <IP>/sensor/<number>/action/<action>
|
||||||
|
server.on("^\\/sensor\\/([0-9]+)\\/action\\/([a-zA-Z0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||||
|
String sensorNumber = request->pathArg(0);
|
||||||
|
String action = request->pathArg(1);
|
||||||
|
request->send(200, "text/plain", "Hello, sensor: " + sensorNumber + ", with action: " + action);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.onNotFound(notFound);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// A simple server implementation showing how to:
|
||||||
|
// * serve static messages
|
||||||
|
// * read GET and POST parameters
|
||||||
|
// * handle missing pages / 404s
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
const char* ssid = "YOUR_SSID";
|
||||||
|
const char* password = "YOUR_PASSWORD";
|
||||||
|
|
||||||
|
const char* PARAM_MESSAGE = "message";
|
||||||
|
|
||||||
|
void notFound(AsyncWebServerRequest *request) {
|
||||||
|
request->send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.printf("WiFi Failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", "Hello, world");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a GET request to <IP>/get?message=<message>
|
||||||
|
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||||
|
String message;
|
||||||
|
if (request->hasParam(PARAM_MESSAGE)) {
|
||||||
|
message = request->getParam(PARAM_MESSAGE)->value();
|
||||||
|
} else {
|
||||||
|
message = "No message sent";
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "Hello, GET: " + message);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a POST request to <IP>/post with a form field message set to <message>
|
||||||
|
server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
String message;
|
||||||
|
if (request->hasParam(PARAM_MESSAGE, true)) {
|
||||||
|
message = request->getParam(PARAM_MESSAGE, true)->value();
|
||||||
|
} else {
|
||||||
|
message = "No message sent";
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "Hello, POST: " + message);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.onNotFound(notFound);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
3
lib/ESPAsyncWebServer/keywords.txt
Normal file
3
lib/ESPAsyncWebServer/keywords.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
JsonArray KEYWORD1
|
||||||
|
add KEYWORD2
|
||||||
|
createArray KEYWORD3
|
||||||
33
lib/ESPAsyncWebServer/library.json
Normal file
33
lib/ESPAsyncWebServer/library.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name":"ESP Async WebServer",
|
||||||
|
"description":"Asynchronous HTTP and WebSocket Server Library for ESP8266 and ESP32",
|
||||||
|
"keywords":"http,async,websocket,webserver",
|
||||||
|
"authors":
|
||||||
|
{
|
||||||
|
"name": "Hristo Gochkov",
|
||||||
|
"maintainer": true
|
||||||
|
},
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/me-no-dev/ESPAsyncWebServer.git"
|
||||||
|
},
|
||||||
|
"version": "1.2.3",
|
||||||
|
"license": "LGPL-3.0",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": ["espressif8266", "espressif32"],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "ESPAsyncTCP",
|
||||||
|
"platforms": "espressif8266"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AsyncTCP",
|
||||||
|
"platforms": "espressif32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hash",
|
||||||
|
"platforms": "espressif8266"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
9
lib/ESPAsyncWebServer/library.properties
Normal file
9
lib/ESPAsyncWebServer/library.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name=ESP Async WebServer
|
||||||
|
version=1.2.3
|
||||||
|
author=Me-No-Dev
|
||||||
|
maintainer=Me-No-Dev
|
||||||
|
sentence=Async Web Server for ESP8266 and ESP31B
|
||||||
|
paragraph=Async Web Server for ESP8266 and ESP31B
|
||||||
|
category=Other
|
||||||
|
url=https://github.com/me-no-dev/ESPAsyncWebServer
|
||||||
|
architectures=*
|
||||||
368
lib/ESPAsyncWebServer/src/AsyncEventSource.cpp
Normal file
368
lib/ESPAsyncWebServer/src/AsyncEventSource.cpp
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
|
||||||
|
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 "Arduino.h"
|
||||||
|
#include "AsyncEventSource.h"
|
||||||
|
|
||||||
|
static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
||||||
|
String ev = "";
|
||||||
|
|
||||||
|
if(reconnect){
|
||||||
|
ev += "retry: ";
|
||||||
|
ev += String(reconnect);
|
||||||
|
ev += "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id){
|
||||||
|
ev += "id: ";
|
||||||
|
ev += String(id);
|
||||||
|
ev += "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event != NULL){
|
||||||
|
ev += "event: ";
|
||||||
|
ev += String(event);
|
||||||
|
ev += "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message != NULL){
|
||||||
|
size_t messageLen = strlen(message);
|
||||||
|
char * lineStart = (char *)message;
|
||||||
|
char * lineEnd;
|
||||||
|
do {
|
||||||
|
char * nextN = strchr(lineStart, '\n');
|
||||||
|
char * nextR = strchr(lineStart, '\r');
|
||||||
|
if(nextN == NULL && nextR == NULL){
|
||||||
|
size_t llen = ((char *)message + messageLen) - lineStart;
|
||||||
|
char * ldata = (char *)malloc(llen+1);
|
||||||
|
if(ldata != NULL){
|
||||||
|
memcpy(ldata, lineStart, llen);
|
||||||
|
ldata[llen] = 0;
|
||||||
|
ev += "data: ";
|
||||||
|
ev += ldata;
|
||||||
|
ev += "\r\n\r\n";
|
||||||
|
free(ldata);
|
||||||
|
}
|
||||||
|
lineStart = (char *)message + messageLen;
|
||||||
|
} else {
|
||||||
|
char * nextLine = NULL;
|
||||||
|
if(nextN != NULL && nextR != NULL){
|
||||||
|
if(nextR < nextN){
|
||||||
|
lineEnd = nextR;
|
||||||
|
if(nextN == (nextR + 1))
|
||||||
|
nextLine = nextN + 1;
|
||||||
|
else
|
||||||
|
nextLine = nextR + 1;
|
||||||
|
} else {
|
||||||
|
lineEnd = nextN;
|
||||||
|
if(nextR == (nextN + 1))
|
||||||
|
nextLine = nextR + 1;
|
||||||
|
else
|
||||||
|
nextLine = nextN + 1;
|
||||||
|
}
|
||||||
|
} else if(nextN != NULL){
|
||||||
|
lineEnd = nextN;
|
||||||
|
nextLine = nextN + 1;
|
||||||
|
} else {
|
||||||
|
lineEnd = nextR;
|
||||||
|
nextLine = nextR + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t llen = lineEnd - lineStart;
|
||||||
|
char * ldata = (char *)malloc(llen+1);
|
||||||
|
if(ldata != NULL){
|
||||||
|
memcpy(ldata, lineStart, llen);
|
||||||
|
ldata[llen] = 0;
|
||||||
|
ev += "data: ";
|
||||||
|
ev += ldata;
|
||||||
|
ev += "\r\n";
|
||||||
|
free(ldata);
|
||||||
|
}
|
||||||
|
lineStart = nextLine;
|
||||||
|
if(lineStart == ((char *)message + messageLen))
|
||||||
|
ev += "\r\n";
|
||||||
|
}
|
||||||
|
} while(lineStart < ((char *)message + messageLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message
|
||||||
|
|
||||||
|
AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len)
|
||||||
|
: _data(nullptr), _len(len), _sent(0), _acked(0)
|
||||||
|
{
|
||||||
|
_data = (uint8_t*)malloc(_len+1);
|
||||||
|
if(_data == nullptr){
|
||||||
|
_len = 0;
|
||||||
|
} else {
|
||||||
|
memcpy(_data, data, len);
|
||||||
|
_data[_len] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncEventSourceMessage::~AsyncEventSourceMessage() {
|
||||||
|
if(_data != NULL)
|
||||||
|
free(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
|
||||||
|
(void)time;
|
||||||
|
// If the whole message is now acked...
|
||||||
|
if(_acked + len > _len){
|
||||||
|
// Return the number of extra bytes acked (they will be carried on to the next message)
|
||||||
|
const size_t extra = _acked + len - _len;
|
||||||
|
_acked = _len;
|
||||||
|
return extra;
|
||||||
|
}
|
||||||
|
// Return that no extra bytes left.
|
||||||
|
_acked += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncEventSourceMessage::send(AsyncClient *client) {
|
||||||
|
const size_t len = _len - _sent;
|
||||||
|
if(client->space() < len){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t sent = client->add((const char *)_data, len);
|
||||||
|
if(client->canSend())
|
||||||
|
client->send();
|
||||||
|
_sent += sent;
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client
|
||||||
|
|
||||||
|
AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server)
|
||||||
|
: _messageQueue(LinkedList<AsyncEventSourceMessage *>([](AsyncEventSourceMessage *m){ delete m; }))
|
||||||
|
{
|
||||||
|
_client = request->client();
|
||||||
|
_server = server;
|
||||||
|
_lastId = 0;
|
||||||
|
if(request->hasHeader("Last-Event-ID"))
|
||||||
|
_lastId = atoi(request->getHeader("Last-Event-ID")->value().c_str());
|
||||||
|
|
||||||
|
_client->setRxTimeout(0);
|
||||||
|
_client->onError(NULL, NULL);
|
||||||
|
_client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this);
|
||||||
|
_client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this);
|
||||||
|
_client->onData(NULL, NULL);
|
||||||
|
_client->onTimeout([this](void *r, AsyncClient* c __attribute__((unused)), uint32_t time){ ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this);
|
||||||
|
_client->onDisconnect([this](void *r, AsyncClient* c){ ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this);
|
||||||
|
|
||||||
|
_server->_addClient(this);
|
||||||
|
delete request;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncEventSourceClient::~AsyncEventSourceClient(){
|
||||||
|
_messageQueue.free();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage *dataMessage){
|
||||||
|
if(dataMessage == NULL)
|
||||||
|
return;
|
||||||
|
if(!connected()){
|
||||||
|
delete dataMessage;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){
|
||||||
|
ets_printf("ERROR: Too many messages queued\n");
|
||||||
|
delete dataMessage;
|
||||||
|
} else {
|
||||||
|
_messageQueue.add(dataMessage);
|
||||||
|
}
|
||||||
|
if(_client->canSend())
|
||||||
|
_runQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){
|
||||||
|
while(len && !_messageQueue.isEmpty()){
|
||||||
|
len = _messageQueue.front()->ack(len, time);
|
||||||
|
if(_messageQueue.front()->finished())
|
||||||
|
_messageQueue.remove(_messageQueue.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
_runQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_onPoll(){
|
||||||
|
if(!_messageQueue.isEmpty()){
|
||||||
|
_runQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){
|
||||||
|
_client->close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_onDisconnect(){
|
||||||
|
_client = NULL;
|
||||||
|
_server->_handleDisconnect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::close(){
|
||||||
|
if(_client != NULL)
|
||||||
|
_client->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::write(const char * message, size_t len){
|
||||||
|
_queueMessage(new AsyncEventSourceMessage(message, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
||||||
|
String ev = generateEventMessage(message, event, id, reconnect);
|
||||||
|
_queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceClient::_runQueue(){
|
||||||
|
while(!_messageQueue.isEmpty() && _messageQueue.front()->finished()){
|
||||||
|
_messageQueue.remove(_messageQueue.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i)
|
||||||
|
{
|
||||||
|
if(!(*i)->sent())
|
||||||
|
(*i)->send(_client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
|
||||||
|
AsyncEventSource::AsyncEventSource(const String& url)
|
||||||
|
: _url(url)
|
||||||
|
, _clients(LinkedList<AsyncEventSourceClient *>([](AsyncEventSourceClient *c){ delete c; }))
|
||||||
|
, _connectcb(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
AsyncEventSource::~AsyncEventSource(){
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::onConnect(ArEventHandlerFunction cb){
|
||||||
|
_connectcb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::_addClient(AsyncEventSourceClient * client){
|
||||||
|
/*char * temp = (char *)malloc(2054);
|
||||||
|
if(temp != NULL){
|
||||||
|
memset(temp+1,' ',2048);
|
||||||
|
temp[0] = ':';
|
||||||
|
temp[2049] = '\r';
|
||||||
|
temp[2050] = '\n';
|
||||||
|
temp[2051] = '\r';
|
||||||
|
temp[2052] = '\n';
|
||||||
|
temp[2053] = 0;
|
||||||
|
client->write((const char *)temp, 2053);
|
||||||
|
free(temp);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
_clients.add(client);
|
||||||
|
if(_connectcb)
|
||||||
|
_connectcb(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){
|
||||||
|
_clients.remove(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::close(){
|
||||||
|
for(const auto &c: _clients){
|
||||||
|
if(c->connected())
|
||||||
|
c->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pmb fix
|
||||||
|
size_t AsyncEventSource::avgPacketsWaiting() const {
|
||||||
|
if(_clients.isEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size_t aql=0;
|
||||||
|
uint32_t nConnectedClients=0;
|
||||||
|
|
||||||
|
for(const auto &c: _clients){
|
||||||
|
if(c->connected()) {
|
||||||
|
aql+=c->packetsWaiting();
|
||||||
|
++nConnectedClients;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return aql / nConnectedClients;
|
||||||
|
return ((aql) + (nConnectedClients/2))/(nConnectedClients); // round up
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){
|
||||||
|
|
||||||
|
|
||||||
|
String ev = generateEventMessage(message, event, id, reconnect);
|
||||||
|
for(const auto &c: _clients){
|
||||||
|
if(c->connected()) {
|
||||||
|
c->write(ev.c_str(), ev.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncEventSource::count() const {
|
||||||
|
return _clients.count_if([](AsyncEventSourceClient *c){
|
||||||
|
return c->connected();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){
|
||||||
|
if(request->method() != HTTP_GET || !request->url().equals(_url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
request->addInterestingHeader("Last-Event-ID");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){
|
||||||
|
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
request->send(new AsyncEventSourceResponse(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response
|
||||||
|
|
||||||
|
AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){
|
||||||
|
_server = server;
|
||||||
|
_code = 200;
|
||||||
|
_contentType = "text/event-stream";
|
||||||
|
_sendContentLength = false;
|
||||||
|
addHeader("Cache-Control", "no-cache");
|
||||||
|
addHeader("Connection","keep-alive");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncEventSourceResponse::_respond(AsyncWebServerRequest *request){
|
||||||
|
String out = _assembleHead(request->version());
|
||||||
|
request->client()->write(out.c_str(), _headLength);
|
||||||
|
_state = RESPONSE_WAIT_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time __attribute__((unused))){
|
||||||
|
if(len){
|
||||||
|
new AsyncEventSourceClient(request, _server);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
133
lib/ESPAsyncWebServer/src/AsyncEventSource.h
Normal file
133
lib/ESPAsyncWebServer/src/AsyncEventSource.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
|
||||||
|
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 ASYNCEVENTSOURCE_H_
|
||||||
|
#define ASYNCEVENTSOURCE_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#define SSE_MAX_QUEUED_MESSAGES 32
|
||||||
|
#else
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#define SSE_MAX_QUEUED_MESSAGES 8
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#include "AsyncWebSynchronization.h"
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <Hash.h>
|
||||||
|
#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
|
||||||
|
#include <../src/Hash.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#define DEFAULT_MAX_SSE_CLIENTS 8
|
||||||
|
#else
|
||||||
|
#define DEFAULT_MAX_SSE_CLIENTS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class AsyncEventSource;
|
||||||
|
class AsyncEventSourceResponse;
|
||||||
|
class AsyncEventSourceClient;
|
||||||
|
typedef std::function<void(AsyncEventSourceClient *client)> ArEventHandlerFunction;
|
||||||
|
|
||||||
|
class AsyncEventSourceMessage {
|
||||||
|
private:
|
||||||
|
uint8_t * _data;
|
||||||
|
size_t _len;
|
||||||
|
size_t _sent;
|
||||||
|
//size_t _ack;
|
||||||
|
size_t _acked;
|
||||||
|
public:
|
||||||
|
AsyncEventSourceMessage(const char * data, size_t len);
|
||||||
|
~AsyncEventSourceMessage();
|
||||||
|
size_t ack(size_t len, uint32_t time __attribute__((unused)));
|
||||||
|
size_t send(AsyncClient *client);
|
||||||
|
bool finished(){ return _acked == _len; }
|
||||||
|
bool sent() { return _sent == _len; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncEventSourceClient {
|
||||||
|
private:
|
||||||
|
AsyncClient *_client;
|
||||||
|
AsyncEventSource *_server;
|
||||||
|
uint32_t _lastId;
|
||||||
|
LinkedList<AsyncEventSourceMessage *> _messageQueue;
|
||||||
|
void _queueMessage(AsyncEventSourceMessage *dataMessage);
|
||||||
|
void _runQueue();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server);
|
||||||
|
~AsyncEventSourceClient();
|
||||||
|
|
||||||
|
AsyncClient* client(){ return _client; }
|
||||||
|
void close();
|
||||||
|
void write(const char * message, size_t len);
|
||||||
|
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
|
||||||
|
bool connected() const { return (_client != NULL) && _client->connected(); }
|
||||||
|
uint32_t lastId() const { return _lastId; }
|
||||||
|
size_t packetsWaiting() const { return _messageQueue.length(); }
|
||||||
|
|
||||||
|
//system callbacks (do not call)
|
||||||
|
void _onAck(size_t len, uint32_t time);
|
||||||
|
void _onPoll();
|
||||||
|
void _onTimeout(uint32_t time);
|
||||||
|
void _onDisconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncEventSource: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
String _url;
|
||||||
|
LinkedList<AsyncEventSourceClient *> _clients;
|
||||||
|
ArEventHandlerFunction _connectcb;
|
||||||
|
public:
|
||||||
|
AsyncEventSource(const String& url);
|
||||||
|
~AsyncEventSource();
|
||||||
|
|
||||||
|
const char * url() const { return _url.c_str(); }
|
||||||
|
void close();
|
||||||
|
void onConnect(ArEventHandlerFunction cb);
|
||||||
|
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
|
||||||
|
size_t count() const; //number clinets connected
|
||||||
|
size_t avgPacketsWaiting() const;
|
||||||
|
|
||||||
|
//system callbacks (do not call)
|
||||||
|
void _addClient(AsyncEventSourceClient * client);
|
||||||
|
void _handleDisconnect(AsyncEventSourceClient * client);
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncEventSourceResponse: public AsyncWebServerResponse {
|
||||||
|
private:
|
||||||
|
String _content;
|
||||||
|
AsyncEventSource *_server;
|
||||||
|
public:
|
||||||
|
AsyncEventSourceResponse(AsyncEventSource *server);
|
||||||
|
void _respond(AsyncWebServerRequest *request);
|
||||||
|
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
||||||
|
bool _sourceValid() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ASYNCEVENTSOURCE_H_ */
|
||||||
252
lib/ESPAsyncWebServer/src/AsyncJson.h
Normal file
252
lib/ESPAsyncWebServer/src/AsyncJson.h
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
// AsyncJson.h
|
||||||
|
/*
|
||||||
|
Async Response to use with ArduinoJson and AsyncWebServer
|
||||||
|
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon.
|
||||||
|
|
||||||
|
Example of callback in use
|
||||||
|
|
||||||
|
server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
|
||||||
|
|
||||||
|
AsyncJsonResponse * response = new AsyncJsonResponse();
|
||||||
|
JsonObject& root = response->getRoot();
|
||||||
|
root["key1"] = "key number one";
|
||||||
|
JsonObject& nested = root.createNestedObject("nested");
|
||||||
|
nested["key1"] = "key number one";
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Async Request to use with ArduinoJson and AsyncWebServer
|
||||||
|
Written by Arsène von Wyss (avonwyss)
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint");
|
||||||
|
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
|
JsonObject& jsonObj = json.as<JsonObject>();
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
server.addHandler(handler);
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef ASYNC_JSON_H_
|
||||||
|
#define ASYNC_JSON_H_
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <Print.h>
|
||||||
|
|
||||||
|
#if ARDUINOJSON_VERSION_MAJOR == 5
|
||||||
|
#define ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
#else
|
||||||
|
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr const char* JSON_MIMETYPE = "application/json";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Json Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
class ChunkPrint : public Print {
|
||||||
|
private:
|
||||||
|
uint8_t* _destination;
|
||||||
|
size_t _to_skip;
|
||||||
|
size_t _to_write;
|
||||||
|
size_t _pos;
|
||||||
|
public:
|
||||||
|
ChunkPrint(uint8_t* destination, size_t from, size_t len)
|
||||||
|
: _destination(destination), _to_skip(from), _to_write(len), _pos{0} {}
|
||||||
|
virtual ~ChunkPrint(){}
|
||||||
|
size_t write(uint8_t c){
|
||||||
|
if (_to_skip > 0) {
|
||||||
|
_to_skip--;
|
||||||
|
return 1;
|
||||||
|
} else if (_to_write > 0) {
|
||||||
|
_to_write--;
|
||||||
|
_destination[_pos++] = c;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t write(const uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
return this->Print::write(buffer, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncJsonResponse: public AsyncAbstractResponse {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
DynamicJsonBuffer _jsonBuffer;
|
||||||
|
#else
|
||||||
|
DynamicJsonDocument _jsonBuffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonVariant _root;
|
||||||
|
bool _isValid;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
AsyncJsonResponse(bool isArray=false): _isValid{false} {
|
||||||
|
_code = 200;
|
||||||
|
_contentType = JSON_MIMETYPE;
|
||||||
|
if(isArray)
|
||||||
|
_root = _jsonBuffer.createArray();
|
||||||
|
else
|
||||||
|
_root = _jsonBuffer.createObject();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
AsyncJsonResponse(bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
|
||||||
|
_code = 200;
|
||||||
|
_contentType = JSON_MIMETYPE;
|
||||||
|
if(isArray)
|
||||||
|
_root = _jsonBuffer.createNestedArray();
|
||||||
|
else
|
||||||
|
_root = _jsonBuffer.createNestedObject();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
~AsyncJsonResponse() {}
|
||||||
|
JsonVariant & getRoot() { return _root; }
|
||||||
|
bool _sourceValid() const { return _isValid; }
|
||||||
|
size_t setLength() {
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
_contentLength = _root.measureLength();
|
||||||
|
#else
|
||||||
|
_contentLength = measureJson(_root);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_contentLength) { _isValid = true; }
|
||||||
|
return _contentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getSize() { return _jsonBuffer.size(); }
|
||||||
|
|
||||||
|
size_t _fillBuffer(uint8_t *data, size_t len){
|
||||||
|
ChunkPrint dest(data, _sentLength, len);
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
_root.printTo( dest ) ;
|
||||||
|
#else
|
||||||
|
serializeJson(_root, dest);
|
||||||
|
#endif
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PrettyAsyncJsonResponse: public AsyncJsonResponse {
|
||||||
|
public:
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
PrettyAsyncJsonResponse (bool isArray=false) : AsyncJsonResponse{isArray} {}
|
||||||
|
#else
|
||||||
|
PrettyAsyncJsonResponse (bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : AsyncJsonResponse{isArray, maxJsonBufferSize} {}
|
||||||
|
#endif
|
||||||
|
size_t setLength () {
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
_contentLength = _root.measurePrettyLength ();
|
||||||
|
#else
|
||||||
|
_contentLength = measureJsonPretty(_root);
|
||||||
|
#endif
|
||||||
|
if (_contentLength) {_isValid = true;}
|
||||||
|
return _contentLength;
|
||||||
|
}
|
||||||
|
size_t _fillBuffer (uint8_t *data, size_t len) {
|
||||||
|
ChunkPrint dest (data, _sentLength, len);
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
_root.prettyPrintTo (dest);
|
||||||
|
#else
|
||||||
|
serializeJsonPretty(_root, dest);
|
||||||
|
#endif
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant &json)> ArJsonRequestHandlerFunction;
|
||||||
|
|
||||||
|
class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
protected:
|
||||||
|
const String _uri;
|
||||||
|
WebRequestMethodComposite _method;
|
||||||
|
ArJsonRequestHandlerFunction _onRequest;
|
||||||
|
size_t _contentLength;
|
||||||
|
#ifndef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
const size_t maxJsonBufferSize;
|
||||||
|
#endif
|
||||||
|
size_t _maxContentLength;
|
||||||
|
public:
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest)
|
||||||
|
: _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
||||||
|
#else
|
||||||
|
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMIC_JSON_DOCUMENT_SIZE)
|
||||||
|
: _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
||||||
|
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
|
||||||
|
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
|
||||||
|
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final{
|
||||||
|
if(!_onRequest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!(_method & request->method()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( !request->contentType().equalsIgnoreCase(JSON_MIMETYPE) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
request->addInterestingHeader("ANY");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
||||||
|
if(_onRequest) {
|
||||||
|
if (request->_tempObject != NULL) {
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_5_COMPATIBILITY
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject));
|
||||||
|
if (json.success()) {
|
||||||
|
#else
|
||||||
|
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
|
||||||
|
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
|
||||||
|
if(!error) {
|
||||||
|
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_onRequest(request, json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request->send(_contentLength > _maxContentLength ? 413 : 400);
|
||||||
|
} else {
|
||||||
|
request->send(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
|
||||||
|
}
|
||||||
|
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||||
|
if (_onRequest) {
|
||||||
|
_contentLength = total;
|
||||||
|
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
|
||||||
|
request->_tempObject = malloc(total);
|
||||||
|
}
|
||||||
|
if (request->_tempObject != NULL) {
|
||||||
|
memcpy((uint8_t*)(request->_tempObject) + index, data, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
1303
lib/ESPAsyncWebServer/src/AsyncWebSocket.cpp
Normal file
1303
lib/ESPAsyncWebServer/src/AsyncWebSocket.cpp
Normal file
File diff suppressed because it is too large
Load Diff
350
lib/ESPAsyncWebServer/src/AsyncWebSocket.h
Normal file
350
lib/ESPAsyncWebServer/src/AsyncWebSocket.h
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 ASYNCWEBSOCKET_H_
|
||||||
|
#define ASYNCWEBSOCKET_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#define WS_MAX_QUEUED_MESSAGES 32
|
||||||
|
#else
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#define WS_MAX_QUEUED_MESSAGES 8
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#include "AsyncWebSynchronization.h"
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <Hash.h>
|
||||||
|
#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
|
||||||
|
#include <../src/Hash.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#define DEFAULT_MAX_WS_CLIENTS 8
|
||||||
|
#else
|
||||||
|
#define DEFAULT_MAX_WS_CLIENTS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class AsyncWebSocket;
|
||||||
|
class AsyncWebSocketResponse;
|
||||||
|
class AsyncWebSocketClient;
|
||||||
|
class AsyncWebSocketControl;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/** Message type as defined by enum AwsFrameType.
|
||||||
|
* Note: Applications will only see WS_TEXT and WS_BINARY.
|
||||||
|
* All other types are handled by the library. */
|
||||||
|
uint8_t message_opcode;
|
||||||
|
/** Frame number of a fragmented message. */
|
||||||
|
uint32_t num;
|
||||||
|
/** Is this the last frame in a fragmented message ?*/
|
||||||
|
uint8_t final;
|
||||||
|
/** Is this frame masked? */
|
||||||
|
uint8_t masked;
|
||||||
|
/** Message type as defined by enum AwsFrameType.
|
||||||
|
* This value is the same as message_opcode for non-fragmented
|
||||||
|
* messages, but may also be WS_CONTINUATION in a fragmented message. */
|
||||||
|
uint8_t opcode;
|
||||||
|
/** Length of the current frame.
|
||||||
|
* This equals the total length of the message if num == 0 && final == true */
|
||||||
|
uint64_t len;
|
||||||
|
/** Mask key */
|
||||||
|
uint8_t mask[4];
|
||||||
|
/** Offset of the data inside the current frame. */
|
||||||
|
uint64_t index;
|
||||||
|
} AwsFrameInfo;
|
||||||
|
|
||||||
|
typedef enum { WS_DISCONNECTED, WS_CONNECTED, WS_DISCONNECTING } AwsClientStatus;
|
||||||
|
typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PING, WS_PONG } AwsFrameType;
|
||||||
|
typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus;
|
||||||
|
typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType;
|
||||||
|
|
||||||
|
class AsyncWebSocketMessageBuffer {
|
||||||
|
private:
|
||||||
|
uint8_t * _data;
|
||||||
|
size_t _len;
|
||||||
|
bool _lock;
|
||||||
|
uint32_t _count;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebSocketMessageBuffer();
|
||||||
|
AsyncWebSocketMessageBuffer(size_t size);
|
||||||
|
AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
|
||||||
|
AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer &);
|
||||||
|
AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer &&);
|
||||||
|
~AsyncWebSocketMessageBuffer();
|
||||||
|
void operator ++(int i) { (void)i; _count++; }
|
||||||
|
void operator --(int i) { (void)i; if (_count > 0) { _count--; } ; }
|
||||||
|
bool reserve(size_t size);
|
||||||
|
void lock() { _lock = true; }
|
||||||
|
void unlock() { _lock = false; }
|
||||||
|
uint8_t * get() { return _data; }
|
||||||
|
size_t length() { return _len; }
|
||||||
|
uint32_t count() { return _count; }
|
||||||
|
bool canDelete() { return (!_count && !_lock); }
|
||||||
|
|
||||||
|
friend AsyncWebSocket;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncWebSocketMessage {
|
||||||
|
protected:
|
||||||
|
uint8_t _opcode;
|
||||||
|
bool _mask;
|
||||||
|
AwsMessageStatus _status;
|
||||||
|
public:
|
||||||
|
AsyncWebSocketMessage():_opcode(WS_TEXT),_mask(false),_status(WS_MSG_ERROR){}
|
||||||
|
virtual ~AsyncWebSocketMessage(){}
|
||||||
|
virtual void ack(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))){}
|
||||||
|
virtual size_t send(AsyncClient *client __attribute__((unused))){ return 0; }
|
||||||
|
virtual bool finished(){ return _status != WS_MSG_SENDING; }
|
||||||
|
virtual bool betweenFrames() const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage {
|
||||||
|
private:
|
||||||
|
size_t _len;
|
||||||
|
size_t _sent;
|
||||||
|
size_t _ack;
|
||||||
|
size_t _acked;
|
||||||
|
uint8_t * _data;
|
||||||
|
public:
|
||||||
|
AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode=WS_TEXT, bool mask=false);
|
||||||
|
AsyncWebSocketBasicMessage(uint8_t opcode=WS_TEXT, bool mask=false);
|
||||||
|
virtual ~AsyncWebSocketBasicMessage() override;
|
||||||
|
virtual bool betweenFrames() const override { return _acked == _ack; }
|
||||||
|
virtual void ack(size_t len, uint32_t time) override ;
|
||||||
|
virtual size_t send(AsyncClient *client) override ;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage {
|
||||||
|
private:
|
||||||
|
uint8_t * _data;
|
||||||
|
size_t _len;
|
||||||
|
size_t _sent;
|
||||||
|
size_t _ack;
|
||||||
|
size_t _acked;
|
||||||
|
AsyncWebSocketMessageBuffer * _WSbuffer;
|
||||||
|
public:
|
||||||
|
AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode=WS_TEXT, bool mask=false);
|
||||||
|
virtual ~AsyncWebSocketMultiMessage() override;
|
||||||
|
virtual bool betweenFrames() const override { return _acked == _ack; }
|
||||||
|
virtual void ack(size_t len, uint32_t time) override ;
|
||||||
|
virtual size_t send(AsyncClient *client) override ;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncWebSocketClient {
|
||||||
|
private:
|
||||||
|
AsyncClient *_client;
|
||||||
|
AsyncWebSocket *_server;
|
||||||
|
uint32_t _clientId;
|
||||||
|
AwsClientStatus _status;
|
||||||
|
|
||||||
|
LinkedList<AsyncWebSocketControl *> _controlQueue;
|
||||||
|
LinkedList<AsyncWebSocketMessage *> _messageQueue;
|
||||||
|
|
||||||
|
uint8_t _pstate;
|
||||||
|
AwsFrameInfo _pinfo;
|
||||||
|
|
||||||
|
uint32_t _lastMessageTime;
|
||||||
|
uint32_t _keepAlivePeriod;
|
||||||
|
|
||||||
|
void _queueMessage(AsyncWebSocketMessage *dataMessage);
|
||||||
|
void _queueControl(AsyncWebSocketControl *controlMessage);
|
||||||
|
void _runQueue();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void *_tempObject;
|
||||||
|
|
||||||
|
AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server);
|
||||||
|
~AsyncWebSocketClient();
|
||||||
|
|
||||||
|
//client id increments for the given server
|
||||||
|
uint32_t id(){ return _clientId; }
|
||||||
|
AwsClientStatus status(){ return _status; }
|
||||||
|
AsyncClient* client(){ return _client; }
|
||||||
|
AsyncWebSocket *server(){ return _server; }
|
||||||
|
AwsFrameInfo const &pinfo() const { return _pinfo; }
|
||||||
|
|
||||||
|
IPAddress remoteIP();
|
||||||
|
uint16_t remotePort();
|
||||||
|
|
||||||
|
//control frames
|
||||||
|
void close(uint16_t code=0, const char * message=NULL);
|
||||||
|
void ping(uint8_t *data=NULL, size_t len=0);
|
||||||
|
|
||||||
|
//set auto-ping period in seconds. disabled if zero (default)
|
||||||
|
void keepAlivePeriod(uint16_t seconds){
|
||||||
|
_keepAlivePeriod = seconds * 1000;
|
||||||
|
}
|
||||||
|
uint16_t keepAlivePeriod(){
|
||||||
|
return (uint16_t)(_keepAlivePeriod / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//data packets
|
||||||
|
void message(AsyncWebSocketMessage *message){ _queueMessage(message); }
|
||||||
|
bool queueIsFull();
|
||||||
|
|
||||||
|
size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#ifndef ESP32
|
||||||
|
size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#endif
|
||||||
|
void text(const char * message, size_t len);
|
||||||
|
void text(const char * message);
|
||||||
|
void text(uint8_t * message, size_t len);
|
||||||
|
void text(char * message);
|
||||||
|
void text(const String &message);
|
||||||
|
void text(const __FlashStringHelper *data);
|
||||||
|
void text(AsyncWebSocketMessageBuffer *buffer);
|
||||||
|
|
||||||
|
void binary(const char * message, size_t len);
|
||||||
|
void binary(const char * message);
|
||||||
|
void binary(uint8_t * message, size_t len);
|
||||||
|
void binary(char * message);
|
||||||
|
void binary(const String &message);
|
||||||
|
void binary(const __FlashStringHelper *data, size_t len);
|
||||||
|
void binary(AsyncWebSocketMessageBuffer *buffer);
|
||||||
|
|
||||||
|
bool canSend() { return _messageQueue.length() < WS_MAX_QUEUED_MESSAGES; }
|
||||||
|
|
||||||
|
//system callbacks (do not call)
|
||||||
|
void _onAck(size_t len, uint32_t time);
|
||||||
|
void _onError(int8_t);
|
||||||
|
void _onPoll();
|
||||||
|
void _onTimeout(uint32_t time);
|
||||||
|
void _onDisconnect();
|
||||||
|
void _onData(void *pbuf, size_t plen);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;
|
||||||
|
|
||||||
|
//WebServer Handler implementation that plays the role of a socket server
|
||||||
|
class AsyncWebSocket: public AsyncWebHandler {
|
||||||
|
public:
|
||||||
|
typedef LinkedList<AsyncWebSocketClient *> AsyncWebSocketClientLinkedList;
|
||||||
|
private:
|
||||||
|
String _url;
|
||||||
|
AsyncWebSocketClientLinkedList _clients;
|
||||||
|
uint32_t _cNextId;
|
||||||
|
AwsEventHandler _eventHandler;
|
||||||
|
bool _enabled;
|
||||||
|
AsyncWebLock _lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebSocket(const String& url);
|
||||||
|
~AsyncWebSocket();
|
||||||
|
const char * url() const { return _url.c_str(); }
|
||||||
|
void enable(bool e){ _enabled = e; }
|
||||||
|
bool enabled() const { return _enabled; }
|
||||||
|
bool availableForWriteAll();
|
||||||
|
bool availableForWrite(uint32_t id);
|
||||||
|
|
||||||
|
size_t count() const;
|
||||||
|
AsyncWebSocketClient * client(uint32_t id);
|
||||||
|
bool hasClient(uint32_t id){ return client(id) != NULL; }
|
||||||
|
|
||||||
|
void close(uint32_t id, uint16_t code=0, const char * message=NULL);
|
||||||
|
void closeAll(uint16_t code=0, const char * message=NULL);
|
||||||
|
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
|
||||||
|
|
||||||
|
void ping(uint32_t id, uint8_t *data=NULL, size_t len=0);
|
||||||
|
void pingAll(uint8_t *data=NULL, size_t len=0); // done
|
||||||
|
|
||||||
|
void text(uint32_t id, const char * message, size_t len);
|
||||||
|
void text(uint32_t id, const char * message);
|
||||||
|
void text(uint32_t id, uint8_t * message, size_t len);
|
||||||
|
void text(uint32_t id, char * message);
|
||||||
|
void text(uint32_t id, const String &message);
|
||||||
|
void text(uint32_t id, const __FlashStringHelper *message);
|
||||||
|
|
||||||
|
void textAll(const char * message, size_t len);
|
||||||
|
void textAll(const char * message);
|
||||||
|
void textAll(uint8_t * message, size_t len);
|
||||||
|
void textAll(char * message);
|
||||||
|
void textAll(const String &message);
|
||||||
|
void textAll(const __FlashStringHelper *message); // need to convert
|
||||||
|
void textAll(AsyncWebSocketMessageBuffer * buffer);
|
||||||
|
|
||||||
|
void binary(uint32_t id, const char * message, size_t len);
|
||||||
|
void binary(uint32_t id, const char * message);
|
||||||
|
void binary(uint32_t id, uint8_t * message, size_t len);
|
||||||
|
void binary(uint32_t id, char * message);
|
||||||
|
void binary(uint32_t id, const String &message);
|
||||||
|
void binary(uint32_t id, const __FlashStringHelper *message, size_t len);
|
||||||
|
|
||||||
|
void binaryAll(const char * message, size_t len);
|
||||||
|
void binaryAll(const char * message);
|
||||||
|
void binaryAll(uint8_t * message, size_t len);
|
||||||
|
void binaryAll(char * message);
|
||||||
|
void binaryAll(const String &message);
|
||||||
|
void binaryAll(const __FlashStringHelper *message, size_t len);
|
||||||
|
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
|
||||||
|
|
||||||
|
void message(uint32_t id, AsyncWebSocketMessage *message);
|
||||||
|
void messageAll(AsyncWebSocketMultiMessage *message);
|
||||||
|
|
||||||
|
size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
|
size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#ifndef ESP32
|
||||||
|
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
|
#endif
|
||||||
|
size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
|
//event listener
|
||||||
|
void onEvent(AwsEventHandler handler){
|
||||||
|
_eventHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
//system callbacks (do not call)
|
||||||
|
uint32_t _getNextId(){ return _cNextId++; }
|
||||||
|
void _addClient(AsyncWebSocketClient * client);
|
||||||
|
void _handleDisconnect(AsyncWebSocketClient * client);
|
||||||
|
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
|
|
||||||
|
|
||||||
|
// messagebuffer functions/objects.
|
||||||
|
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
|
||||||
|
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);
|
||||||
|
LinkedList<AsyncWebSocketMessageBuffer *> _buffers;
|
||||||
|
void _cleanBuffers();
|
||||||
|
|
||||||
|
AsyncWebSocketClientLinkedList getClients() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//WebServer response to authenticate the socket and detach the tcp client from the web server request
|
||||||
|
class AsyncWebSocketResponse: public AsyncWebServerResponse {
|
||||||
|
private:
|
||||||
|
String _content;
|
||||||
|
AsyncWebSocket *_server;
|
||||||
|
public:
|
||||||
|
AsyncWebSocketResponse(const String& key, AsyncWebSocket *server);
|
||||||
|
void _respond(AsyncWebServerRequest *request);
|
||||||
|
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
||||||
|
bool _sourceValid() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ASYNCWEBSOCKET_H_ */
|
||||||
87
lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h
Normal file
87
lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef ASYNCWEBSYNCHRONIZATION_H_
|
||||||
|
#define ASYNCWEBSYNCHRONIZATION_H_
|
||||||
|
|
||||||
|
// Synchronisation is only available on ESP32, as the ESP8266 isn't using FreeRTOS by default
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
|
||||||
|
// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore
|
||||||
|
class AsyncWebLock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SemaphoreHandle_t _lock;
|
||||||
|
mutable void *_lockedBy;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebLock() {
|
||||||
|
_lock = xSemaphoreCreateBinary();
|
||||||
|
_lockedBy = NULL;
|
||||||
|
xSemaphoreGive(_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncWebLock() {
|
||||||
|
vSemaphoreDelete(_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock() const {
|
||||||
|
extern void *pxCurrentTCB;
|
||||||
|
if (_lockedBy != pxCurrentTCB) {
|
||||||
|
xSemaphoreTake(_lock, portMAX_DELAY);
|
||||||
|
_lockedBy = pxCurrentTCB;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() const {
|
||||||
|
_lockedBy = NULL;
|
||||||
|
xSemaphoreGive(_lock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// This is the 8266 version of the Sync Lock which is currently unimplemented
|
||||||
|
class AsyncWebLock
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebLock() {
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncWebLock() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() const {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class AsyncWebLockGuard
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const AsyncWebLock *_lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebLockGuard(const AsyncWebLock &l) {
|
||||||
|
if (l.lock()) {
|
||||||
|
_lock = &l;
|
||||||
|
} else {
|
||||||
|
_lock = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncWebLockGuard() {
|
||||||
|
if (_lock) {
|
||||||
|
_lock->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ASYNCWEBSYNCHRONIZATION_H_
|
||||||
500
lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h
Normal file
500
lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 _ESPAsyncWebServer_H_
|
||||||
|
#define _ESPAsyncWebServer_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "FS.h"
|
||||||
|
#include "StringArray.h"
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#else
|
||||||
|
#error Platform not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ASYNCWEBSERVER_REGEX
|
||||||
|
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE
|
||||||
|
#else
|
||||||
|
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUGF(...) //Serial.printf(__VA_ARGS__)
|
||||||
|
|
||||||
|
class AsyncWebServer;
|
||||||
|
class AsyncWebServerRequest;
|
||||||
|
class AsyncWebServerResponse;
|
||||||
|
class AsyncWebHeader;
|
||||||
|
class AsyncWebParameter;
|
||||||
|
class AsyncWebRewrite;
|
||||||
|
class AsyncWebHandler;
|
||||||
|
class AsyncStaticWebHandler;
|
||||||
|
class AsyncCallbackWebHandler;
|
||||||
|
class AsyncResponseStream;
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#ifdef WEBSERVER_H
|
||||||
|
#define HTTP_ENUM
|
||||||
|
#endif
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#ifdef ESP8266WEBSERVER_H
|
||||||
|
#define HTTP_ENUM
|
||||||
|
#endif
|
||||||
|
#ifndef HTTP_ENUM
|
||||||
|
typedef enum { HTTP_GET = 0b00000001,
|
||||||
|
HTTP_POST = 0b00000010,
|
||||||
|
HTTP_DELETE = 0b00000100,
|
||||||
|
HTTP_PUT = 0b00001000,
|
||||||
|
HTTP_PATCH = 0b00010000,
|
||||||
|
HTTP_HEAD = 0b00100000,
|
||||||
|
HTTP_OPTIONS = 0b01000000,
|
||||||
|
HTTP_ANY = 0b01111111,
|
||||||
|
} WebRequestMethod;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if this value is returned when asked for data, packet will not be sent and you will be asked for data again
|
||||||
|
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
|
||||||
|
|
||||||
|
typedef uint8_t WebRequestMethodComposite;
|
||||||
|
typedef std::function<void(void)> ArDisconnectHandler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PARAMETER :: Chainable object to hold GET/POST and FILE parameters
|
||||||
|
* */
|
||||||
|
|
||||||
|
class AsyncWebParameter {
|
||||||
|
private:
|
||||||
|
String _name;
|
||||||
|
String _value;
|
||||||
|
size_t _size;
|
||||||
|
bool _isForm;
|
||||||
|
bool _isFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebParameter(const String& name, const String& value, bool form = false, bool file = false, size_t size = 0) : _name(name), _value(value), _size(size), _isForm(form), _isFile(file) {}
|
||||||
|
const String& name() const { return _name; }
|
||||||
|
const String& value() const { return _value; }
|
||||||
|
size_t size() const { return _size; }
|
||||||
|
bool isPost() const { return _isForm; }
|
||||||
|
bool isFile() const { return _isFile; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HEADER :: Chainable object to hold the headers
|
||||||
|
* */
|
||||||
|
|
||||||
|
class AsyncWebHeader {
|
||||||
|
private:
|
||||||
|
String _name;
|
||||||
|
String _value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebHeader(const String& name, const String& value) : _name(name), _value(value) {}
|
||||||
|
AsyncWebHeader(const String& data) : _name(), _value() {
|
||||||
|
if (!data) return;
|
||||||
|
int index = data.indexOf(':');
|
||||||
|
if (index < 0) return;
|
||||||
|
_name = data.substring(0, index);
|
||||||
|
_value = data.substring(index + 2);
|
||||||
|
}
|
||||||
|
~AsyncWebHeader() {}
|
||||||
|
const String& name() const { return _name; }
|
||||||
|
const String& value() const { return _value; }
|
||||||
|
String toString() const { return String(_name + ": " + _value + "\r\n"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
|
||||||
|
* */
|
||||||
|
|
||||||
|
typedef enum { RCT_NOT_USED = -1,
|
||||||
|
RCT_DEFAULT = 0,
|
||||||
|
RCT_HTTP,
|
||||||
|
RCT_WS,
|
||||||
|
RCT_EVENT,
|
||||||
|
RCT_MAX } RequestedConnectionType;
|
||||||
|
|
||||||
|
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
|
||||||
|
typedef std::function<String(const String&)> AwsTemplateProcessor;
|
||||||
|
|
||||||
|
class AsyncWebServerRequest {
|
||||||
|
using File = fs::File;
|
||||||
|
using FS = fs::FS;
|
||||||
|
friend class AsyncWebServer;
|
||||||
|
friend class AsyncCallbackWebHandler;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AsyncClient* _client;
|
||||||
|
AsyncWebServer* _server;
|
||||||
|
AsyncWebHandler* _handler;
|
||||||
|
AsyncWebServerResponse* _response;
|
||||||
|
StringArray _interestingHeaders;
|
||||||
|
ArDisconnectHandler _onDisconnectfn;
|
||||||
|
|
||||||
|
String _temp;
|
||||||
|
uint8_t _parseState;
|
||||||
|
|
||||||
|
uint8_t _version;
|
||||||
|
WebRequestMethodComposite _method;
|
||||||
|
String _url;
|
||||||
|
String _host;
|
||||||
|
String _contentType;
|
||||||
|
String _boundary;
|
||||||
|
String _authorization;
|
||||||
|
RequestedConnectionType _reqconntype;
|
||||||
|
void _removeNotInterestingHeaders();
|
||||||
|
bool _isDigest;
|
||||||
|
bool _isMultipart;
|
||||||
|
bool _isPlainPost;
|
||||||
|
bool _expectingContinue;
|
||||||
|
size_t _contentLength;
|
||||||
|
size_t _parsedLength;
|
||||||
|
|
||||||
|
LinkedList<AsyncWebHeader*> _headers;
|
||||||
|
LinkedList<AsyncWebParameter*> _params;
|
||||||
|
LinkedList<String*> _pathParams;
|
||||||
|
|
||||||
|
uint8_t _multiParseState;
|
||||||
|
uint8_t _boundaryPosition;
|
||||||
|
size_t _itemStartIndex;
|
||||||
|
size_t _itemSize;
|
||||||
|
String _itemName;
|
||||||
|
String _itemFilename;
|
||||||
|
String _itemType;
|
||||||
|
String _itemValue;
|
||||||
|
uint8_t* _itemBuffer;
|
||||||
|
size_t _itemBufferIndex;
|
||||||
|
bool _itemIsFile;
|
||||||
|
|
||||||
|
void _onPoll();
|
||||||
|
void _onAck(size_t len, uint32_t time);
|
||||||
|
void _onError(int8_t error);
|
||||||
|
void _onTimeout(uint32_t time);
|
||||||
|
void _onDisconnect();
|
||||||
|
void _onData(void* buf, size_t len);
|
||||||
|
|
||||||
|
void _addParam(AsyncWebParameter*);
|
||||||
|
void _addPathParam(const char* param);
|
||||||
|
|
||||||
|
bool _parseReqHead();
|
||||||
|
bool _parseReqHeader();
|
||||||
|
void _parseLine();
|
||||||
|
void _parsePlainPostChar(uint8_t data);
|
||||||
|
void _parseMultipartPostByte(uint8_t data, bool last);
|
||||||
|
void _addGetParams(const String& params);
|
||||||
|
|
||||||
|
void _handleUploadStart();
|
||||||
|
void _handleUploadByte(uint8_t data, bool last);
|
||||||
|
void _handleUploadEnd();
|
||||||
|
|
||||||
|
public:
|
||||||
|
File _tempFile;
|
||||||
|
void* _tempObject;
|
||||||
|
|
||||||
|
AsyncWebServerRequest(AsyncWebServer*, AsyncClient*);
|
||||||
|
~AsyncWebServerRequest();
|
||||||
|
|
||||||
|
AsyncClient* client() { return _client; }
|
||||||
|
uint8_t version() const { return _version; }
|
||||||
|
WebRequestMethodComposite method() const { return _method; }
|
||||||
|
const String& url() const { return _url; }
|
||||||
|
const String& host() const { return _host; }
|
||||||
|
const String& contentType() const { return _contentType; }
|
||||||
|
size_t contentLength() const { return _contentLength; }
|
||||||
|
bool multipart() const { return _isMultipart; }
|
||||||
|
const char* methodToString() const;
|
||||||
|
const char* requestedConnTypeToString() const;
|
||||||
|
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
||||||
|
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
||||||
|
void onDisconnect(ArDisconnectHandler fn);
|
||||||
|
|
||||||
|
//hash is the string representation of:
|
||||||
|
// base64(user:pass) for basic or
|
||||||
|
// user:realm:md5(user:realm:pass) for digest
|
||||||
|
bool authenticate(const char* hash);
|
||||||
|
bool authenticate(const char* username, const char* password, const char* realm = NULL, bool passwordIsHash = false);
|
||||||
|
void requestAuthentication(const char* realm = NULL, bool isDigest = true);
|
||||||
|
|
||||||
|
void setHandler(AsyncWebHandler* handler) { _handler = handler; }
|
||||||
|
void addInterestingHeader(const String& name);
|
||||||
|
|
||||||
|
void redirect(const String& url);
|
||||||
|
|
||||||
|
void send(AsyncWebServerResponse* response);
|
||||||
|
void send(int code, const String& contentType = String(), const String& content = String());
|
||||||
|
void send(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
|
void send(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
|
void send(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
|
void send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
|
void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
|
void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
|
void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
||||||
|
|
||||||
|
AsyncWebServerResponse* beginResponse(int code, const String& contentType = String(), const String& content = String());
|
||||||
|
AsyncWebServerResponse* beginResponse(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
|
AsyncWebServerResponse* beginResponse(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
|
AsyncWebServerResponse* beginResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
|
AsyncWebServerResponse* beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
|
AsyncWebServerResponse* beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
|
AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460);
|
||||||
|
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
|
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
||||||
|
|
||||||
|
size_t headers() const; // get header count
|
||||||
|
bool hasHeader(const String& name) const; // check if header exists
|
||||||
|
bool hasHeader(const __FlashStringHelper* data) const; // check if header exists
|
||||||
|
|
||||||
|
AsyncWebHeader* getHeader(const String& name) const;
|
||||||
|
AsyncWebHeader* getHeader(const __FlashStringHelper* data) const;
|
||||||
|
AsyncWebHeader* getHeader(size_t num) const;
|
||||||
|
|
||||||
|
size_t params() const; // get arguments count
|
||||||
|
bool hasParam(const String& name, bool post = false, bool file = false) const;
|
||||||
|
bool hasParam(const __FlashStringHelper* data, bool post = false, bool file = false) const;
|
||||||
|
|
||||||
|
AsyncWebParameter* getParam(const String& name, bool post = false, bool file = false) const;
|
||||||
|
AsyncWebParameter* getParam(const __FlashStringHelper* data, bool post, bool file) const;
|
||||||
|
AsyncWebParameter* getParam(size_t num) const;
|
||||||
|
|
||||||
|
size_t args() const { return params(); } // get arguments count
|
||||||
|
const String& arg(const String& name) const; // get request argument value by name
|
||||||
|
const String& arg(const __FlashStringHelper* data) const; // get request argument value by F(name)
|
||||||
|
const String& arg(size_t i) const; // get request argument value by number
|
||||||
|
const String& argName(size_t i) const; // get request argument name by number
|
||||||
|
bool hasArg(const char* name) const; // check if argument exists
|
||||||
|
bool hasArg(const __FlashStringHelper* data) const; // check if F(argument) exists
|
||||||
|
|
||||||
|
const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const;
|
||||||
|
|
||||||
|
const String& header(const char* name) const; // get request header value by name
|
||||||
|
const String& header(const __FlashStringHelper* data) const; // get request header value by F(name)
|
||||||
|
const String& header(size_t i) const; // get request header value by number
|
||||||
|
const String& headerName(size_t i) const; // get request header name by number
|
||||||
|
String urlDecode(const String& text) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
|
||||||
|
* */
|
||||||
|
|
||||||
|
typedef std::function<bool(AsyncWebServerRequest* request)> ArRequestFilterFunction;
|
||||||
|
|
||||||
|
bool ON_STA_FILTER(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
|
bool ON_AP_FILTER(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REWRITE :: One instance can be handle any Request (done by the Server)
|
||||||
|
* */
|
||||||
|
|
||||||
|
class AsyncWebRewrite {
|
||||||
|
protected:
|
||||||
|
String _from;
|
||||||
|
String _toUrl;
|
||||||
|
String _params;
|
||||||
|
ArRequestFilterFunction _filter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebRewrite(const char* from, const char* to) : _from(from), _toUrl(to), _params(String()), _filter(NULL) {
|
||||||
|
int index = _toUrl.indexOf('?');
|
||||||
|
if (index > 0) {
|
||||||
|
_params = _toUrl.substring(index + 1);
|
||||||
|
_toUrl = _toUrl.substring(0, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual ~AsyncWebRewrite() {}
|
||||||
|
AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) {
|
||||||
|
_filter = fn;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool filter(AsyncWebServerRequest* request) const { return _filter == NULL || _filter(request); }
|
||||||
|
const String& from(void) const { return _from; }
|
||||||
|
const String& toUrl(void) const { return _toUrl; }
|
||||||
|
const String& params(void) const { return _params; }
|
||||||
|
virtual bool match(AsyncWebServerRequest* request) { return from() == request->url() && filter(request); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HANDLER :: One instance can be attached to any Request (done by the Server)
|
||||||
|
* */
|
||||||
|
|
||||||
|
class AsyncWebHandler {
|
||||||
|
protected:
|
||||||
|
ArRequestFilterFunction _filter;
|
||||||
|
String _username;
|
||||||
|
String _password;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebHandler() : _username(""), _password("") {}
|
||||||
|
AsyncWebHandler& setFilter(ArRequestFilterFunction fn) {
|
||||||
|
_filter = fn;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
AsyncWebHandler& setAuthentication(const char* username, const char* password) {
|
||||||
|
_username = String(username);
|
||||||
|
_password = String(password);
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
bool filter(AsyncWebServerRequest* request) { return _filter == NULL || _filter(request); }
|
||||||
|
virtual ~AsyncWebHandler() {}
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest* request __attribute__((unused))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest* request __attribute__((unused))) {}
|
||||||
|
virtual void handleUpload(AsyncWebServerRequest* request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))) {}
|
||||||
|
virtual void handleBody(AsyncWebServerRequest* request __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))) {}
|
||||||
|
virtual bool isRequestHandlerTrivial() { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RESPONSE :: One instance is created for each Request (attached by the Handler)
|
||||||
|
* */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RESPONSE_SETUP,
|
||||||
|
RESPONSE_HEADERS,
|
||||||
|
RESPONSE_CONTENT,
|
||||||
|
RESPONSE_WAIT_ACK,
|
||||||
|
RESPONSE_END,
|
||||||
|
RESPONSE_FAILED
|
||||||
|
} WebResponseState;
|
||||||
|
|
||||||
|
class AsyncWebServerResponse {
|
||||||
|
protected:
|
||||||
|
int _code;
|
||||||
|
LinkedList<AsyncWebHeader*> _headers;
|
||||||
|
String _contentType;
|
||||||
|
size_t _contentLength;
|
||||||
|
bool _sendContentLength;
|
||||||
|
bool _chunked;
|
||||||
|
size_t _headLength;
|
||||||
|
size_t _sentLength;
|
||||||
|
size_t _ackedLength;
|
||||||
|
size_t _writtenLength;
|
||||||
|
WebResponseState _state;
|
||||||
|
const char* _responseCodeToString(int code);
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebServerResponse();
|
||||||
|
virtual ~AsyncWebServerResponse();
|
||||||
|
virtual void setCode(int code);
|
||||||
|
virtual void setContentLength(size_t len);
|
||||||
|
virtual void setContentType(const String& type);
|
||||||
|
virtual void addHeader(const String& name, const String& value);
|
||||||
|
virtual String _assembleHead(uint8_t version);
|
||||||
|
virtual bool _started() const;
|
||||||
|
virtual bool _finished() const;
|
||||||
|
virtual bool _failed() const;
|
||||||
|
virtual bool _sourceValid() const;
|
||||||
|
virtual void _respond(AsyncWebServerRequest* request);
|
||||||
|
virtual size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SERVER :: One instance
|
||||||
|
* */
|
||||||
|
|
||||||
|
typedef std::function<void(AsyncWebServerRequest* request)> ArRequestHandlerFunction;
|
||||||
|
typedef std::function<void(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final)> ArUploadHandlerFunction;
|
||||||
|
typedef std::function<void(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
||||||
|
|
||||||
|
class AsyncWebServer {
|
||||||
|
protected:
|
||||||
|
AsyncServer _server;
|
||||||
|
LinkedList<AsyncWebRewrite*> _rewrites;
|
||||||
|
LinkedList<AsyncWebHandler*> _handlers;
|
||||||
|
AsyncCallbackWebHandler* _catchAllHandler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebServer(uint16_t port);
|
||||||
|
~AsyncWebServer();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void end();
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
void onSslFileRequest(AcSSlFileHandler cb, void* arg);
|
||||||
|
void beginSecure(const char* cert, const char* private_key_file, const char* password);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite);
|
||||||
|
bool removeRewrite(AsyncWebRewrite* rewrite);
|
||||||
|
AsyncWebRewrite& rewrite(const char* from, const char* to);
|
||||||
|
|
||||||
|
AsyncWebHandler& addHandler(AsyncWebHandler* handler);
|
||||||
|
bool removeHandler(AsyncWebHandler* handler);
|
||||||
|
|
||||||
|
AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest);
|
||||||
|
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest);
|
||||||
|
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
|
||||||
|
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL);
|
||||||
|
|
||||||
|
void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned
|
||||||
|
void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads
|
||||||
|
void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request)
|
||||||
|
|
||||||
|
void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody
|
||||||
|
|
||||||
|
void _handleDisconnect(AsyncWebServerRequest* request);
|
||||||
|
void _attachHandler(AsyncWebServerRequest* request);
|
||||||
|
void _rewriteRequest(AsyncWebServerRequest* request);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultHeaders {
|
||||||
|
using headers_t = LinkedList<AsyncWebHeader*>;
|
||||||
|
headers_t _headers;
|
||||||
|
|
||||||
|
DefaultHeaders()
|
||||||
|
: _headers(headers_t([](AsyncWebHeader* h) { delete h; })) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using ConstIterator = headers_t::ConstIterator;
|
||||||
|
|
||||||
|
void addHeader(const String& name, const String& value) {
|
||||||
|
_headers.add(new AsyncWebHeader(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstIterator begin() const { return _headers.begin(); }
|
||||||
|
ConstIterator end() const { return _headers.end(); }
|
||||||
|
|
||||||
|
DefaultHeaders(DefaultHeaders const&) = delete;
|
||||||
|
DefaultHeaders& operator=(DefaultHeaders const&) = delete;
|
||||||
|
static DefaultHeaders& Instance() {
|
||||||
|
static DefaultHeaders instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "AsyncEventSource.h"
|
||||||
|
#include "AsyncWebSocket.h"
|
||||||
|
#include "WebHandlerImpl.h"
|
||||||
|
#include "WebResponseImpl.h"
|
||||||
|
|
||||||
|
#endif /* _AsyncWebServer_H_ */
|
||||||
544
lib/ESPAsyncWebServer/src/SPIFFSEditor.cpp
Normal file
544
lib/ESPAsyncWebServer/src/SPIFFSEditor.cpp
Normal file
@@ -0,0 +1,544 @@
|
|||||||
|
#include "SPIFFSEditor.h"
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
//File: edit.htm.gz, Size: 4151
|
||||||
|
#define edit_htm_gz_len 4151
|
||||||
|
const uint8_t edit_htm_gz[] PROGMEM = {
|
||||||
|
0x1F, 0x8B, 0x08, 0x08, 0xB8, 0x94, 0xB1, 0x59, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68,
|
||||||
|
0x74, 0x6D, 0x00, 0xB5, 0x3A, 0x0B, 0x7B, 0xDA, 0xB8, 0xB2, 0x7F, 0xC5, 0x71, 0xCF, 0x66, 0xED,
|
||||||
|
0x83, 0x31, 0x90, 0xA4, 0xD9, 0xD6, 0xC4, 0xC9, 0x42, 0x92, 0x36, 0x6D, 0xF3, 0x6A, 0x80, 0xB6,
|
||||||
|
0x69, 0x4F, 0xEE, 0x7E, 0xC2, 0x16, 0xA0, 0xC6, 0x96, 0x5D, 0x5B, 0x0E, 0x49, 0x59, 0xFE, 0xFB,
|
||||||
|
0x9D, 0x91, 0x6C, 0xB0, 0x09, 0x69, 0x77, 0xCF, 0xBD, 0xBB, 0xDD, 0x2D, 0x92, 0x46, 0x33, 0x9A,
|
||||||
|
0x19, 0xCD, 0x53, 0xDE, 0xBD, 0x8D, 0xA3, 0x8B, 0xC3, 0xFE, 0xF5, 0xE5, 0xB1, 0x36, 0x11, 0x61,
|
||||||
|
0xB0, 0xBF, 0x87, 0x7F, 0x6B, 0x01, 0xE1, 0x63, 0x97, 0xF2, 0xFD, 0x3D, 0xC1, 0x44, 0x40, 0xF7,
|
||||||
|
0x8F, 0x7B, 0x97, 0xDA, 0xB1, 0xCF, 0x44, 0x94, 0xEC, 0x35, 0xD4, 0xCA, 0x5E, 0x2A, 0x1E, 0x02,
|
||||||
|
0xAA, 0x85, 0xD4, 0x67, 0xC4, 0x4D, 0xBD, 0x84, 0xC2, 0x66, 0xDB, 0x0B, 0x67, 0xDF, 0xEB, 0x8C,
|
||||||
|
0xFB, 0xF4, 0xDE, 0xD9, 0x6E, 0x36, 0xDB, 0x71, 0x94, 0x32, 0xC1, 0x22, 0xEE, 0x90, 0x61, 0x1A,
|
||||||
|
0x05, 0x99, 0xA0, 0xED, 0x80, 0x8E, 0x84, 0xF3, 0x3C, 0xBE, 0x6F, 0x0F, 0xA3, 0xC4, 0xA7, 0x89,
|
||||||
|
0xD3, 0x8A, 0xEF, 0x35, 0x00, 0x31, 0x5F, 0x7B, 0xB6, 0xB3, 0xB3, 0xD3, 0x1E, 0x12, 0xEF, 0x76,
|
||||||
|
0x9C, 0x44, 0x19, 0xF7, 0xEB, 0x5E, 0x14, 0x44, 0x89, 0xF3, 0x6C, 0xF4, 0x1C, 0xFF, 0xB4, 0x7D,
|
||||||
|
0x96, 0xC6, 0x01, 0x79, 0x70, 0x78, 0xC4, 0x29, 0xE0, 0xDE, 0xD7, 0xD3, 0x09, 0xF1, 0xA3, 0xA9,
|
||||||
|
0xD3, 0xD4, 0x9A, 0x5A, 0xAB, 0x09, 0x44, 0x92, 0xF1, 0x90, 0x18, 0x4D, 0x0B, 0xFF, 0xD8, 0x3B,
|
||||||
|
0x66, 0x7B, 0x14, 0x71, 0x51, 0x4F, 0xD9, 0x77, 0xEA, 0xB4, 0xB6, 0xE0, 0x34, 0x39, 0x1D, 0x91,
|
||||||
|
0x90, 0x05, 0x0F, 0x4E, 0x4A, 0x78, 0x5A, 0x4F, 0x69, 0xC2, 0x46, 0x6A, 0x79, 0x4A, 0xD9, 0x78,
|
||||||
|
0x22, 0x9C, 0xDF, 0x9A, 0xCD, 0x39, 0xF0, 0xAF, 0x65, 0xC1, 0x2C, 0x60, 0x29, 0x20, 0xA3, 0x78,
|
||||||
|
0xEA, 0x3C, 0x11, 0xC5, 0x4E, 0x53, 0xB1, 0xDE, 0x6C, 0x87, 0x24, 0x19, 0x33, 0x0E, 0x83, 0x98,
|
||||||
|
0xF8, 0x3E, 0xE3, 0x63, 0x47, 0xA1, 0x05, 0x6C, 0xB6, 0x90, 0x36, 0xA1, 0x01, 0x11, 0xEC, 0x8E,
|
||||||
|
0xB6, 0x43, 0xC6, 0xEB, 0x53, 0xE6, 0x8B, 0x89, 0xB3, 0x0B, 0x3C, 0xB6, 0xBD, 0x2C, 0x49, 0x41,
|
||||||
|
0xA6, 0x38, 0x62, 0x5C, 0xD0, 0x44, 0xA2, 0xA5, 0x31, 0xE1, 0xB3, 0x5C, 0x54, 0x54, 0x40, 0x21,
|
||||||
|
0x27, 0xE3, 0x01, 0xE3, 0xB4, 0x3E, 0x0C, 0x22, 0xEF, 0x76, 0x71, 0xD2, 0x6E, 0x7C, 0x9F, 0x9F,
|
||||||
|
0xE5, 0x4C, 0xA2, 0x3B, 0x9A, 0xCC, 0x96, 0xEA, 0x92, 0xD8, 0x15, 0x60, 0x85, 0x34, 0xA5, 0x74,
|
||||||
|
0x6E, 0x8B, 0xBB, 0x0C, 0xA0, 0x96, 0xFC, 0x05, 0x29, 0x17, 0xFC, 0x2F, 0x45, 0x5A, 0x11, 0x5C,
|
||||||
|
0xA1, 0x30, 0x1E, 0x67, 0x62, 0xF6, 0xF8, 0x2A, 0xA3, 0x98, 0x78, 0x4C, 0x3C, 0xA0, 0xFC, 0xB0,
|
||||||
|
0x6D, 0x86, 0xBA, 0x04, 0xAC, 0x24, 0x24, 0x81, 0x86, 0x3A, 0xD7, 0x3E, 0xD0, 0xC4, 0x27, 0x9C,
|
||||||
|
0x58, 0x9D, 0x84, 0x91, 0xC0, 0xEA, 0x2D, 0xB5, 0x5E, 0x0F, 0xA3, 0xEF, 0xF5, 0x0C, 0xC6, 0x30,
|
||||||
|
0x0F, 0xA8, 0x27, 0x94, 0x92, 0xE1, 0x1E, 0x86, 0xB7, 0x4C, 0x3C, 0x06, 0x3C, 0x5A, 0x28, 0xA9,
|
||||||
|
0x4B, 0x2A, 0x69, 0xA2, 0x2E, 0xB0, 0x25, 0xD5, 0x83, 0x1C, 0x4B, 0xC9, 0x95, 0x50, 0xF5, 0x61,
|
||||||
|
0x24, 0x44, 0x14, 0x4A, 0x93, 0x5B, 0x08, 0xAC, 0x49, 0xAB, 0x79, 0xF1, 0xE8, 0x46, 0xD6, 0x6B,
|
||||||
|
0xBF, 0x44, 0xBE, 0x0D, 0x7A, 0x15, 0xCC, 0x23, 0x41, 0x9D, 0x04, 0x6C, 0xCC, 0x9D, 0x90, 0xF9,
|
||||||
|
0x7E, 0x40, 0x4B, 0x56, 0xEB, 0x64, 0x49, 0x60, 0xF8, 0x44, 0x10, 0x87, 0x85, 0x64, 0x4C, 0x1B,
|
||||||
|
0x31, 0x1F, 0x03, 0x34, 0xA5, 0xBB, 0x3B, 0x16, 0xFB, 0xD0, 0xBD, 0xB8, 0x9A, 0x36, 0xDF, 0xBD,
|
||||||
|
0x1E, 0x47, 0x1D, 0xF8, 0xE7, 0xBC, 0x37, 0x98, 0x1C, 0x0F, 0xC6, 0x30, 0xEA, 0xE2, 0xB4, 0xF3,
|
||||||
|
0xFE, 0xB0, 0xF3, 0x1E, 0x7E, 0x0E, 0x5B, 0xB5, 0xAF, 0xA3, 0x6F, 0xB8, 0xD0, 0x7D, 0xED, 0x77,
|
||||||
|
0xFB, 0x83, 0xE3, 0x4E, 0xE7, 0x5D, 0xE3, 0xCD, 0xF9, 0xF4, 0xE3, 0xBB, 0x5D, 0x04, 0x77, 0x83,
|
||||||
|
0xE6, 0xD5, 0x87, 0x49, 0x73, 0xB0, 0xF5, 0x32, 0xF4, 0x4F, 0xFC, 0x89, 0x17, 0x0E, 0x3A, 0xEF,
|
||||||
|
0x3F, 0x5E, 0xDD, 0x5D, 0x87, 0x83, 0x71, 0xEF, 0x63, 0x6B, 0xF2, 0x79, 0xEB, 0x43, 0xEF, 0xF3,
|
||||||
|
0xC7, 0x57, 0xB7, 0xF4, 0xD3, 0xC9, 0xDB, 0xCF, 0xFD, 0x29, 0x20, 0x1C, 0x45, 0xBD, 0xC1, 0x55,
|
||||||
|
0xF7, 0x43, 0x77, 0xFC, 0xB9, 0xEB, 0x1D, 0xDF, 0x0F, 0x83, 0xF3, 0xEE, 0xEB, 0xCE, 0xB0, 0xB3,
|
||||||
|
0xE5, 0x51, 0x3A, 0xEE, 0x5F, 0x75, 0xB3, 0x37, 0xEF, 0x2E, 0xC6, 0x8C, 0x4D, 0x7A, 0x9F, 0xCF,
|
||||||
|
0xFB, 0xDE, 0xE1, 0xF3, 0xD3, 0xC1, 0x49, 0x87, 0x4D, 0xCE, 0xDF, 0x5E, 0x35, 0x6F, 0x5F, 0xBF,
|
||||||
|
0x3B, 0x3C, 0xF2, 0xAE, 0xDF, 0x5E, 0xEF, 0x1E, 0x6D, 0x37, 0x7E, 0xFB, 0xED, 0xCC, 0xBF, 0x60,
|
||||||
|
0xBC, 0x7F, 0xF7, 0xBD, 0x33, 0x3E, 0x9C, 0xBE, 0x78, 0x48, 0xFB, 0x93, 0x37, 0x77, 0xBC, 0xF1,
|
||||||
|
0x21, 0xFA, 0xFA, 0xE6, 0xE1, 0x0C, 0xFE, 0xBB, 0xBC, 0xAC, 0x0D, 0x7B, 0xAD, 0x74, 0xF0, 0xFE,
|
||||||
|
0xCD, 0x87, 0xAD, 0xF4, 0xE5, 0xF3, 0xB8, 0x7B, 0x74, 0x74, 0x17, 0x0E, 0x2F, 0x1B, 0xA1, 0x7F,
|
||||||
|
0x3B, 0x12, 0x2F, 0xB6, 0x45, 0x7C, 0x3D, 0xCE, 0x3E, 0x7F, 0x7B, 0xFE, 0x76, 0xD2, 0xB8, 0xA0,
|
||||||
|
0xE4, 0x7A, 0x52, 0x7B, 0xF8, 0xFE, 0xF0, 0x62, 0xD2, 0x3F, 0xB9, 0x3B, 0x0F, 0xC8, 0xFD, 0xF9,
|
||||||
|
0xB9, 0xF7, 0x3D, 0xAC, 0x05, 0xE4, 0xE5, 0x45, 0x3F, 0x20, 0x49, 0x6B, 0xE0, 0x77, 0x1A, 0xB5,
|
||||||
|
0xC3, 0xAD, 0xCE, 0x8E, 0x48, 0xAE, 0x0E, 0xF9, 0xD1, 0xF6, 0xD7, 0xDE, 0x8B, 0x6E, 0xB7, 0x15,
|
||||||
|
0x0D, 0xBF, 0x6D, 0xBD, 0xBE, 0xDD, 0x7D, 0x3D, 0xD8, 0x7D, 0x3F, 0x7C, 0xDF, 0xE9, 0xED, 0x74,
|
||||||
|
0x07, 0xE4, 0xBA, 0xF7, 0xBE, 0x33, 0xDA, 0x19, 0x4E, 0x26, 0xEF, 0xDE, 0xF5, 0x5F, 0xF9, 0x9D,
|
||||||
|
0xEF, 0x49, 0xE7, 0x62, 0xDA, 0xB9, 0x3F, 0x1E, 0x74, 0x4E, 0x6A, 0xEF, 0x8E, 0xCF, 0x9A, 0xAD,
|
||||||
|
0xDE, 0xF5, 0xF6, 0xF8, 0x6C, 0x77, 0xDA, 0x4D, 0x8F, 0x3B, 0xEF, 0xBB, 0xCD, 0xF1, 0xDB, 0x5A,
|
||||||
|
0x48, 0x3E, 0x47, 0x87, 0xDB, 0xE3, 0x37, 0xBB, 0xEC, 0xF2, 0x9A, 0x74, 0xDE, 0x74, 0xDF, 0xA6,
|
||||||
|
0xEC, 0x2A, 0x3C, 0x19, 0x34, 0x3B, 0x9D, 0xD3, 0x0B, 0xFA, 0xEA, 0x70, 0x9B, 0xBC, 0xDB, 0xF2,
|
||||||
|
0x3E, 0x82, 0xFE, 0x07, 0x9F, 0xE8, 0x6F, 0xB5, 0xCE, 0xF4, 0xA2, 0x19, 0x78, 0x2F, 0x69, 0xFF,
|
||||||
|
0xE4, 0xBA, 0x2F, 0x6F, 0xE7, 0x38, 0x78, 0xD5, 0xBF, 0xED, 0x65, 0xEF, 0xC3, 0xC3, 0x43, 0x53,
|
||||||
|
0xE3, 0x51, 0x3D, 0xA1, 0x31, 0x25, 0xA2, 0x1C, 0xAE, 0x16, 0xFE, 0x01, 0xB6, 0xB5, 0xB4, 0xC2,
|
||||||
|
0xDC, 0x4F, 0x05, 0xBD, 0x17, 0x75, 0x9F, 0x7A, 0x51, 0x42, 0xE4, 0x1E, 0x40, 0xA0, 0x09, 0x9A,
|
||||||
|
0xD8, 0xFC, 0x77, 0x19, 0x3F, 0x35, 0x15, 0x3F, 0x35, 0xC2, 0x7D, 0xCD, 0x28, 0x1C, 0x01, 0x83,
|
||||||
|
0x87, 0x4F, 0xEF, 0x98, 0x47, 0xEB, 0x31, 0xBB, 0xA7, 0x41, 0x5D, 0x22, 0x3B, 0x4D, 0x73, 0x26,
|
||||||
|
0xFD, 0xAD, 0xD8, 0x46, 0x38, 0x98, 0x9A, 0xA4, 0x5A, 0x2C, 0xF8, 0x5F, 0x89, 0x47, 0x21, 0xB0,
|
||||||
|
0x81, 0xCB, 0x84, 0xF8, 0xAB, 0x7C, 0x27, 0x4A, 0xEA, 0xC3, 0x6C, 0x3C, 0x62, 0xF7, 0xE0, 0xD0,
|
||||||
|
0x23, 0xC6, 0x99, 0xA0, 0x5A, 0x2B, 0x9D, 0xFF, 0x5E, 0x90, 0xB9, 0xA5, 0x0F, 0xA3, 0x84, 0x84,
|
||||||
|
0x34, 0xD5, 0xFE, 0x22, 0x99, 0xD9, 0x28, 0x89, 0xC2, 0x65, 0x10, 0x99, 0x8B, 0xA8, 0x34, 0x99,
|
||||||
|
0xCF, 0x9F, 0x65, 0x71, 0x10, 0x11, 0x10, 0x73, 0x4D, 0xE4, 0x50, 0xF1, 0x34, 0x91, 0x6E, 0xB5,
|
||||||
|
0x88, 0xAB, 0xB9, 0x9B, 0x6D, 0xA1, 0x5B, 0x96, 0xDD, 0x7A, 0x6B, 0x67, 0xE9, 0xBA, 0x75, 0xB9,
|
||||||
|
0x17, 0xE3, 0xFD, 0x9A, 0x4C, 0x81, 0xF1, 0xA0, 0x14, 0xEE, 0x9E, 0x09, 0x50, 0xE9, 0x13, 0x87,
|
||||||
|
0xCB, 0x43, 0xF2, 0xC8, 0xB0, 0x60, 0x40, 0x05, 0xEA, 0x96, 0x8C, 0xD4, 0x85, 0x24, 0xB0, 0x6F,
|
||||||
|
0xFE, 0x8C, 0xCA, 0xBC, 0x67, 0x3D, 0x8B, 0x13, 0xB8, 0x0D, 0x3A, 0xFD, 0x11, 0xCD, 0x42, 0xA6,
|
||||||
|
0x2A, 0x6D, 0x45, 0x53, 0x65, 0xBC, 0x5C, 0x84, 0x65, 0xDA, 0x93, 0xBC, 0x16, 0xA4, 0x1F, 0x4B,
|
||||||
|
0x05, 0xE0, 0x05, 0x37, 0xCF, 0x91, 0x9B, 0x1F, 0x6A, 0x75, 0x7B, 0xF7, 0x97, 0x9C, 0x87, 0x9D,
|
||||||
|
0xE6, 0x2F, 0x73, 0x3B, 0xDF, 0x5B, 0xA4, 0xE4, 0x56, 0x13, 0xFE, 0x29, 0x32, 0xEF, 0x8B, 0x25,
|
||||||
|
0x0B, 0xC3, 0xE7, 0xF8, 0xA7, 0x60, 0x10, 0xE9, 0x94, 0x80, 0xDB, 0x3B, 0x2F, 0x5F, 0xF8, 0xC3,
|
||||||
|
0x02, 0x98, 0x0B, 0xF6, 0x24, 0x3C, 0x21, 0x3E, 0xCB, 0x52, 0xE7, 0x79, 0xF3, 0x97, 0x5C, 0x9F,
|
||||||
|
0x5B, 0x3B, 0x28, 0xFB, 0xE2, 0x2E, 0x71, 0xB2, 0xB4, 0xD8, 0x34, 0x66, 0x5C, 0xDB, 0x4A, 0x35,
|
||||||
|
0xBC, 0x6F, 0x92, 0x2C, 0x0C, 0xB3, 0x92, 0xED, 0xE7, 0xBF, 0x2F, 0x4D, 0x13, 0xF7, 0xCF, 0x9A,
|
||||||
|
0xBF, 0xCC, 0x44, 0x02, 0xD9, 0x64, 0x04, 0xB9, 0xC6, 0x49, 0x22, 0x41, 0x04, 0x35, 0x9A, 0xE6,
|
||||||
|
0x1C, 0x84, 0x5B, 0x03, 0xD8, 0xDE, 0x6D, 0xFA, 0x74, 0x6C, 0xCE, 0xE7, 0x7B, 0x0D, 0x99, 0xD7,
|
||||||
|
0xA0, 0x6C, 0xF1, 0x12, 0x16, 0x8B, 0xFD, 0x51, 0xC6, 0x3D, 0xE4, 0x41, 0x1B, 0x53, 0x83, 0x9A,
|
||||||
|
0xB3, 0x84, 0x8A, 0x2C, 0xE1, 0x9A, 0x1F, 0x79, 0x19, 0x1A, 0xBB, 0x3D, 0xA6, 0xE2, 0x58, 0xD9,
|
||||||
|
0x7D, 0xF7, 0xE1, 0x8D, 0x0F, 0x3B, 0xE6, 0x0B, 0x04, 0x6F, 0x2D, 0x02, 0x38, 0x30, 0x9C, 0x97,
|
||||||
|
0xE3, 0x54, 0xF6, 0x43, 0x82, 0x01, 0x22, 0xEF, 0xE8, 0x83, 0x41, 0x2D, 0xB1, 0x40, 0xA4, 0x36,
|
||||||
|
0xAE, 0x1B, 0xC5, 0x2E, 0x80, 0x71, 0x73, 0x76, 0x07, 0x4A, 0x20, 0x2E, 0xFD, 0x22, 0x6E, 0x2C,
|
||||||
|
0xE6, 0x72, 0xF8, 0x69, 0xE7, 0xBB, 0xC9, 0x1E, 0x3B, 0xA8, 0xB7, 0x1C, 0xB2, 0xCF, 0x0E, 0x5A,
|
||||||
|
0xE0, 0x5E, 0x65, 0x6E, 0xE4, 0xB9, 0xAF, 0x58, 0x40, 0x07, 0xB9, 0xC3, 0xE1, 0x31, 0x48, 0x6C,
|
||||||
|
0xB1, 0x85, 0x28, 0xE2, 0x5B, 0xCD, 0xE6, 0x86, 0x4B, 0x0F, 0x48, 0x00, 0x39, 0xCC, 0xD0, 0x8F,
|
||||||
|
0xAF, 0xAE, 0x2E, 0xAE, 0xBE, 0xE8, 0x35, 0x5A, 0xD3, 0x6F, 0x1C, 0x4D, 0xAF, 0x71, 0xD3, 0x11,
|
||||||
|
0x76, 0x42, 0x47, 0x09, 0x4D, 0x27, 0x97, 0x44, 0x4C, 0x8C, 0xD4, 0xBE, 0x23, 0x41, 0x56, 0x16,
|
||||||
|
0x84, 0xA1, 0xDC, 0xC8, 0xA2, 0x70, 0x39, 0x9D, 0x6A, 0xAF, 0x40, 0xCD, 0x47, 0x90, 0xEA, 0xDA,
|
||||||
|
0xC2, 0x26, 0x71, 0x4C, 0xB9, 0x6F, 0xE8, 0x31, 0x20, 0xEA, 0x16, 0x35, 0xAD, 0x84, 0x7E, 0xCB,
|
||||||
|
0x68, 0x2A, 0x52, 0x1B, 0x2C, 0xD7, 0xD0, 0x2F, 0x07, 0x7D, 0xDD, 0xD2, 0x1B, 0xE8, 0x47, 0x3A,
|
||||||
|
0xF0, 0x46, 0xCC, 0x39, 0x52, 0x89, 0x5C, 0xD0, 0xA4, 0x3E, 0xCC, 0xC0, 0xA0, 0xB8, 0x6E, 0xB6,
|
||||||
|
0x23, 0x9B, 0x71, 0x4E, 0x93, 0x93, 0xFE, 0xD9, 0xA9, 0xAB, 0x5F, 0x29, 0x46, 0xB4, 0x53, 0x28,
|
||||||
|
0x48, 0x74, 0x4B, 0x5E, 0x51, 0x7E, 0xC8, 0xE1, 0x84, 0x05, 0xBE, 0x11, 0x99, 0x6D, 0x24, 0xE1,
|
||||||
|
0x49, 0x12, 0xB2, 0x40, 0x01, 0x0A, 0x9E, 0x2D, 0x1E, 0x62, 0xEA, 0xEA, 0x23, 0x50, 0x86, 0x6E,
|
||||||
|
0x79, 0x76, 0x98, 0x05, 0x82, 0xC5, 0x01, 0x75, 0x37, 0x5A, 0x30, 0xE3, 0x60, 0x41, 0xAE, 0x8E,
|
||||||
|
0xB9, 0x19, 0x61, 0xCC, 0x77, 0x75, 0x15, 0xA1, 0xF2, 0xB8, 0xB6, 0xEE, 0x14, 0x4F, 0x9D, 0x92,
|
||||||
|
0x56, 0x4E, 0x49, 0xCB, 0xB8, 0x4A, 0xE0, 0x34, 0x3F, 0x18, 0xC3, 0x3C, 0xCE, 0xD4, 0x51, 0x05,
|
||||||
|
0xCC, 0xA7, 0x23, 0x02, 0x9C, 0x7C, 0x40, 0x6D, 0xBA, 0x7A, 0x63, 0xDD, 0x41, 0xA9, 0x3A, 0xC8,
|
||||||
|
0xAF, 0x6A, 0xC4, 0x2F, 0x6B, 0x44, 0xDD, 0xEE, 0x3A, 0x64, 0x5F, 0x21, 0x07, 0x55, 0xE4, 0xA0,
|
||||||
|
0x8C, 0x7C, 0x28, 0x8D, 0x64, 0x1D, 0x72, 0xA0, 0x90, 0x93, 0x8A, 0x88, 0x89, 0x14, 0x51, 0x85,
|
||||||
|
0xBD, 0x3A, 0x6A, 0x13, 0x05, 0xD2, 0xAD, 0xA4, 0x22, 0x66, 0x62, 0x83, 0x97, 0x92, 0x61, 0x40,
|
||||||
|
0x7D, 0x77, 0xA3, 0x09, 0x33, 0x2C, 0xB6, 0xDD, 0xAD, 0xE6, 0x9A, 0x33, 0x12, 0x75, 0x46, 0x56,
|
||||||
|
0x65, 0x30, 0x2B, 0x33, 0xA8, 0xF5, 0xC8, 0x1D, 0xD5, 0xD6, 0x31, 0x98, 0x99, 0x56, 0x60, 0x47,
|
||||||
|
0xDC, 0x0B, 0x98, 0x77, 0xEB, 0x2E, 0xBD, 0xC5, 0x9C, 0xB1, 0x85, 0x85, 0x5A, 0x5C, 0x06, 0xBA,
|
||||||
|
0x01, 0x94, 0x5E, 0x8B, 0xA5, 0x7C, 0x80, 0xFA, 0x9E, 0x5B, 0xD9, 0x5A, 0x02, 0xDC, 0xA6, 0xF7,
|
||||||
|
0xD4, 0x3B, 0x8C, 0xC2, 0x90, 0xA0, 0xED, 0xA6, 0xC0, 0x41, 0x3E, 0xD1, 0xCD, 0xB9, 0x15, 0xAD,
|
||||||
|
0xC5, 0x79, 0xC2, 0x45, 0x2C, 0x7F, 0x3D, 0x8B, 0x23, 0x03, 0x5C, 0xCE, 0xF5, 0x6C, 0xD4, 0x61,
|
||||||
|
0x6A, 0x83, 0x1E, 0xC7, 0x62, 0xF2, 0x13, 0x17, 0x2A, 0x0C, 0x54, 0xA2, 0x7C, 0x69, 0xDE, 0x58,
|
||||||
|
0x0B, 0x91, 0x56, 0x7C, 0xEA, 0xA2, 0xB7, 0xE2, 0x54, 0xA8, 0xBC, 0x8A, 0x5D, 0x9A, 0x4B, 0x1D,
|
||||||
|
0x94, 0x61, 0xB9, 0xBD, 0x2F, 0xA0, 0xFA, 0x7C, 0x0E, 0xE7, 0x01, 0xFF, 0x13, 0x68, 0xF9, 0xE8,
|
||||||
|
0x5F, 0x17, 0x60, 0xC9, 0xA3, 0x34, 0x78, 0x8B, 0xBB, 0x0D, 0xE3, 0xC0, 0xF9, 0x8F, 0x6D, 0x7C,
|
||||||
|
0xF9, 0x1F, 0xFB, 0xA6, 0x66, 0x9A, 0x07, 0xFF, 0x6A, 0x48, 0x0D, 0x1B, 0xC2, 0xFC, 0xD2, 0xBA,
|
||||||
|
0xB1, 0x08, 0x80, 0xED, 0x7F, 0x9B, 0xFF, 0xB1, 0x25, 0xB8, 0x02, 0x6B, 0xDF, 0x45, 0x90, 0x49,
|
||||||
|
0xF0, 0x24, 0x34, 0xB0, 0x68, 0xA4, 0x91, 0xCD, 0x4D, 0x43, 0xB8, 0xA4, 0x72, 0x8D, 0x35, 0x51,
|
||||||
|
0xD3, 0x6D, 0x88, 0x53, 0x50, 0x5B, 0xAC, 0x04, 0xBF, 0x3E, 0x24, 0x7A, 0x15, 0x5B, 0x17, 0x00,
|
||||||
|
0xC9, 0x3D, 0xCA, 0x0C, 0x3D, 0x22, 0x97, 0x52, 0xCB, 0x0C, 0x02, 0x42, 0xA7, 0x89, 0xE7, 0x2A,
|
||||||
|
0xAD, 0x1D, 0x14, 0x30, 0x17, 0xA2, 0xE0, 0xBC, 0x1C, 0x2D, 0x15, 0xEA, 0xAA, 0xFD, 0x17, 0x0A,
|
||||||
|
0xA3, 0xD6, 0x12, 0x8A, 0x04, 0x31, 0xAD, 0xD8, 0x79, 0xC6, 0x72, 0x75, 0x4C, 0x59, 0xBA, 0x35,
|
||||||
|
0x59, 0x5D, 0x96, 0xAD, 0x04, 0xAE, 0x2F, 0x8D, 0xFE, 0xD7, 0x3D, 0x16, 0x8E, 0xB5, 0x12, 0x3F,
|
||||||
|
0xF8, 0x97, 0xFB, 0x2B, 0x46, 0xE4, 0xCD, 0x3F, 0xBC, 0x21, 0x70, 0x05, 0xA6, 0x41, 0x6D, 0x1E,
|
||||||
|
0x4D, 0x0D, 0xB3, 0xF6, 0xAB, 0xAE, 0x49, 0x8A, 0xAE, 0x1E, 0x92, 0xFB, 0xBC, 0xA7, 0xC4, 0x8C,
|
||||||
|
0xD7, 0xD6, 0x70, 0x5E, 0xB4, 0x28, 0xF9, 0x82, 0xEC, 0xE6, 0x48, 0x26, 0xA2, 0xB6, 0x56, 0x64,
|
||||||
|
0x52, 0xD5, 0xCA, 0xE8, 0x5A, 0x63, 0xFF, 0xD7, 0x4A, 0x40, 0xB7, 0x98, 0xBA, 0x4E, 0x15, 0x8C,
|
||||||
|
0xB3, 0x00, 0x1C, 0x93, 0x3E, 0x1D, 0x69, 0x03, 0x26, 0x03, 0x75, 0x35, 0x46, 0x5A, 0x81, 0xC1,
|
||||||
|
0xCC, 0x03, 0xC3, 0x2B, 0xFB, 0xF3, 0x1E, 0x16, 0xBF, 0xFB, 0x97, 0xAA, 0xAA, 0x81, 0xD4, 0x8B,
|
||||||
|
0x33, 0x5D, 0x59, 0x59, 0xD5, 0x4B, 0xE0, 0xD2, 0x08, 0xA0, 0x5B, 0x8B, 0x3C, 0x3A, 0x8C, 0xFC,
|
||||||
|
0x87, 0x52, 0xF6, 0x4D, 0xBB, 0x0F, 0x87, 0x01, 0x49, 0xD3, 0x73, 0xB8, 0x01, 0x43, 0xF7, 0x42,
|
||||||
|
0x50, 0xB8, 0xB2, 0xC2, 0xFD, 0xE6, 0xE6, 0x66, 0x15, 0x29, 0xA1, 0x21, 0x14, 0xDB, 0x8A, 0x2B,
|
||||||
|
0xF0, 0x49, 0xD3, 0xF1, 0x81, 0x30, 0x18, 0xD2, 0x1A, 0xC6, 0xF0, 0x25, 0xE3, 0x47, 0x5C, 0x71,
|
||||||
|
0xF4, 0xF4, 0x22, 0xA6, 0xFC, 0x33, 0xDC, 0x95, 0x32, 0xCB, 0x1A, 0xAD, 0xA6, 0x68, 0xFA, 0x8F,
|
||||||
|
0xD8, 0x3E, 0xCA, 0x0D, 0x76, 0xC1, 0x7A, 0xBA, 0x56, 0xA1, 0xFC, 0x9F, 0x61, 0xB9, 0x94, 0x28,
|
||||||
|
0xD6, 0x70, 0x9C, 0x40, 0x80, 0x5A, 0xC3, 0x31, 0xC4, 0x1A, 0x41, 0x17, 0xFC, 0x26, 0x6B, 0xF9,
|
||||||
|
0xCD, 0xFE, 0x19, 0x7E, 0x97, 0x76, 0x1E, 0x15, 0x25, 0x91, 0xAA, 0xAF, 0x50, 0x02, 0x9F, 0xDD,
|
||||||
|
0xE9, 0xA6, 0x15, 0xB9, 0x55, 0x0A, 0x50, 0x1B, 0x46, 0x41, 0xD0, 0x8F, 0xE2, 0x83, 0x27, 0xD6,
|
||||||
|
0x9D, 0xC5, 0x7A, 0x31, 0xC8, 0xD9, 0x5C, 0x6E, 0xB1, 0xBC, 0xB5, 0x44, 0x4F, 0xA1, 0xEC, 0x5F,
|
||||||
|
0x4B, 0x15, 0x01, 0x3F, 0x23, 0x8B, 0x7B, 0xAC, 0xD4, 0xA5, 0x36, 0x28, 0x0F, 0x56, 0x3F, 0xD5,
|
||||||
|
0x3C, 0xCB, 0x5F, 0xCC, 0xAE, 0x6B, 0x51, 0x9B, 0xC0, 0x38, 0x57, 0x92, 0x8B, 0x4A, 0xB2, 0xC8,
|
||||||
|
0x13, 0x01, 0xA8, 0x58, 0xC7, 0x2E, 0xC4, 0x4D, 0x6B, 0x7A, 0x7C, 0xBF, 0x5C, 0x83, 0xC2, 0xDF,
|
||||||
|
0xF5, 0xD5, 0x12, 0x33, 0x08, 0xC4, 0xD3, 0x95, 0x4B, 0x29, 0x5F, 0x37, 0x29, 0x8A, 0x0E, 0x62,
|
||||||
|
0x47, 0xA3, 0x51, 0x4A, 0xC5, 0x47, 0x0C, 0x49, 0x56, 0xB2, 0x98, 0x9F, 0xC8, 0x90, 0x04, 0x8C,
|
||||||
|
0x45, 0x3C, 0x8C, 0xB2, 0x94, 0x46, 0x99, 0xA8, 0xA4, 0x16, 0x63, 0x21, 0xCC, 0x5E, 0xFA, 0xE7,
|
||||||
|
0x9F, 0x8B, 0xC9, 0x7E, 0x5A, 0x0B, 0x96, 0xD3, 0xEB, 0x3D, 0xBF, 0x34, 0xD9, 0xF7, 0x6B, 0x89,
|
||||||
|
0xB9, 0x7A, 0xE9, 0xFF, 0x67, 0x4B, 0x21, 0x65, 0x4B, 0xF1, 0xB0, 0x54, 0x2E, 0x62, 0x62, 0x29,
|
||||||
|
0xE6, 0xC9, 0x82, 0x91, 0x97, 0x7C, 0x16, 0x0D, 0x1A, 0x2B, 0x25, 0x55, 0x9E, 0x97, 0x7D, 0x95,
|
||||||
|
0x43, 0x40, 0x59, 0x71, 0xE5, 0x35, 0x11, 0x06, 0x34, 0xE0, 0x63, 0x64, 0xF2, 0x41, 0xEB, 0xA7,
|
||||||
|
0xD1, 0x94, 0x26, 0x87, 0x24, 0xA5, 0x06, 0x24, 0xCD, 0x65, 0xDC, 0x41, 0xA8, 0xE9, 0x04, 0xEB,
|
||||||
|
0x76, 0x6D, 0x6E, 0x12, 0x05, 0xCE, 0x33, 0x77, 0xC4, 0xB1, 0x26, 0x03, 0xF9, 0xB2, 0xCA, 0x09,
|
||||||
|
0xD4, 0xC6, 0xBE, 0x12, 0xA4, 0x3E, 0x52, 0x25, 0xA8, 0x61, 0x5A, 0xD0, 0x76, 0xC0, 0x35, 0x5F,
|
||||||
|
0x26, 0x51, 0x4C, 0xC6, 0xB2, 0x07, 0x83, 0x35, 0x74, 0x0F, 0xA4, 0x66, 0x6D, 0x34, 0x91, 0x60,
|
||||||
|
0xA9, 0x73, 0x29, 0xFC, 0x66, 0xD9, 0xC2, 0x70, 0x4B, 0x57, 0xC9, 0xB0, 0xBD, 0xF4, 0xA5, 0x35,
|
||||||
|
0x59, 0x83, 0xE0, 0x0B, 0x6C, 0x62, 0xE0, 0x1E, 0x68, 0x64, 0xF2, 0x7B, 0x00, 0x77, 0x6B, 0xB6,
|
||||||
|
0xA3, 0x3D, 0xD6, 0x8E, 0x6A, 0x35, 0x53, 0x55, 0xE9, 0xAE, 0x0B, 0x6D, 0x4E, 0x74, 0x23, 0x0B,
|
||||||
|
0x4B, 0x10, 0xAA, 0x9A, 0x59, 0x0C, 0x38, 0x1B, 0x81, 0xAA, 0xBA, 0xC0, 0x11, 0xD6, 0x98, 0x66,
|
||||||
|
0xA9, 0x23, 0xF1, 0x97, 0x1D, 0xC9, 0x13, 0xB5, 0x07, 0x95, 0xF5, 0x05, 0xD4, 0x31, 0xAB, 0x25,
|
||||||
|
0x86, 0x30, 0xD3, 0x29, 0x13, 0xDE, 0x04, 0x03, 0x90, 0x07, 0x5A, 0xD5, 0x05, 0x14, 0xB5, 0x8E,
|
||||||
|
0x1C, 0x4D, 0x44, 0xB8, 0x1C, 0x05, 0xF9, 0xF0, 0x6B, 0x9A, 0x0F, 0xBC, 0xB4, 0x18, 0xDD, 0x97,
|
||||||
|
0x80, 0x50, 0xD2, 0xE6, 0xE0, 0x88, 0x8F, 0xF2, 0x21, 0xF4, 0xB2, 0x05, 0x9D, 0x02, 0x58, 0xFC,
|
||||||
|
0xC6, 0x71, 0x3E, 0x8A, 0x27, 0xC5, 0x68, 0x42, 0xEF, 0x17, 0x78, 0x51, 0x01, 0xF5, 0xA9, 0xEE,
|
||||||
|
0x28, 0x1B, 0xDB, 0x68, 0xCE, 0xF3, 0x41, 0x6B, 0x29, 0x7F, 0xF0, 0xFF, 0x28, 0x7F, 0xCC, 0xC7,
|
||||||
|
0x85, 0x34, 0x71, 0x31, 0x1A, 0xB3, 0x42, 0x96, 0x61, 0x18, 0xFF, 0x90, 0x93, 0xA4, 0xD4, 0x13,
|
||||||
|
0x97, 0x7A, 0x5A, 0xF1, 0xB3, 0xB6, 0x53, 0x98, 0x8E, 0x31, 0xAA, 0xF8, 0xE3, 0xC8, 0xF6, 0xF0,
|
||||||
|
0xF7, 0x3C, 0xF2, 0x65, 0x6D, 0x69, 0x5A, 0xA1, 0x31, 0x82, 0x3A, 0x57, 0x37, 0xCB, 0x7E, 0x9A,
|
||||||
|
0xFD, 0xB7, 0xAD, 0xE8, 0xD1, 0xF1, 0xE9, 0x71, 0xFF, 0xB8, 0x5C, 0x38, 0x23, 0xE7, 0x25, 0x93,
|
||||||
|
0x8A, 0x2B, 0x5D, 0xFA, 0xB2, 0x22, 0x80, 0x02, 0x1B, 0x45, 0x01, 0x7B, 0xDD, 0xDC, 0x54, 0x7E,
|
||||||
|
0xF1, 0xB6, 0x77, 0x71, 0x6E, 0xC7, 0x24, 0x01, 0x8F, 0x24, 0x15, 0xE6, 0xC2, 0x82, 0x44, 0xF9,
|
||||||
|
0xE0, 0xD7, 0xC7, 0xA5, 0x72, 0x5D, 0x7E, 0x61, 0x70, 0xC4, 0xDC, 0x52, 0xA7, 0xA9, 0x7E, 0x78,
|
||||||
|
0xE2, 0x62, 0x5D, 0x99, 0xBF, 0x04, 0x41, 0x72, 0x1A, 0x2D, 0x13, 0x55, 0x11, 0x67, 0x46, 0xE5,
|
||||||
|
0x30, 0x2F, 0xEE, 0xB2, 0x75, 0x0D, 0xD3, 0xC8, 0xB4, 0xC4, 0x84, 0xA5, 0xE5, 0x46, 0xA5, 0x12,
|
||||||
|
0x14, 0xFE, 0xA2, 0xB6, 0xE7, 0x8B, 0x91, 0x24, 0xB7, 0x5A, 0x73, 0xAB, 0x6F, 0x41, 0x2A, 0x3E,
|
||||||
|
0x58, 0x04, 0x23, 0x66, 0x39, 0xDB, 0x16, 0x77, 0xA3, 0x43, 0xEE, 0x61, 0x5C, 0x7F, 0xBA, 0x35,
|
||||||
|
0x78, 0xD2, 0x3C, 0x79, 0x61, 0x9E, 0xFC, 0xB1, 0x7B, 0x2E, 0x1C, 0x45, 0xF9, 0xDA, 0xE2, 0x98,
|
||||||
|
0xF6, 0x10, 0x58, 0xBB, 0x6D, 0x2F, 0x7D, 0x18, 0x20, 0xD2, 0x83, 0xCB, 0x00, 0xF4, 0x63, 0x58,
|
||||||
|
0xFF, 0x4A, 0xEE, 0x88, 0x7A, 0x09, 0xAA, 0xA2, 0xAD, 0x73, 0x54, 0xD8, 0xEE, 0xFD, 0x81, 0xA3,
|
||||||
|
0xF2, 0xCE, 0x65, 0x18, 0x48, 0x97, 0xC3, 0x92, 0x37, 0x8B, 0x75, 0xC1, 0x61, 0x19, 0x31, 0x64,
|
||||||
|
0x6C, 0x00, 0xE3, 0xCD, 0x5D, 0x49, 0x13, 0xD5, 0x1C, 0xB4, 0xF0, 0x1B, 0x08, 0x8A, 0x4F, 0x39,
|
||||||
|
0xCE, 0x9A, 0x38, 0xAD, 0x62, 0x72, 0xC5, 0x23, 0xC8, 0x4A, 0x67, 0x89, 0xC0, 0x6E, 0x10, 0x0D,
|
||||||
|
0x0D, 0x7C, 0x64, 0x9A, 0xA1, 0xB6, 0x1D, 0x3E, 0x37, 0xD7, 0xBC, 0xD9, 0x54, 0xFA, 0x4B, 0x62,
|
||||||
|
0x79, 0xD5, 0xB0, 0x8B, 0x1C, 0x56, 0xCC, 0x75, 0x7D, 0x1F, 0xF4, 0xA3, 0x4E, 0x29, 0xAF, 0x48,
|
||||||
|
0xA4, 0x53, 0xD1, 0x83, 0xC4, 0x86, 0xA2, 0x41, 0xBE, 0x91, 0x40, 0x44, 0x72, 0x4A, 0x33, 0x5D,
|
||||||
|
0xC7, 0xCA, 0xD2, 0x0B, 0x28, 0x49, 0x7A, 0xB2, 0x73, 0x95, 0x49, 0x6B, 0x25, 0x06, 0xFE, 0xC8,
|
||||||
|
0xD7, 0xF0, 0xC7, 0xA1, 0xD0, 0xA3, 0x83, 0x9B, 0x49, 0x2B, 0x83, 0xA4, 0x23, 0x64, 0x83, 0xA9,
|
||||||
|
0x37, 0xE4, 0xBB, 0xA8, 0x2D, 0x2F, 0xCB, 0xB4, 0x16, 0x50, 0x70, 0x71, 0x83, 0xBB, 0x11, 0x30,
|
||||||
|
0x52, 0x5A, 0xC4, 0x9E, 0x94, 0xA8, 0xC7, 0x8F, 0x10, 0x1F, 0x53, 0x4A, 0x20, 0x06, 0x20, 0xA6,
|
||||||
|
0x40, 0xD0, 0xA7, 0x42, 0x8A, 0x54, 0xE6, 0x92, 0x53, 0x2A, 0x20, 0xCA, 0x48, 0xCD, 0xE2, 0xC1,
|
||||||
|
0x85, 0x78, 0xD4, 0x46, 0xD6, 0x80, 0xFD, 0xDC, 0xBD, 0x73, 0x33, 0xDE, 0x90, 0x68, 0x09, 0x56,
|
||||||
|
0x36, 0x3D, 0x9A, 0xA6, 0x52, 0x5C, 0x54, 0xC7, 0x19, 0xF8, 0xA8, 0xA1, 0x03, 0x5A, 0x23, 0x84,
|
||||||
|
0x11, 0x1E, 0x84, 0x8A, 0x01, 0x40, 0x7F, 0x42, 0xC3, 0x1C, 0x22, 0x70, 0x08, 0x20, 0x82, 0xA0,
|
||||||
|
0x7F, 0x49, 0x0D, 0xF7, 0x64, 0x05, 0xC9, 0xF8, 0xD8, 0x6D, 0x35, 0xF0, 0x9D, 0x66, 0x95, 0xEC,
|
||||||
|
0x20, 0xA5, 0xBD, 0x68, 0x24, 0xFA, 0x64, 0x98, 0x1A, 0x50, 0x00, 0xAC, 0xD9, 0x01, 0xA0, 0x1E,
|
||||||
|
0x24, 0x5E, 0x63, 0x2B, 0x3F, 0xEF, 0x04, 0x2A, 0xBB, 0x00, 0xAB, 0xBB, 0x8E, 0x87, 0x5F, 0x39,
|
||||||
|
0x4F, 0x19, 0xA7, 0x39, 0x26, 0x00, 0x7B, 0x93, 0x68, 0x7A, 0x99, 0x30, 0x2E, 0xCE, 0x64, 0x1B,
|
||||||
|
0x6A, 0x6C, 0xB4, 0xE4, 0xF5, 0xA9, 0x87, 0x15, 0x79, 0x3F, 0xC5, 0x8B, 0xCB, 0x0C, 0xF3, 0xBA,
|
||||||
|
0x53, 0x79, 0x77, 0xB1, 0x86, 0x70, 0x21, 0x50, 0x66, 0x38, 0xB3, 0x29, 0x74, 0xB0, 0xFA, 0xA1,
|
||||||
|
0x48, 0x82, 0x7A, 0x4F, 0xB7, 0x42, 0xE2, 0xC1, 0x44, 0xED, 0x81, 0xF9, 0xDC, 0xC2, 0xD8, 0xE1,
|
||||||
|
0x94, 0x83, 0x5A, 0x0A, 0xB5, 0x02, 0x45, 0xC6, 0x95, 0xCD, 0x98, 0x35, 0x1D, 0x6A, 0x58, 0x88,
|
||||||
|
0x61, 0xE0, 0xAF, 0xFE, 0x05, 0x0F, 0x1E, 0x1C, 0xC8, 0x55, 0x3F, 0xE1, 0x23, 0xE3, 0x7E, 0xF4,
|
||||||
|
0x23, 0x3E, 0x3E, 0xAF, 0xF0, 0xF1, 0x79, 0x1D, 0x1F, 0xB4, 0xAA, 0x3C, 0x98, 0x0C, 0x80, 0xEC,
|
||||||
|
0x19, 0xE1, 0x64, 0x4C, 0x13, 0x58, 0xC0, 0x43, 0x50, 0x25, 0x7F, 0x8B, 0xB3, 0x84, 0xFE, 0x98,
|
||||||
|
0xB3, 0xDE, 0x84, 0x8D, 0xC4, 0x23, 0xFE, 0x8A, 0xD5, 0xFF, 0x82, 0x4B, 0x3C, 0x70, 0x3D, 0x97,
|
||||||
|
0x79, 0x6D, 0x5A, 0x49, 0x28, 0x3F, 0x7E, 0x2B, 0x91, 0x7E, 0xE4, 0x42, 0x78, 0xA9, 0x38, 0xC8,
|
||||||
|
0xDF, 0xB7, 0xF4, 0x00, 0xBC, 0x11, 0xF8, 0x29, 0x35, 0x75, 0xBC, 0x0B, 0xA5, 0xFC, 0x29, 0x30,
|
||||||
|
0x64, 0xA8, 0xC0, 0x47, 0xDD, 0xD9, 0xDC, 0x12, 0xAE, 0x01, 0x8A, 0xF1, 0xA3, 0x29, 0xB0, 0xEA,
|
||||||
|
0xC9, 0x02, 0xD7, 0x9E, 0x40, 0x26, 0x04, 0x91, 0xE0, 0x48, 0xC8, 0xA7, 0x8D, 0x2F, 0x07, 0x9B,
|
||||||
|
0x37, 0x35, 0xC8, 0x43, 0x2E, 0xFC, 0x98, 0x2E, 0x0C, 0x36, 0x6F, 0xFE, 0x6D, 0x36, 0xC6, 0xCC,
|
||||||
|
0x5A, 0x76, 0xA4, 0x96, 0x4C, 0xF6, 0xF4, 0x0B, 0xBF, 0x71, 0x09, 0x48, 0x5D, 0x49, 0x78, 0x45,
|
||||||
|
0x34, 0x03, 0x6B, 0x43, 0x61, 0xE1, 0x07, 0xFF, 0x47, 0x09, 0xF8, 0x91, 0x9E, 0x07, 0xCE, 0xBD,
|
||||||
|
0xE6, 0x3D, 0x5E, 0x2F, 0x3E, 0x85, 0xE9, 0x56, 0xE9, 0xC1, 0x4A, 0xC7, 0xEF, 0x53, 0x3A, 0x76,
|
||||||
|
0x59, 0xA2, 0x14, 0x4A, 0x14, 0x59, 0x88, 0x1A, 0x6A, 0x50, 0x0E, 0x51, 0x98, 0x89, 0x17, 0xCD,
|
||||||
|
0x81, 0x02, 0x9B, 0x73, 0x34, 0x5B, 0x3A, 0x02, 0x0F, 0xF4, 0xF5, 0x45, 0xEE, 0xFC, 0x74, 0x76,
|
||||||
|
0x7A, 0x22, 0x44, 0x7C, 0xA5, 0x62, 0x22, 0xD0, 0xAA, 0x2E, 0x2C, 0x2F, 0xCF, 0x9C, 0x89, 0xE4,
|
||||||
|
0xA1, 0x28, 0x75, 0x30, 0x31, 0x28, 0x87, 0xFE, 0x74, 0x31, 0xFC, 0x0A, 0x71, 0xD6, 0xD0, 0xCF,
|
||||||
|
0x52, 0x48, 0x58, 0x5B, 0x36, 0xA2, 0xF7, 0xFB, 0x97, 0xF6, 0xAE, 0xDD, 0x84, 0xBA, 0x00, 0xB4,
|
||||||
|
0x0A, 0x69, 0x19, 0xEE, 0x7D, 0xFE, 0xB7, 0x90, 0xB7, 0xFF, 0x1E, 0x32, 0x83, 0xA8, 0x95, 0x42,
|
||||||
|
0x58, 0x2A, 0xF0, 0xAB, 0xB8, 0x93, 0x24, 0x9A, 0x4A, 0xB4, 0xE3, 0x24, 0xC1, 0x4B, 0xE9, 0x43,
|
||||||
|
0x85, 0xA2, 0x0D, 0x61, 0x31, 0xA5, 0x89, 0xE6, 0x47, 0x34, 0xD5, 0x78, 0x24, 0xB4, 0x34, 0x8B,
|
||||||
|
0x63, 0x68, 0x5C, 0x56, 0xF4, 0x61, 0xEB, 0xC5, 0xEB, 0xCB, 0xFB, 0x8C, 0x66, 0xD4, 0xCF, 0x97,
|
||||||
|
0x69, 0x52, 0xD1, 0x0B, 0x56, 0x50, 0xDF, 0x10, 0xEE, 0x7E, 0xB9, 0xC9, 0xEB, 0xA9, 0x8C, 0x73,
|
||||||
|
0x8C, 0xA2, 0x1B, 0x2D, 0x35, 0x07, 0xE9, 0x26, 0x40, 0xD5, 0xE5, 0x59, 0x10, 0xCC, 0xDB, 0x2B,
|
||||||
|
0xB4, 0xA0, 0xF1, 0x8A, 0x44, 0x24, 0x9F, 0xCB, 0x67, 0x7F, 0xE4, 0xC9, 0xA9, 0xE2, 0x82, 0x50,
|
||||||
|
0xF2, 0x54, 0xA9, 0x36, 0xAD, 0x0D, 0x63, 0x83, 0x6A, 0x8C, 0xA7, 0x82, 0x70, 0x0F, 0xAF, 0x51,
|
||||||
|
0xE9, 0xC2, 0x2C, 0x6A, 0x29, 0xDC, 0xDE, 0x46, 0x5F, 0xCB, 0x6D, 0xE9, 0x89, 0x7C, 0x2A, 0x25,
|
||||||
|
0xE3, 0xAE, 0xAE, 0x63, 0x55, 0x45, 0xB1, 0x3E, 0x25, 0x61, 0x5A, 0x26, 0x5B, 0x54, 0x06, 0x26,
|
||||||
|
0x77, 0x0B, 0x70, 0x9B, 0x06, 0x29, 0x1C, 0xBD, 0x7E, 0x7F, 0xCE, 0x46, 0xD1, 0xCE, 0x11, 0x80,
|
||||||
|
0x69, 0xC5, 0x3E, 0x93, 0xD7, 0xE0, 0x24, 0xCC, 0x73, 0x07, 0x32, 0xE9, 0x4A, 0x03, 0x0E, 0xA9,
|
||||||
|
0x98, 0x44, 0xFE, 0x81, 0x7E, 0xA0, 0x3B, 0x3A, 0xFC, 0xBB, 0x09, 0x35, 0x47, 0xCD, 0xA5, 0xD0,
|
||||||
|
0xA4, 0xFA, 0x74, 0x70, 0xF5, 0x06, 0xC2, 0x53, 0x0C, 0xA5, 0x01, 0x17, 0x50, 0x34, 0xD7, 0x74,
|
||||||
|
0x7C, 0x7A, 0x7D, 0x0C, 0x29, 0xC8, 0x7F, 0x21, 0x37, 0x66, 0xBB, 0xAA, 0x6C, 0xB8, 0xF3, 0xEA,
|
||||||
|
0x75, 0x56, 0x2E, 0x03, 0x7A, 0x61, 0x8C, 0x58, 0x0F, 0x29, 0x7E, 0xFB, 0x7B, 0xF4, 0x9E, 0x8D,
|
||||||
|
0x15, 0xD2, 0x6A, 0x5D, 0x6F, 0xCE, 0x76, 0x90, 0x67, 0x89, 0xD5, 0x43, 0x2C, 0x70, 0x97, 0x1F,
|
||||||
|
0x29, 0x59, 0x95, 0x35, 0xDC, 0xF6, 0x48, 0x10, 0xE0, 0xC7, 0x5A, 0x03, 0x1B, 0x6A, 0x22, 0xB2,
|
||||||
|
0xD4, 0x42, 0x22, 0x29, 0x08, 0x90, 0xD2, 0x3E, 0x84, 0x39, 0xD3, 0x92, 0x65, 0x86, 0xB2, 0xA1,
|
||||||
|
0xBC, 0xFF, 0xC5, 0x9A, 0xA3, 0x64, 0x46, 0xE8, 0xCE, 0xF9, 0x6C, 0x73, 0x53, 0xD8, 0x85, 0x99,
|
||||||
|
0x18, 0x05, 0x52, 0x8A, 0x01, 0x1C, 0x9A, 0x7D, 0x68, 0x2D, 0x8C, 0xB2, 0x90, 0x58, 0xAB, 0x3D,
|
||||||
|
0xD2, 0xB6, 0x51, 0x55, 0x03, 0x54, 0x7C, 0x46, 0x01, 0x03, 0xCE, 0xB2, 0x24, 0x80, 0xA8, 0x8B,
|
||||||
|
0x39, 0xBA, 0xB2, 0x2D, 0xC5, 0xBA, 0xD0, 0x84, 0x0E, 0xEC, 0x67, 0xC8, 0x12, 0x95, 0x97, 0xAD,
|
||||||
|
0xA2, 0x27, 0x12, 0xC5, 0x77, 0x95, 0x9E, 0xC8, 0x6F, 0xE5, 0x84, 0xAA, 0xC8, 0x77, 0x88, 0x2F,
|
||||||
|
0x13, 0x5C, 0xD4, 0xD1, 0x13, 0xA0, 0x24, 0x83, 0x52, 0x34, 0x60, 0x2A, 0x2C, 0x37, 0xEE, 0xEB,
|
||||||
|
0xD3, 0xE9, 0xB4, 0x8E, 0xDF, 0x6A, 0xEB, 0x70, 0x82, 0xB2, 0x02, 0x5F, 0x5F, 0xC7, 0x21, 0x47,
|
||||||
|
0x15, 0x58, 0xF8, 0x6E, 0xE1, 0xAC, 0xBA, 0xE8, 0x42, 0x7F, 0x2B, 0xDE, 0xD4, 0xAA, 0xD2, 0x59,
|
||||||
|
0xE1, 0x73, 0x79, 0xDB, 0x7B, 0x3B, 0x2B, 0x20, 0x32, 0xC4, 0xAF, 0xB2, 0x90, 0x69, 0x20, 0x0D,
|
||||||
|
0x3B, 0xE5, 0x46, 0x56, 0x25, 0x85, 0x65, 0x5C, 0xB0, 0xE3, 0x2C, 0x9D, 0x18, 0x33, 0x60, 0xDD,
|
||||||
|
0x11, 0x96, 0xD2, 0x95, 0x43, 0x2D, 0x65, 0xB7, 0x0E, 0xB7, 0x0A, 0xFB, 0x70, 0x30, 0x83, 0x94,
|
||||||
|
0x79, 0xFB, 0xF3, 0x4F, 0x39, 0x5B, 0xDE, 0xF6, 0x92, 0x62, 0x71, 0xE1, 0xF3, 0xFC, 0xA9, 0x35,
|
||||||
|
0xAF, 0x69, 0xA5, 0xD1, 0xAF, 0xC4, 0x97, 0xBD, 0x46, 0xFE, 0x19, 0x3B, 0xFF, 0x9C, 0xAD, 0x81,
|
||||||
|
0xB1, 0x43, 0x23, 0x2A, 0xDC, 0x4C, 0x8C, 0xEA, 0x2F, 0x34, 0xE6, 0x63, 0x79, 0x29, 0xBF, 0x2D,
|
||||||
|
0xA0, 0x54, 0xA9, 0xD3, 0x68, 0x78, 0x3E, 0xFF, 0x9A, 0x42, 0x19, 0x1D, 0x65, 0xFE, 0x28, 0x20,
|
||||||
|
0x09, 0xC5, 0x82, 0xA3, 0x41, 0xBE, 0x92, 0xFB, 0x46, 0xC0, 0x86, 0x69, 0x03, 0x93, 0x6D, 0xCB,
|
||||||
|
0xDE, 0xB2, 0x77, 0x71, 0x64, 0x7F, 0x4D, 0xF7, 0x57, 0x4F, 0xD8, 0x5F, 0x34, 0x69, 0x58, 0x0B,
|
||||||
|
0xE7, 0xB5, 0xAB, 0x8A, 0x4D, 0x6A, 0x83, 0xFB, 0xC4, 0xA7, 0x70, 0x3D, 0x6F, 0xB3, 0xCC, 0xB6,
|
||||||
|
0x1A, 0xE4, 0x5F, 0x60, 0xD4, 0x31, 0xBA, 0x95, 0x2F, 0x92, 0xF4, 0x81, 0x7B, 0x18, 0x5B, 0x17,
|
||||||
|
0x54, 0x26, 0x70, 0x49, 0xD5, 0x87, 0x34, 0xB9, 0xD3, 0x9C, 0x2F, 0x39, 0xC3, 0xB7, 0x3C, 0xA8,
|
||||||
|
0x03, 0xE4, 0x37, 0x9C, 0x72, 0x39, 0xB0, 0xBF, 0x07, 0x5D, 0x33, 0x2A, 0x41, 0x79, 0xB1, 0x26,
|
||||||
|
0x9B, 0xE6, 0x7C, 0x02, 0x82, 0x01, 0x70, 0xB1, 0xA3, 0x48, 0xCD, 0x2B, 0xCB, 0x98, 0x9B, 0x57,
|
||||||
|
0x96, 0x54, 0xE2, 0x5F, 0x59, 0xCC, 0xDB, 0x9F, 0xFC, 0xDB, 0x4C, 0xF9, 0x7F, 0x5B, 0x28, 0x36,
|
||||||
|
0x32, 0xF9, 0xE1, 0x09, 0xF7, 0x56, 0x3F, 0x45, 0xAD, 0x47, 0x51, 0xBB, 0xF7, 0xFF, 0x17, 0x53,
|
||||||
|
0xE8, 0x9D, 0x36, 0x92, 0x29, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPIFFS_MAXLENGTH_FILEPATH 32
|
||||||
|
const char *excludeListFile = "/.exclude.files";
|
||||||
|
|
||||||
|
typedef struct ExcludeListS {
|
||||||
|
char *item;
|
||||||
|
ExcludeListS *next;
|
||||||
|
} ExcludeList;
|
||||||
|
|
||||||
|
static ExcludeList *excludes = NULL;
|
||||||
|
|
||||||
|
static bool matchWild(const char *pattern, const char *testee) {
|
||||||
|
const char *nxPat = NULL, *nxTst = NULL;
|
||||||
|
|
||||||
|
while (*testee) {
|
||||||
|
if (( *pattern == '?' ) || (*pattern == *testee)){
|
||||||
|
pattern++;testee++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*pattern=='*'){
|
||||||
|
nxPat=pattern++; nxTst=testee;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (nxPat){
|
||||||
|
pattern = nxPat+1; testee=++nxTst;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (*pattern=='*'){pattern++;}
|
||||||
|
return (*pattern == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool addExclude(const char *item){
|
||||||
|
size_t len = strlen(item);
|
||||||
|
if(!len){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList));
|
||||||
|
if(!e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
e->item = (char *)malloc(len+1);
|
||||||
|
if(!e->item){
|
||||||
|
free(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(e->item, item, len+1);
|
||||||
|
e->next = excludes;
|
||||||
|
excludes = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadExcludeList(fs::FS &_fs, const char *filename){
|
||||||
|
static char linebuf[SPIFFS_MAXLENGTH_FILEPATH];
|
||||||
|
fs::File excludeFile=_fs.open(filename, "r");
|
||||||
|
if(!excludeFile){
|
||||||
|
//addExclude("/*.js.gz");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef ESP32
|
||||||
|
if(excludeFile.isDirectory()){
|
||||||
|
excludeFile.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (excludeFile.size() > 0){
|
||||||
|
uint8_t idx;
|
||||||
|
bool isOverflowed = false;
|
||||||
|
while (excludeFile.available()){
|
||||||
|
linebuf[0] = '\0';
|
||||||
|
idx = 0;
|
||||||
|
int lastChar;
|
||||||
|
do {
|
||||||
|
lastChar = excludeFile.read();
|
||||||
|
if(lastChar != '\r'){
|
||||||
|
linebuf[idx++] = (char) lastChar;
|
||||||
|
}
|
||||||
|
} while ((lastChar >= 0) && (lastChar != '\n') && (idx < SPIFFS_MAXLENGTH_FILEPATH));
|
||||||
|
|
||||||
|
if(isOverflowed){
|
||||||
|
isOverflowed = (lastChar != '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
isOverflowed = (idx >= SPIFFS_MAXLENGTH_FILEPATH);
|
||||||
|
linebuf[idx-1] = '\0';
|
||||||
|
if(!addExclude(linebuf)){
|
||||||
|
excludeFile.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
excludeFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isExcluded(fs::FS &_fs, const char *filename) {
|
||||||
|
if(excludes == NULL){
|
||||||
|
loadExcludeList(_fs, excludeListFile);
|
||||||
|
}
|
||||||
|
ExcludeList *e = excludes;
|
||||||
|
while(e){
|
||||||
|
if (matchWild(e->item, filename)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WEB HANDLER IMPLEMENTATION
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
SPIFFSEditor::SPIFFSEditor(const fs::FS& fs, const String& username, const String& password)
|
||||||
|
#else
|
||||||
|
SPIFFSEditor::SPIFFSEditor(const String& username, const String& password, const fs::FS& fs)
|
||||||
|
#endif
|
||||||
|
:_fs(fs)
|
||||||
|
,_username(username)
|
||||||
|
,_password(password)
|
||||||
|
,_authenticated(false)
|
||||||
|
,_startTime(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request){
|
||||||
|
if(request->url().equalsIgnoreCase("/edit")){
|
||||||
|
if(request->method() == HTTP_GET){
|
||||||
|
if(request->hasParam("list"))
|
||||||
|
return true;
|
||||||
|
if(request->hasParam("edit")){
|
||||||
|
request->_tempFile = _fs.open(request->arg("edit"), "r");
|
||||||
|
if(!request->_tempFile){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef ESP32
|
||||||
|
if(request->_tempFile.isDirectory()){
|
||||||
|
request->_tempFile.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if(request->hasParam("download")){
|
||||||
|
request->_tempFile = _fs.open(request->arg("download"), "r");
|
||||||
|
if(!request->_tempFile){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef ESP32
|
||||||
|
if(request->_tempFile.isDirectory()){
|
||||||
|
request->_tempFile.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
request->addInterestingHeader("If-Modified-Since");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(request->method() == HTTP_POST)
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_DELETE)
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_PUT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){
|
||||||
|
if(_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str()))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
|
||||||
|
if(request->method() == HTTP_GET){
|
||||||
|
if(request->hasParam("list")){
|
||||||
|
String path = request->getParam("list")->value();
|
||||||
|
#ifdef ESP32
|
||||||
|
File dir = _fs.open(path);
|
||||||
|
#else
|
||||||
|
Dir dir = _fs.openDir(path);
|
||||||
|
#endif
|
||||||
|
path = String();
|
||||||
|
String output = "[";
|
||||||
|
#ifdef ESP32
|
||||||
|
File entry = dir.openNextFile();
|
||||||
|
while(entry){
|
||||||
|
#else
|
||||||
|
while(dir.next()){
|
||||||
|
fs::File entry = dir.openFile("r");
|
||||||
|
#endif
|
||||||
|
if (isExcluded(_fs, entry.name())) {
|
||||||
|
#ifdef ESP32
|
||||||
|
entry = dir.openNextFile();
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (output != "[") output += ',';
|
||||||
|
output += "{\"type\":\"";
|
||||||
|
output += "file";
|
||||||
|
output += "\",\"name\":\"";
|
||||||
|
output += String(entry.name());
|
||||||
|
output += "\",\"size\":";
|
||||||
|
output += String(entry.size());
|
||||||
|
output += "}";
|
||||||
|
#ifdef ESP32
|
||||||
|
entry = dir.openNextFile();
|
||||||
|
#else
|
||||||
|
entry.close();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef ESP32
|
||||||
|
dir.close();
|
||||||
|
#endif
|
||||||
|
output += "]";
|
||||||
|
request->send(200, "application/json", output);
|
||||||
|
output = String();
|
||||||
|
}
|
||||||
|
else if(request->hasParam("edit") || request->hasParam("download")){
|
||||||
|
request->send(request->_tempFile, request->_tempFile.name(), String(), request->hasParam("download"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const char * buildTime = __DATE__ " " __TIME__ " GMT";
|
||||||
|
if (request->header("If-Modified-Since").equals(buildTime)) {
|
||||||
|
request->send(304);
|
||||||
|
} else {
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len);
|
||||||
|
response->addHeader("Content-Encoding", "gzip");
|
||||||
|
response->addHeader("Last-Modified", buildTime);
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(request->method() == HTTP_DELETE){
|
||||||
|
if(request->hasParam("path", true)){
|
||||||
|
_fs.remove(request->getParam("path", true)->value());
|
||||||
|
request->send(200, "", "DELETE: "+request->getParam("path", true)->value());
|
||||||
|
} else
|
||||||
|
request->send(404);
|
||||||
|
} else if(request->method() == HTTP_POST){
|
||||||
|
if(request->hasParam("data", true, true) && _fs.exists(request->getParam("data", true, true)->value()))
|
||||||
|
request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value());
|
||||||
|
else
|
||||||
|
request->send(500);
|
||||||
|
} else if(request->method() == HTTP_PUT){
|
||||||
|
if(request->hasParam("path", true)){
|
||||||
|
String filename = request->getParam("path", true)->value();
|
||||||
|
if(_fs.exists(filename)){
|
||||||
|
request->send(200);
|
||||||
|
} else {
|
||||||
|
fs::File f = _fs.open(filename, "w");
|
||||||
|
if(f){
|
||||||
|
f.write((uint8_t)0x00);
|
||||||
|
f.close();
|
||||||
|
request->send(200, "", "CREATE: "+filename);
|
||||||
|
} else {
|
||||||
|
request->send(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
request->send(400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPIFFSEditor::handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
|
if(!index){
|
||||||
|
if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str())){
|
||||||
|
_authenticated = true;
|
||||||
|
request->_tempFile = _fs.open(filename, "w");
|
||||||
|
_startTime = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(_authenticated && request->_tempFile){
|
||||||
|
if(len){
|
||||||
|
request->_tempFile.write(data,len);
|
||||||
|
}
|
||||||
|
if(final){
|
||||||
|
request->_tempFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
lib/ESPAsyncWebServer/src/SPIFFSEditor.h
Normal file
24
lib/ESPAsyncWebServer/src/SPIFFSEditor.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef SPIFFSEditor_H_
|
||||||
|
#define SPIFFSEditor_H_
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
class SPIFFSEditor: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
fs::FS _fs;
|
||||||
|
String _username;
|
||||||
|
String _password;
|
||||||
|
bool _authenticated;
|
||||||
|
uint32_t _startTime;
|
||||||
|
public:
|
||||||
|
#ifdef ESP32
|
||||||
|
SPIFFSEditor(const fs::FS& fs, const String& username=String(), const String& password=String());
|
||||||
|
#else
|
||||||
|
SPIFFSEditor(const String& username=String(), const String& password=String(), const fs::FS& fs=SPIFFS);
|
||||||
|
#endif
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return false;}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
193
lib/ESPAsyncWebServer/src/StringArray.h
Normal file
193
lib/ESPAsyncWebServer/src/StringArray.h
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 STRINGARRAY_H_
|
||||||
|
#define STRINGARRAY_H_
|
||||||
|
|
||||||
|
#include "stddef.h"
|
||||||
|
#include "WString.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class LinkedListNode {
|
||||||
|
T _value;
|
||||||
|
public:
|
||||||
|
LinkedListNode<T>* next;
|
||||||
|
LinkedListNode(const T val): _value(val), next(nullptr) {}
|
||||||
|
~LinkedListNode(){}
|
||||||
|
const T& value() const { return _value; };
|
||||||
|
T& value(){ return _value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, template<typename> class Item = LinkedListNode>
|
||||||
|
class LinkedList {
|
||||||
|
public:
|
||||||
|
typedef Item<T> ItemType;
|
||||||
|
typedef std::function<void(const T&)> OnRemove;
|
||||||
|
typedef std::function<bool(const T&)> Predicate;
|
||||||
|
private:
|
||||||
|
ItemType* _root;
|
||||||
|
OnRemove _onRemove;
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
ItemType* _node;
|
||||||
|
public:
|
||||||
|
Iterator(ItemType* current = nullptr) : _node(current) {}
|
||||||
|
Iterator(const Iterator& i) : _node(i._node) {}
|
||||||
|
Iterator& operator ++() { _node = _node->next; return *this; }
|
||||||
|
bool operator != (const Iterator& i) const { return _node != i._node; }
|
||||||
|
const T& operator * () const { return _node->value(); }
|
||||||
|
const T* operator -> () const { return &_node->value(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const Iterator ConstIterator;
|
||||||
|
ConstIterator begin() const { return ConstIterator(_root); }
|
||||||
|
ConstIterator end() const { return ConstIterator(nullptr); }
|
||||||
|
|
||||||
|
LinkedList(OnRemove onRemove) : _root(nullptr), _onRemove(onRemove) {}
|
||||||
|
~LinkedList(){}
|
||||||
|
void add(const T& t){
|
||||||
|
auto it = new ItemType(t);
|
||||||
|
if(!_root){
|
||||||
|
_root = it;
|
||||||
|
} else {
|
||||||
|
auto i = _root;
|
||||||
|
while(i->next) i = i->next;
|
||||||
|
i->next = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T& front() const {
|
||||||
|
return _root->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const {
|
||||||
|
return _root == nullptr;
|
||||||
|
}
|
||||||
|
size_t length() const {
|
||||||
|
size_t i = 0;
|
||||||
|
auto it = _root;
|
||||||
|
while(it){
|
||||||
|
i++;
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
size_t count_if(Predicate predicate) const {
|
||||||
|
size_t i = 0;
|
||||||
|
auto it = _root;
|
||||||
|
while(it){
|
||||||
|
if (!predicate){
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (predicate(it->value())) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
const T* nth(size_t N) const {
|
||||||
|
size_t i = 0;
|
||||||
|
auto it = _root;
|
||||||
|
while(it){
|
||||||
|
if(i++ == N)
|
||||||
|
return &(it->value());
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool remove(const T& t){
|
||||||
|
auto it = _root;
|
||||||
|
auto pit = _root;
|
||||||
|
while(it){
|
||||||
|
if(it->value() == t){
|
||||||
|
if(it == _root){
|
||||||
|
_root = _root->next;
|
||||||
|
} else {
|
||||||
|
pit->next = it->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_onRemove) {
|
||||||
|
_onRemove(it->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pit = it;
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool remove_first(Predicate predicate){
|
||||||
|
auto it = _root;
|
||||||
|
auto pit = _root;
|
||||||
|
while(it){
|
||||||
|
if(predicate(it->value())){
|
||||||
|
if(it == _root){
|
||||||
|
_root = _root->next;
|
||||||
|
} else {
|
||||||
|
pit->next = it->next;
|
||||||
|
}
|
||||||
|
if (_onRemove) {
|
||||||
|
_onRemove(it->value());
|
||||||
|
}
|
||||||
|
delete it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pit = it;
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(){
|
||||||
|
while(_root != nullptr){
|
||||||
|
auto it = _root;
|
||||||
|
_root = _root->next;
|
||||||
|
if (_onRemove) {
|
||||||
|
_onRemove(it->value());
|
||||||
|
}
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
_root = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StringArray : public LinkedList<String> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
StringArray() : LinkedList(nullptr) {}
|
||||||
|
|
||||||
|
bool containsIgnoreCase(const String& str){
|
||||||
|
for (const auto& s : *this) {
|
||||||
|
if (str.equalsIgnoreCase(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* STRINGARRAY_H_ */
|
||||||
235
lib/ESPAsyncWebServer/src/WebAuthentication.cpp
Normal file
235
lib/ESPAsyncWebServer/src/WebAuthentication.cpp
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 "WebAuthentication.h"
|
||||||
|
#include <libb64/cencode.h>
|
||||||
|
#ifdef ESP32
|
||||||
|
#include "mbedtls/md5.h"
|
||||||
|
#else
|
||||||
|
#include "md5.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Basic Auth hash = base64("username:password")
|
||||||
|
|
||||||
|
bool checkBasicAuthentication(const char * hash, const char * username, const char * password){
|
||||||
|
if(username == NULL || password == NULL || hash == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t toencodeLen = strlen(username)+strlen(password)+1;
|
||||||
|
size_t encodedLen = base64_encode_expected_len(toencodeLen);
|
||||||
|
if(strlen(hash) != encodedLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char *toencode = new char[toencodeLen+1];
|
||||||
|
if(toencode == NULL){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
|
||||||
|
if(encoded == NULL){
|
||||||
|
delete[] toencode;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sprintf(toencode, "%s:%s", username, password);
|
||||||
|
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0){
|
||||||
|
delete[] toencode;
|
||||||
|
delete[] encoded;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
delete[] toencode;
|
||||||
|
delete[] encoded;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or more
|
||||||
|
#ifdef ESP32
|
||||||
|
mbedtls_md5_context _ctx;
|
||||||
|
#else
|
||||||
|
md5_context_t _ctx;
|
||||||
|
#endif
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t * _buf = (uint8_t*)malloc(16);
|
||||||
|
if(_buf == NULL)
|
||||||
|
return false;
|
||||||
|
memset(_buf, 0x00, 16);
|
||||||
|
#ifdef ESP32
|
||||||
|
mbedtls_md5_init(&_ctx);
|
||||||
|
mbedtls_md5_starts(&_ctx);
|
||||||
|
mbedtls_md5_update(&_ctx, data, len);
|
||||||
|
mbedtls_md5_finish(&_ctx, _buf);
|
||||||
|
#else
|
||||||
|
MD5Init(&_ctx);
|
||||||
|
MD5Update(&_ctx, data, len);
|
||||||
|
MD5Final(_buf, &_ctx);
|
||||||
|
#endif
|
||||||
|
for(i = 0; i < 16; i++) {
|
||||||
|
sprintf(output + (i * 2), "%02x", _buf[i]);
|
||||||
|
}
|
||||||
|
free(_buf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String genRandomMD5(){
|
||||||
|
#ifdef ESP8266
|
||||||
|
uint32_t r = RANDOM_REG32;
|
||||||
|
#else
|
||||||
|
uint32_t r = rand();
|
||||||
|
#endif
|
||||||
|
char * out = (char*)malloc(33);
|
||||||
|
if(out == NULL || !getMD5((uint8_t*)(&r), 4, out))
|
||||||
|
return "";
|
||||||
|
String res = String(out);
|
||||||
|
free(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String stringMD5(const String& in){
|
||||||
|
char * out = (char*)malloc(33);
|
||||||
|
if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
|
||||||
|
return "";
|
||||||
|
String res = String(out);
|
||||||
|
free(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String generateDigestHash(const char * username, const char * password, const char * realm){
|
||||||
|
if(username == NULL || password == NULL || realm == NULL){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
char * out = (char*)malloc(33);
|
||||||
|
String res = String(username);
|
||||||
|
res.concat(":");
|
||||||
|
res.concat(realm);
|
||||||
|
res.concat(":");
|
||||||
|
String in = res;
|
||||||
|
in.concat(password);
|
||||||
|
if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
|
||||||
|
return "";
|
||||||
|
res.concat(out);
|
||||||
|
free(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String requestDigestAuthentication(const char * realm){
|
||||||
|
String header = "realm=\"";
|
||||||
|
if(realm == NULL)
|
||||||
|
header.concat("asyncesp");
|
||||||
|
else
|
||||||
|
header.concat(realm);
|
||||||
|
header.concat( "\", qop=\"auth\", nonce=\"");
|
||||||
|
header.concat(genRandomMD5());
|
||||||
|
header.concat("\", opaque=\"");
|
||||||
|
header.concat(genRandomMD5());
|
||||||
|
header.concat("\"");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri){
|
||||||
|
if(username == NULL || password == NULL || header == NULL || method == NULL){
|
||||||
|
//os_printf("AUTH FAIL: missing requred fields\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String myHeader = String(header);
|
||||||
|
int nextBreak = myHeader.indexOf(",");
|
||||||
|
if(nextBreak < 0){
|
||||||
|
//os_printf("AUTH FAIL: no variables\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String myUsername = String();
|
||||||
|
String myRealm = String();
|
||||||
|
String myNonce = String();
|
||||||
|
String myUri = String();
|
||||||
|
String myResponse = String();
|
||||||
|
String myQop = String();
|
||||||
|
String myNc = String();
|
||||||
|
String myCnonce = String();
|
||||||
|
|
||||||
|
myHeader += ", ";
|
||||||
|
do {
|
||||||
|
String avLine = myHeader.substring(0, nextBreak);
|
||||||
|
avLine.trim();
|
||||||
|
myHeader = myHeader.substring(nextBreak+1);
|
||||||
|
nextBreak = myHeader.indexOf(",");
|
||||||
|
|
||||||
|
int eqSign = avLine.indexOf("=");
|
||||||
|
if(eqSign < 0){
|
||||||
|
//os_printf("AUTH FAIL: no = sign\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String varName = avLine.substring(0, eqSign);
|
||||||
|
avLine = avLine.substring(eqSign + 1);
|
||||||
|
if(avLine.startsWith("\"")){
|
||||||
|
avLine = avLine.substring(1, avLine.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(varName.equals("username")){
|
||||||
|
if(!avLine.equals(username)){
|
||||||
|
//os_printf("AUTH FAIL: username\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
myUsername = avLine;
|
||||||
|
} else if(varName.equals("realm")){
|
||||||
|
if(realm != NULL && !avLine.equals(realm)){
|
||||||
|
//os_printf("AUTH FAIL: realm\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
myRealm = avLine;
|
||||||
|
} else if(varName.equals("nonce")){
|
||||||
|
if(nonce != NULL && !avLine.equals(nonce)){
|
||||||
|
//os_printf("AUTH FAIL: nonce\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
myNonce = avLine;
|
||||||
|
} else if(varName.equals("opaque")){
|
||||||
|
if(opaque != NULL && !avLine.equals(opaque)){
|
||||||
|
//os_printf("AUTH FAIL: opaque\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if(varName.equals("uri")){
|
||||||
|
if(uri != NULL && !avLine.equals(uri)){
|
||||||
|
//os_printf("AUTH FAIL: uri\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
myUri = avLine;
|
||||||
|
} else if(varName.equals("response")){
|
||||||
|
myResponse = avLine;
|
||||||
|
} else if(varName.equals("qop")){
|
||||||
|
myQop = avLine;
|
||||||
|
} else if(varName.equals("nc")){
|
||||||
|
myNc = avLine;
|
||||||
|
} else if(varName.equals("cnonce")){
|
||||||
|
myCnonce = avLine;
|
||||||
|
}
|
||||||
|
} while(nextBreak > 0);
|
||||||
|
|
||||||
|
String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ":" + myRealm + ":" + String(password));
|
||||||
|
String ha2 = String(method) + ":" + myUri;
|
||||||
|
String response = ha1 + ":" + myNonce + ":" + myNc + ":" + myCnonce + ":" + myQop + ":" + stringMD5(ha2);
|
||||||
|
|
||||||
|
if(myResponse.equals(stringMD5(response))){
|
||||||
|
//os_printf("AUTH SUCCESS\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//os_printf("AUTH FAIL: password\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
34
lib/ESPAsyncWebServer/src/WebAuthentication.h
Normal file
34
lib/ESPAsyncWebServer/src/WebAuthentication.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 WEB_AUTHENTICATION_H_
|
||||||
|
#define WEB_AUTHENTICATION_H_
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
bool checkBasicAuthentication(const char * header, const char * username, const char * password);
|
||||||
|
String requestDigestAuthentication(const char * realm);
|
||||||
|
bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri);
|
||||||
|
|
||||||
|
//for storing hashed versions on the device that can be authenticated against
|
||||||
|
String generateDigestHash(const char * username, const char * password, const char * realm);
|
||||||
|
|
||||||
|
#endif
|
||||||
138
lib/ESPAsyncWebServer/src/WebHandlerImpl.h
Normal file
138
lib/ESPAsyncWebServer/src/WebHandlerImpl.h
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 ASYNCWEBSERVERHANDLERIMPL_H_
|
||||||
|
#define ASYNCWEBSERVERHANDLERIMPL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#ifdef ASYNCWEBSERVER_REGEX
|
||||||
|
#include <regex>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stddef.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
class AsyncStaticWebHandler: public AsyncWebHandler {
|
||||||
|
using File = fs::File;
|
||||||
|
using FS = fs::FS;
|
||||||
|
private:
|
||||||
|
bool _getFile(AsyncWebServerRequest *request);
|
||||||
|
bool _fileExists(AsyncWebServerRequest *request, const String& path);
|
||||||
|
uint8_t _countBits(const uint8_t value) const;
|
||||||
|
protected:
|
||||||
|
FS _fs;
|
||||||
|
String _uri;
|
||||||
|
String _path;
|
||||||
|
String _default_file;
|
||||||
|
String _cache_control;
|
||||||
|
String _last_modified;
|
||||||
|
AwsTemplateProcessor _callback;
|
||||||
|
bool _isDir;
|
||||||
|
bool _gzipFirst;
|
||||||
|
uint8_t _gzipStats;
|
||||||
|
public:
|
||||||
|
AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
|
AsyncStaticWebHandler& setIsDir(bool isDir);
|
||||||
|
AsyncStaticWebHandler& setDefaultFile(const char* filename);
|
||||||
|
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
|
||||||
|
AsyncStaticWebHandler& setLastModified(const char* last_modified);
|
||||||
|
AsyncStaticWebHandler& setLastModified(struct tm* last_modified);
|
||||||
|
#ifdef ESP8266
|
||||||
|
AsyncStaticWebHandler& setLastModified(time_t last_modified);
|
||||||
|
AsyncStaticWebHandler& setLastModified(); //sets to current time. Make sure sntp is runing and time is updated
|
||||||
|
#endif
|
||||||
|
AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncCallbackWebHandler: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
protected:
|
||||||
|
String _uri;
|
||||||
|
WebRequestMethodComposite _method;
|
||||||
|
ArRequestHandlerFunction _onRequest;
|
||||||
|
ArUploadHandlerFunction _onUpload;
|
||||||
|
ArBodyHandlerFunction _onBody;
|
||||||
|
bool _isRegex;
|
||||||
|
public:
|
||||||
|
AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {}
|
||||||
|
void setUri(const String& uri){
|
||||||
|
_uri = uri;
|
||||||
|
_isRegex = uri.startsWith("^") && uri.endsWith("$");
|
||||||
|
}
|
||||||
|
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
||||||
|
void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; }
|
||||||
|
void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; }
|
||||||
|
void onBody(ArBodyHandlerFunction fn){ _onBody = fn; }
|
||||||
|
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final{
|
||||||
|
|
||||||
|
if(!_onRequest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!(_method & request->method()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef ASYNCWEBSERVER_REGEX
|
||||||
|
if (_isRegex) {
|
||||||
|
std::regex pattern(_uri.c_str());
|
||||||
|
std::smatch matches;
|
||||||
|
std::string s(request->url().c_str());
|
||||||
|
if(std::regex_search(s, matches, pattern)) {
|
||||||
|
for (size_t i = 1; i < matches.size(); ++i) { // start from 1
|
||||||
|
request->_addPathParam(matches[i].str().c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (_uri.length() && _uri.endsWith("*")) {
|
||||||
|
String uriTemplate = String(_uri);
|
||||||
|
uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1);
|
||||||
|
if (!request->url().startsWith(uriTemplate))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
request->addInterestingHeader("ANY");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
||||||
|
if(_onRequest)
|
||||||
|
_onRequest(request);
|
||||||
|
else
|
||||||
|
request->send(500);
|
||||||
|
}
|
||||||
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
|
||||||
|
if(_onUpload)
|
||||||
|
_onUpload(request, filename, index, data, len, final);
|
||||||
|
}
|
||||||
|
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||||
|
if(_onBody)
|
||||||
|
_onBody(request, data, len, index, total);
|
||||||
|
}
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
||||||
220
lib/ESPAsyncWebServer/src/WebHandlers.cpp
Normal file
220
lib/ESPAsyncWebServer/src/WebHandlers.cpp
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 "ESPAsyncWebServer.h"
|
||||||
|
#include "WebHandlerImpl.h"
|
||||||
|
|
||||||
|
AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control)
|
||||||
|
: _fs(fs), _uri(uri), _path(path), _default_file("index.htm"), _cache_control(cache_control), _last_modified(""), _callback(nullptr)
|
||||||
|
{
|
||||||
|
// Ensure leading '/'
|
||||||
|
if (_uri.length() == 0 || _uri[0] != '/') _uri = "/" + _uri;
|
||||||
|
if (_path.length() == 0 || _path[0] != '/') _path = "/" + _path;
|
||||||
|
|
||||||
|
// If path ends with '/' we assume a hint that this is a directory to improve performance.
|
||||||
|
// However - if it does not end with '/' we, can't assume a file, path can still be a directory.
|
||||||
|
_isDir = _path[_path.length()-1] == '/';
|
||||||
|
|
||||||
|
// Remove the trailing '/' so we can handle default file
|
||||||
|
// Notice that root will be "" not "/"
|
||||||
|
if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1);
|
||||||
|
if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1);
|
||||||
|
|
||||||
|
// Reset stats
|
||||||
|
_gzipFirst = false;
|
||||||
|
_gzipStats = 0xF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir){
|
||||||
|
_isDir = isDir;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename){
|
||||||
|
_default_file = String(filename);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control){
|
||||||
|
_cache_control = String(cache_control);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified){
|
||||||
|
_last_modified = String(last_modified);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified){
|
||||||
|
char result[30];
|
||||||
|
strftime (result,30,"%a, %d %b %Y %H:%M:%S %Z", last_modified);
|
||||||
|
return setLastModified((const char *)result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified){
|
||||||
|
return setLastModified((struct tm *)gmtime(&last_modified));
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){
|
||||||
|
time_t last_modified;
|
||||||
|
if(time(&last_modified) == 0) //time is not yet set
|
||||||
|
return *this;
|
||||||
|
return setLastModified(last_modified);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){
|
||||||
|
if(request->method() != HTTP_GET
|
||||||
|
|| !request->url().startsWith(_uri)
|
||||||
|
|| !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)
|
||||||
|
){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_getFile(request)) {
|
||||||
|
// We interested in "If-Modified-Since" header to check if file was modified
|
||||||
|
if (_last_modified.length())
|
||||||
|
request->addInterestingHeader("If-Modified-Since");
|
||||||
|
|
||||||
|
if(_cache_control.length())
|
||||||
|
request->addInterestingHeader("If-None-Match");
|
||||||
|
|
||||||
|
DEBUGF("[AsyncStaticWebHandler::canHandle] TRUE\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
// Remove the found uri
|
||||||
|
String path = request->url().substring(_uri.length());
|
||||||
|
|
||||||
|
// We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/'
|
||||||
|
bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/');
|
||||||
|
|
||||||
|
path = _path + path;
|
||||||
|
|
||||||
|
// Do we have a file or .gz file
|
||||||
|
if (!canSkipFileCheck && _fileExists(request, path))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Can't handle if not default file
|
||||||
|
if (_default_file.length() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Try to add default file, ensure there is a trailing '/' ot the path.
|
||||||
|
if (path.length() == 0 || path[path.length()-1] != '/')
|
||||||
|
path += "/";
|
||||||
|
path += _default_file;
|
||||||
|
|
||||||
|
return _fileExists(request, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#define FILE_IS_REAL(f) (f == true && !f.isDirectory())
|
||||||
|
#else
|
||||||
|
#define FILE_IS_REAL(f) (f == true)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const String& path)
|
||||||
|
{
|
||||||
|
bool fileFound = false;
|
||||||
|
bool gzipFound = false;
|
||||||
|
|
||||||
|
String gzip = path + ".gz";
|
||||||
|
|
||||||
|
if (_gzipFirst) {
|
||||||
|
request->_tempFile = _fs.open(gzip, "r");
|
||||||
|
gzipFound = FILE_IS_REAL(request->_tempFile);
|
||||||
|
if (!gzipFound){
|
||||||
|
request->_tempFile = _fs.open(path, "r");
|
||||||
|
fileFound = FILE_IS_REAL(request->_tempFile);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request->_tempFile = _fs.open(path, "r");
|
||||||
|
fileFound = FILE_IS_REAL(request->_tempFile);
|
||||||
|
if (!fileFound){
|
||||||
|
request->_tempFile = _fs.open(gzip, "r");
|
||||||
|
gzipFound = FILE_IS_REAL(request->_tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = fileFound || gzipFound;
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
// Extract the file name from the path and keep it in _tempObject
|
||||||
|
size_t pathLen = path.length();
|
||||||
|
char * _tempPath = (char*)malloc(pathLen+1);
|
||||||
|
snprintf(_tempPath, pathLen+1, "%s", path.c_str());
|
||||||
|
request->_tempObject = (void*)_tempPath;
|
||||||
|
|
||||||
|
// Calculate gzip statistic
|
||||||
|
_gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0);
|
||||||
|
if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip
|
||||||
|
else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip
|
||||||
|
else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const
|
||||||
|
{
|
||||||
|
uint8_t w = value;
|
||||||
|
uint8_t n;
|
||||||
|
for (n=0; w!=0; n++) w&=w-1;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
// Get the filename from request->_tempObject and free it
|
||||||
|
String filename = String((char*)request->_tempObject);
|
||||||
|
free(request->_tempObject);
|
||||||
|
request->_tempObject = NULL;
|
||||||
|
if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
|
||||||
|
if (request->_tempFile == true) {
|
||||||
|
String etag = String(request->_tempFile.size());
|
||||||
|
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since")) {
|
||||||
|
request->_tempFile.close();
|
||||||
|
request->send(304); // Not modified
|
||||||
|
} else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag)) {
|
||||||
|
request->_tempFile.close();
|
||||||
|
AsyncWebServerResponse * response = new AsyncBasicResponse(304); // Not modified
|
||||||
|
response->addHeader("Cache-Control", _cache_control);
|
||||||
|
response->addHeader("ETag", etag);
|
||||||
|
request->send(response);
|
||||||
|
} else {
|
||||||
|
AsyncWebServerResponse * response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback);
|
||||||
|
if (_last_modified.length())
|
||||||
|
response->addHeader("Last-Modified", _last_modified);
|
||||||
|
if (_cache_control.length()){
|
||||||
|
response->addHeader("Cache-Control", _cache_control);
|
||||||
|
response->addHeader("ETag", etag);
|
||||||
|
}
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request->send(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
1008
lib/ESPAsyncWebServer/src/WebRequest.cpp
Normal file
1008
lib/ESPAsyncWebServer/src/WebRequest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
136
lib/ESPAsyncWebServer/src/WebResponseImpl.h
Normal file
136
lib/ESPAsyncWebServer/src/WebResponseImpl.h
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 ASYNCWEBSERVERRESPONSEIMPL_H_
|
||||||
|
#define ASYNCWEBSERVERRESPONSEIMPL_H_
|
||||||
|
|
||||||
|
#ifdef Arduino_h
|
||||||
|
// arduino is not compatible with std::vector
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
#include <vector>
|
||||||
|
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
|
||||||
|
|
||||||
|
class AsyncBasicResponse: public AsyncWebServerResponse {
|
||||||
|
private:
|
||||||
|
String _content;
|
||||||
|
public:
|
||||||
|
AsyncBasicResponse(int code, const String& contentType=String(), const String& content=String());
|
||||||
|
void _respond(AsyncWebServerRequest *request);
|
||||||
|
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
||||||
|
bool _sourceValid() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncAbstractResponse: public AsyncWebServerResponse {
|
||||||
|
private:
|
||||||
|
String _head;
|
||||||
|
// Data is inserted into cache at begin().
|
||||||
|
// This is inefficient with vector, but if we use some other container,
|
||||||
|
// we won't be able to access it as contiguous array of bytes when reading from it,
|
||||||
|
// so by gaining performance in one place, we'll lose it in another.
|
||||||
|
std::vector<uint8_t> _cache;
|
||||||
|
size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len);
|
||||||
|
size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen);
|
||||||
|
protected:
|
||||||
|
AwsTemplateProcessor _callback;
|
||||||
|
public:
|
||||||
|
AsyncAbstractResponse(AwsTemplateProcessor callback=nullptr);
|
||||||
|
void _respond(AsyncWebServerRequest *request);
|
||||||
|
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
||||||
|
bool _sourceValid() const { return false; }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef TEMPLATE_PLACEHOLDER
|
||||||
|
#define TEMPLATE_PLACEHOLDER '%'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TEMPLATE_PARAM_NAME_LENGTH 32
|
||||||
|
class AsyncFileResponse: public AsyncAbstractResponse {
|
||||||
|
using File = fs::File;
|
||||||
|
using FS = fs::FS;
|
||||||
|
private:
|
||||||
|
File _content;
|
||||||
|
String _path;
|
||||||
|
void _setContentType(const String& path);
|
||||||
|
public:
|
||||||
|
AsyncFileResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
|
||||||
|
AsyncFileResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
|
||||||
|
~AsyncFileResponse();
|
||||||
|
bool _sourceValid() const { return !!(_content); }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncStreamResponse: public AsyncAbstractResponse {
|
||||||
|
private:
|
||||||
|
Stream *_content;
|
||||||
|
public:
|
||||||
|
AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr);
|
||||||
|
bool _sourceValid() const { return !!(_content); }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncCallbackResponse: public AsyncAbstractResponse {
|
||||||
|
private:
|
||||||
|
AwsResponseFiller _content;
|
||||||
|
size_t _filledLength;
|
||||||
|
public:
|
||||||
|
AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
|
||||||
|
bool _sourceValid() const { return !!(_content); }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncChunkedResponse: public AsyncAbstractResponse {
|
||||||
|
private:
|
||||||
|
AwsResponseFiller _content;
|
||||||
|
size_t _filledLength;
|
||||||
|
public:
|
||||||
|
AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
|
||||||
|
bool _sourceValid() const { return !!(_content); }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncProgmemResponse: public AsyncAbstractResponse {
|
||||||
|
private:
|
||||||
|
const uint8_t * _content;
|
||||||
|
size_t _readLength;
|
||||||
|
public:
|
||||||
|
AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
|
||||||
|
bool _sourceValid() const { return true; }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cbuf;
|
||||||
|
|
||||||
|
class AsyncResponseStream: public AsyncAbstractResponse, public Print {
|
||||||
|
private:
|
||||||
|
cbuf *_content;
|
||||||
|
public:
|
||||||
|
AsyncResponseStream(const String& contentType, size_t bufferSize);
|
||||||
|
~AsyncResponseStream();
|
||||||
|
bool _sourceValid() const { return (_state < RESPONSE_END); }
|
||||||
|
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
|
||||||
|
size_t write(const uint8_t *data, size_t len);
|
||||||
|
size_t write(uint8_t data);
|
||||||
|
using Print::write;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ASYNCWEBSERVERRESPONSEIMPL_H_ */
|
||||||
699
lib/ESPAsyncWebServer/src/WebResponses.cpp
Normal file
699
lib/ESPAsyncWebServer/src/WebResponses.cpp
Normal file
@@ -0,0 +1,699 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 "ESPAsyncWebServer.h"
|
||||||
|
#include "WebResponseImpl.h"
|
||||||
|
#include "cbuf.h"
|
||||||
|
|
||||||
|
// Since ESP8266 does not link memchr by default, here's its implementation.
|
||||||
|
void* memchr(void* ptr, int ch, size_t count)
|
||||||
|
{
|
||||||
|
unsigned char* p = static_cast<unsigned char*>(ptr);
|
||||||
|
while(count--)
|
||||||
|
if(*p++ == static_cast<unsigned char>(ch))
|
||||||
|
return --p;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Abstract Response
|
||||||
|
* */
|
||||||
|
const char* AsyncWebServerResponse::_responseCodeToString(int code) {
|
||||||
|
switch (code) {
|
||||||
|
case 100: return "Continue";
|
||||||
|
case 101: return "Switching Protocols";
|
||||||
|
case 200: return "OK";
|
||||||
|
case 201: return "Created";
|
||||||
|
case 202: return "Accepted";
|
||||||
|
case 203: return "Non-Authoritative Information";
|
||||||
|
case 204: return "No Content";
|
||||||
|
case 205: return "Reset Content";
|
||||||
|
case 206: return "Partial Content";
|
||||||
|
case 300: return "Multiple Choices";
|
||||||
|
case 301: return "Moved Permanently";
|
||||||
|
case 302: return "Found";
|
||||||
|
case 303: return "See Other";
|
||||||
|
case 304: return "Not Modified";
|
||||||
|
case 305: return "Use Proxy";
|
||||||
|
case 307: return "Temporary Redirect";
|
||||||
|
case 400: return "Bad Request";
|
||||||
|
case 401: return "Unauthorized";
|
||||||
|
case 402: return "Payment Required";
|
||||||
|
case 403: return "Forbidden";
|
||||||
|
case 404: return "Not Found";
|
||||||
|
case 405: return "Method Not Allowed";
|
||||||
|
case 406: return "Not Acceptable";
|
||||||
|
case 407: return "Proxy Authentication Required";
|
||||||
|
case 408: return "Request Time-out";
|
||||||
|
case 409: return "Conflict";
|
||||||
|
case 410: return "Gone";
|
||||||
|
case 411: return "Length Required";
|
||||||
|
case 412: return "Precondition Failed";
|
||||||
|
case 413: return "Request Entity Too Large";
|
||||||
|
case 414: return "Request-URI Too Large";
|
||||||
|
case 415: return "Unsupported Media Type";
|
||||||
|
case 416: return "Requested range not satisfiable";
|
||||||
|
case 417: return "Expectation Failed";
|
||||||
|
case 500: return "Internal Server Error";
|
||||||
|
case 501: return "Not Implemented";
|
||||||
|
case 502: return "Bad Gateway";
|
||||||
|
case 503: return "Service Unavailable";
|
||||||
|
case 504: return "Gateway Time-out";
|
||||||
|
case 505: return "HTTP Version not supported";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse::AsyncWebServerResponse()
|
||||||
|
: _code(0)
|
||||||
|
, _headers(LinkedList<AsyncWebHeader *>([](AsyncWebHeader *h){ delete h; }))
|
||||||
|
, _contentType()
|
||||||
|
, _contentLength(0)
|
||||||
|
, _sendContentLength(true)
|
||||||
|
, _chunked(false)
|
||||||
|
, _headLength(0)
|
||||||
|
, _sentLength(0)
|
||||||
|
, _ackedLength(0)
|
||||||
|
, _writtenLength(0)
|
||||||
|
, _state(RESPONSE_SETUP)
|
||||||
|
{
|
||||||
|
for(auto header: DefaultHeaders::Instance()) {
|
||||||
|
_headers.add(new AsyncWebHeader(header->name(), header->value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse::~AsyncWebServerResponse(){
|
||||||
|
_headers.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::setCode(int code){
|
||||||
|
if(_state == RESPONSE_SETUP)
|
||||||
|
_code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::setContentLength(size_t len){
|
||||||
|
if(_state == RESPONSE_SETUP)
|
||||||
|
_contentLength = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::setContentType(const String& type){
|
||||||
|
if(_state == RESPONSE_SETUP)
|
||||||
|
_contentType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::addHeader(const String& name, const String& value){
|
||||||
|
_headers.add(new AsyncWebHeader(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
String AsyncWebServerResponse::_assembleHead(uint8_t version){
|
||||||
|
if(version){
|
||||||
|
addHeader("Accept-Ranges","none");
|
||||||
|
if(_chunked)
|
||||||
|
addHeader("Transfer-Encoding","chunked");
|
||||||
|
}
|
||||||
|
String out = String();
|
||||||
|
int bufSize = 300;
|
||||||
|
char buf[bufSize];
|
||||||
|
|
||||||
|
snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, _responseCodeToString(_code));
|
||||||
|
out.concat(buf);
|
||||||
|
|
||||||
|
if(_sendContentLength) {
|
||||||
|
snprintf(buf, bufSize, "Content-Length: %d\r\n", _contentLength);
|
||||||
|
out.concat(buf);
|
||||||
|
}
|
||||||
|
if(_contentType.length()) {
|
||||||
|
snprintf(buf, bufSize, "Content-Type: %s\r\n", _contentType.c_str());
|
||||||
|
out.concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& header: _headers){
|
||||||
|
snprintf(buf, bufSize, "%s: %s\r\n", header->name().c_str(), header->value().c_str());
|
||||||
|
out.concat(buf);
|
||||||
|
}
|
||||||
|
_headers.free();
|
||||||
|
|
||||||
|
out.concat("\r\n");
|
||||||
|
_headLength = out.length();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; }
|
||||||
|
bool AsyncWebServerResponse::_finished() const { return _state > RESPONSE_WAIT_ACK; }
|
||||||
|
bool AsyncWebServerResponse::_failed() const { return _state == RESPONSE_FAILED; }
|
||||||
|
bool AsyncWebServerResponse::_sourceValid() const { return false; }
|
||||||
|
void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); }
|
||||||
|
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ (void)request; (void)len; (void)time; return 0; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* String/Code Response
|
||||||
|
* */
|
||||||
|
AsyncBasicResponse::AsyncBasicResponse(int code, const String& contentType, const String& content){
|
||||||
|
_code = code;
|
||||||
|
_content = content;
|
||||||
|
_contentType = contentType;
|
||||||
|
if(_content.length()){
|
||||||
|
_contentLength = _content.length();
|
||||||
|
if(!_contentType.length())
|
||||||
|
_contentType = "text/plain";
|
||||||
|
}
|
||||||
|
addHeader("Connection","close");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){
|
||||||
|
_state = RESPONSE_HEADERS;
|
||||||
|
String out = _assembleHead(request->version());
|
||||||
|
size_t outLen = out.length();
|
||||||
|
size_t space = request->client()->space();
|
||||||
|
if(!_contentLength && space >= outLen){
|
||||||
|
_writtenLength += request->client()->write(out.c_str(), outLen);
|
||||||
|
_state = RESPONSE_WAIT_ACK;
|
||||||
|
} else if(_contentLength && space >= outLen + _contentLength){
|
||||||
|
out += _content;
|
||||||
|
outLen += _contentLength;
|
||||||
|
_writtenLength += request->client()->write(out.c_str(), outLen);
|
||||||
|
_state = RESPONSE_WAIT_ACK;
|
||||||
|
} else if(space && space < outLen){
|
||||||
|
String partial = out.substring(0, space);
|
||||||
|
_content = out.substring(space) + _content;
|
||||||
|
_contentLength += outLen - space;
|
||||||
|
_writtenLength += request->client()->write(partial.c_str(), partial.length());
|
||||||
|
_state = RESPONSE_CONTENT;
|
||||||
|
} else if(space > outLen && space < (outLen + _contentLength)){
|
||||||
|
size_t shift = space - outLen;
|
||||||
|
outLen += shift;
|
||||||
|
_sentLength += shift;
|
||||||
|
out += _content.substring(0, shift);
|
||||||
|
_content = _content.substring(shift);
|
||||||
|
_writtenLength += request->client()->write(out.c_str(), outLen);
|
||||||
|
_state = RESPONSE_CONTENT;
|
||||||
|
} else {
|
||||||
|
_content = out + _content;
|
||||||
|
_contentLength += outLen;
|
||||||
|
_state = RESPONSE_CONTENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
|
||||||
|
(void)time;
|
||||||
|
_ackedLength += len;
|
||||||
|
if(_state == RESPONSE_CONTENT){
|
||||||
|
size_t available = _contentLength - _sentLength;
|
||||||
|
size_t space = request->client()->space();
|
||||||
|
//we can fit in this packet
|
||||||
|
if(space > available){
|
||||||
|
_writtenLength += request->client()->write(_content.c_str(), available);
|
||||||
|
_content = String();
|
||||||
|
_state = RESPONSE_WAIT_ACK;
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
//send some data, the rest on ack
|
||||||
|
String out = _content.substring(0, space);
|
||||||
|
_content = _content.substring(space);
|
||||||
|
_sentLength += space;
|
||||||
|
_writtenLength += request->client()->write(out.c_str(), space);
|
||||||
|
return space;
|
||||||
|
} else if(_state == RESPONSE_WAIT_ACK){
|
||||||
|
if(_ackedLength >= _writtenLength){
|
||||||
|
_state = RESPONSE_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Abstract Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback): _callback(callback)
|
||||||
|
{
|
||||||
|
// In case of template processing, we're unable to determine real response size
|
||||||
|
if(callback) {
|
||||||
|
_contentLength = 0;
|
||||||
|
_sendContentLength = false;
|
||||||
|
_chunked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){
|
||||||
|
addHeader("Connection","close");
|
||||||
|
_head = _assembleHead(request->version());
|
||||||
|
_state = RESPONSE_HEADERS;
|
||||||
|
_ack(request, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
|
||||||
|
(void)time;
|
||||||
|
if(!_sourceValid()){
|
||||||
|
_state = RESPONSE_FAILED;
|
||||||
|
request->client()->close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ackedLength += len;
|
||||||
|
size_t space = request->client()->space();
|
||||||
|
|
||||||
|
size_t headLen = _head.length();
|
||||||
|
if(_state == RESPONSE_HEADERS){
|
||||||
|
if(space >= headLen){
|
||||||
|
_state = RESPONSE_CONTENT;
|
||||||
|
space -= headLen;
|
||||||
|
} else {
|
||||||
|
String out = _head.substring(0, space);
|
||||||
|
_head = _head.substring(space);
|
||||||
|
_writtenLength += request->client()->write(out.c_str(), out.length());
|
||||||
|
return out.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_state == RESPONSE_CONTENT){
|
||||||
|
size_t outLen;
|
||||||
|
if(_chunked){
|
||||||
|
if(space <= 8){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
outLen = space;
|
||||||
|
} else if(!_sendContentLength){
|
||||||
|
outLen = space;
|
||||||
|
} else {
|
||||||
|
outLen = ((_contentLength - _sentLength) > space)?space:(_contentLength - _sentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *buf = (uint8_t *)malloc(outLen+headLen);
|
||||||
|
if (!buf) {
|
||||||
|
// os_printf("_ack malloc %d failed\n", outLen+headLen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(headLen){
|
||||||
|
memcpy(buf, _head.c_str(), _head.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readLen = 0;
|
||||||
|
|
||||||
|
if(_chunked){
|
||||||
|
// HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added.
|
||||||
|
// See RFC2616 sections 2, 3.6.1.
|
||||||
|
readLen = _fillBufferAndProcessTemplates(buf+headLen+6, outLen - 8);
|
||||||
|
if(readLen == RESPONSE_TRY_AGAIN){
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
outLen = sprintf((char*)buf+headLen, "%x", readLen) + headLen;
|
||||||
|
while(outLen < headLen + 4) buf[outLen++] = ' ';
|
||||||
|
buf[outLen++] = '\r';
|
||||||
|
buf[outLen++] = '\n';
|
||||||
|
outLen += readLen;
|
||||||
|
buf[outLen++] = '\r';
|
||||||
|
buf[outLen++] = '\n';
|
||||||
|
} else {
|
||||||
|
readLen = _fillBufferAndProcessTemplates(buf+headLen, outLen);
|
||||||
|
if(readLen == RESPONSE_TRY_AGAIN){
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
outLen = readLen + headLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(headLen){
|
||||||
|
_head = String();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outLen){
|
||||||
|
_writtenLength += request->client()->write((const char*)buf, outLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_chunked){
|
||||||
|
_sentLength += readLen;
|
||||||
|
} else {
|
||||||
|
_sentLength += outLen - headLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || (!_chunked && _sentLength == _contentLength)){
|
||||||
|
_state = RESPONSE_WAIT_ACK;
|
||||||
|
}
|
||||||
|
return outLen;
|
||||||
|
|
||||||
|
} else if(_state == RESPONSE_WAIT_ACK){
|
||||||
|
if(!_sendContentLength || _ackedLength >= _writtenLength){
|
||||||
|
_state = RESPONSE_END;
|
||||||
|
if(!_chunked && !_sendContentLength)
|
||||||
|
request->client()->close(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const size_t len)
|
||||||
|
{
|
||||||
|
// If we have something in cache, copy it to buffer
|
||||||
|
const size_t readFromCache = std::min(len, _cache.size());
|
||||||
|
if(readFromCache) {
|
||||||
|
memcpy(data, _cache.data(), readFromCache);
|
||||||
|
_cache.erase(_cache.begin(), _cache.begin() + readFromCache);
|
||||||
|
}
|
||||||
|
// If we need to read more...
|
||||||
|
const size_t needFromFile = len - readFromCache;
|
||||||
|
const size_t readFromContent = _fillBuffer(data + readFromCache, needFromFile);
|
||||||
|
return readFromCache + readFromContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len)
|
||||||
|
{
|
||||||
|
if(!_callback)
|
||||||
|
return _fillBuffer(data, len);
|
||||||
|
|
||||||
|
const size_t originalLen = len;
|
||||||
|
len = _readDataFromCacheOrContent(data, len);
|
||||||
|
// Now we've read 'len' bytes, either from cache or from file
|
||||||
|
// Search for template placeholders
|
||||||
|
uint8_t* pTemplateStart = data;
|
||||||
|
while((pTemplateStart < &data[len]) && (pTemplateStart = (uint8_t*)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1]
|
||||||
|
uint8_t* pTemplateEnd = (pTemplateStart < &data[len - 1]) ? (uint8_t*)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr;
|
||||||
|
// temporary buffer to hold parameter name
|
||||||
|
uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1];
|
||||||
|
String paramName;
|
||||||
|
// If closing placeholder is found:
|
||||||
|
if(pTemplateEnd) {
|
||||||
|
// prepare argument to callback
|
||||||
|
const size_t paramNameLength = std::min(sizeof(buf) - 1, (unsigned int)(pTemplateEnd - pTemplateStart - 1));
|
||||||
|
if(paramNameLength) {
|
||||||
|
memcpy(buf, pTemplateStart + 1, paramNameLength);
|
||||||
|
buf[paramNameLength] = 0;
|
||||||
|
paramName = String(reinterpret_cast<char*>(buf));
|
||||||
|
} else { // double percent sign encountered, this is single percent sign escaped.
|
||||||
|
// remove the 2nd percent sign
|
||||||
|
memmove(pTemplateEnd, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1);
|
||||||
|
len += _readDataFromCacheOrContent(&data[len - 1], 1) - 1;
|
||||||
|
++pTemplateStart;
|
||||||
|
}
|
||||||
|
} else if(&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data
|
||||||
|
memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart);
|
||||||
|
const size_t readFromCacheOrContent = _readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1));
|
||||||
|
if(readFromCacheOrContent) {
|
||||||
|
pTemplateEnd = (uint8_t*)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent);
|
||||||
|
if(pTemplateEnd) {
|
||||||
|
// prepare argument to callback
|
||||||
|
*pTemplateEnd = 0;
|
||||||
|
paramName = String(reinterpret_cast<char*>(buf));
|
||||||
|
// Copy remaining read-ahead data into cache
|
||||||
|
_cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
||||||
|
pTemplateEnd = &data[len - 1];
|
||||||
|
}
|
||||||
|
else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
|
||||||
|
{
|
||||||
|
// but first, store read file data in cache
|
||||||
|
_cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
||||||
|
++pTemplateStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
|
||||||
|
++pTemplateStart;
|
||||||
|
}
|
||||||
|
else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
|
||||||
|
++pTemplateStart;
|
||||||
|
if(paramName.length()) {
|
||||||
|
// call callback and replace with result.
|
||||||
|
// Everything in range [pTemplateStart, pTemplateEnd] can be safely replaced with parameter value.
|
||||||
|
// Data after pTemplateEnd may need to be moved.
|
||||||
|
// The first byte of data after placeholder is located at pTemplateEnd + 1.
|
||||||
|
// It should be located at pTemplateStart + numBytesCopied (to begin right after inserted parameter value).
|
||||||
|
const String paramValue(_callback(paramName));
|
||||||
|
const char* pvstr = paramValue.c_str();
|
||||||
|
const unsigned int pvlen = paramValue.length();
|
||||||
|
const size_t numBytesCopied = std::min(pvlen, static_cast<unsigned int>(&data[originalLen - 1] - pTemplateStart + 1));
|
||||||
|
// make room for param value
|
||||||
|
// 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store
|
||||||
|
if((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) {
|
||||||
|
_cache.insert(_cache.begin(), &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]);
|
||||||
|
//2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end
|
||||||
|
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied);
|
||||||
|
len = originalLen; // fix issue with truncated data, not sure if it has any side effects
|
||||||
|
} else if(pTemplateEnd + 1 != pTemplateStart + numBytesCopied)
|
||||||
|
//2. Either parameter value is shorter than placeholder text OR there is enough free space in buffer to fit.
|
||||||
|
// Move the entire data after the placeholder
|
||||||
|
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1);
|
||||||
|
// 3. replace placeholder with actual value
|
||||||
|
memcpy(pTemplateStart, pvstr, numBytesCopied);
|
||||||
|
// If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer)
|
||||||
|
if(numBytesCopied < pvlen) {
|
||||||
|
_cache.insert(_cache.begin(), pvstr + numBytesCopied, pvstr + pvlen);
|
||||||
|
} else if(pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text...
|
||||||
|
// there is some free room, fill it from cache
|
||||||
|
const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied;
|
||||||
|
const size_t totalFreeRoom = originalLen - len + roomFreed;
|
||||||
|
len += _readDataFromCacheOrContent(&data[len - roomFreed], totalFreeRoom) - roomFreed;
|
||||||
|
} else { // result is copied fully; it is longer than placeholder text
|
||||||
|
const size_t roomTaken = pTemplateStart + numBytesCopied - pTemplateEnd - 1;
|
||||||
|
len = std::min(len + roomTaken, originalLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // while(pTemplateStart)
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncFileResponse::~AsyncFileResponse(){
|
||||||
|
if(_content)
|
||||||
|
_content.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncFileResponse::_setContentType(const String& path){
|
||||||
|
if (path.endsWith(".html")) _contentType = "text/html";
|
||||||
|
else if (path.endsWith(".htm")) _contentType = "text/html";
|
||||||
|
else if (path.endsWith(".css")) _contentType = "text/css";
|
||||||
|
else if (path.endsWith(".json")) _contentType = "application/json";
|
||||||
|
else if (path.endsWith(".js")) _contentType = "application/javascript";
|
||||||
|
else if (path.endsWith(".png")) _contentType = "image/png";
|
||||||
|
else if (path.endsWith(".gif")) _contentType = "image/gif";
|
||||||
|
else if (path.endsWith(".jpg")) _contentType = "image/jpeg";
|
||||||
|
else if (path.endsWith(".ico")) _contentType = "image/x-icon";
|
||||||
|
else if (path.endsWith(".svg")) _contentType = "image/svg+xml";
|
||||||
|
else if (path.endsWith(".eot")) _contentType = "font/eot";
|
||||||
|
else if (path.endsWith(".woff")) _contentType = "font/woff";
|
||||||
|
else if (path.endsWith(".woff2")) _contentType = "font/woff2";
|
||||||
|
else if (path.endsWith(".ttf")) _contentType = "font/ttf";
|
||||||
|
else if (path.endsWith(".xml")) _contentType = "text/xml";
|
||||||
|
else if (path.endsWith(".pdf")) _contentType = "application/pdf";
|
||||||
|
else if (path.endsWith(".zip")) _contentType = "application/zip";
|
||||||
|
else if(path.endsWith(".gz")) _contentType = "application/x-gzip";
|
||||||
|
else _contentType = "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){
|
||||||
|
_code = 200;
|
||||||
|
_path = path;
|
||||||
|
|
||||||
|
if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){
|
||||||
|
_path = _path+".gz";
|
||||||
|
addHeader("Content-Encoding", "gzip");
|
||||||
|
_callback = nullptr; // Unable to process zipped templates
|
||||||
|
_sendContentLength = true;
|
||||||
|
_chunked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_content = fs.open(_path, "r");
|
||||||
|
_contentLength = _content.size();
|
||||||
|
|
||||||
|
if(contentType == "")
|
||||||
|
_setContentType(path);
|
||||||
|
else
|
||||||
|
_contentType = contentType;
|
||||||
|
|
||||||
|
int filenameStart = path.lastIndexOf('/') + 1;
|
||||||
|
char buf[26+path.length()-filenameStart];
|
||||||
|
char* filename = (char*)path.c_str() + filenameStart;
|
||||||
|
|
||||||
|
if(download) {
|
||||||
|
// set filename and force download
|
||||||
|
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename);
|
||||||
|
} else {
|
||||||
|
// set filename and force rendering
|
||||||
|
snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename);
|
||||||
|
}
|
||||||
|
addHeader("Content-Disposition", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){
|
||||||
|
_code = 200;
|
||||||
|
_path = path;
|
||||||
|
|
||||||
|
if(!download && String(content.name()).endsWith(".gz") && !path.endsWith(".gz")){
|
||||||
|
addHeader("Content-Encoding", "gzip");
|
||||||
|
_callback = nullptr; // Unable to process gzipped templates
|
||||||
|
_sendContentLength = true;
|
||||||
|
_chunked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_content = content;
|
||||||
|
_contentLength = _content.size();
|
||||||
|
|
||||||
|
if(contentType == "")
|
||||||
|
_setContentType(path);
|
||||||
|
else
|
||||||
|
_contentType = contentType;
|
||||||
|
|
||||||
|
int filenameStart = path.lastIndexOf('/') + 1;
|
||||||
|
char buf[26+path.length()-filenameStart];
|
||||||
|
char* filename = (char*)path.c_str() + filenameStart;
|
||||||
|
|
||||||
|
if(download) {
|
||||||
|
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename);
|
||||||
|
}
|
||||||
|
addHeader("Content-Disposition", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
return _content.read(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stream Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncStreamResponse::AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) {
|
||||||
|
_code = 200;
|
||||||
|
_content = &stream;
|
||||||
|
_contentLength = len;
|
||||||
|
_contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
size_t available = _content->available();
|
||||||
|
size_t outLen = (available > len)?len:available;
|
||||||
|
size_t i;
|
||||||
|
for(i=0;i<outLen;i++)
|
||||||
|
data[i] = _content->read();
|
||||||
|
return outLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback): AsyncAbstractResponse(templateCallback) {
|
||||||
|
_code = 200;
|
||||||
|
_content = callback;
|
||||||
|
_contentLength = len;
|
||||||
|
if(!len)
|
||||||
|
_sendContentLength = false;
|
||||||
|
_contentType = contentType;
|
||||||
|
_filledLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
size_t ret = _content(data, len, _filledLength);
|
||||||
|
if(ret != RESPONSE_TRY_AGAIN){
|
||||||
|
_filledLength += ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chunked Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback): AsyncAbstractResponse(processorCallback) {
|
||||||
|
_code = 200;
|
||||||
|
_content = callback;
|
||||||
|
_contentLength = 0;
|
||||||
|
_contentType = contentType;
|
||||||
|
_sendContentLength = false;
|
||||||
|
_chunked = true;
|
||||||
|
_filledLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
size_t ret = _content(data, len, _filledLength);
|
||||||
|
if(ret != RESPONSE_TRY_AGAIN){
|
||||||
|
_filledLength += ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Progmem Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) {
|
||||||
|
_code = code;
|
||||||
|
_content = content;
|
||||||
|
_contentType = contentType;
|
||||||
|
_contentLength = len;
|
||||||
|
_readLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
size_t left = _contentLength - _readLength;
|
||||||
|
if (left > len) {
|
||||||
|
memcpy_P(data, _content + _readLength, len);
|
||||||
|
_readLength += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
memcpy_P(data, _content + _readLength, left);
|
||||||
|
_readLength += left;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Response Stream (You can print/write/printf to it, up to the contentLen bytes)
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize){
|
||||||
|
_code = 200;
|
||||||
|
_contentLength = 0;
|
||||||
|
_contentType = contentType;
|
||||||
|
_content = new cbuf(bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncResponseStream::~AsyncResponseStream(){
|
||||||
|
delete _content;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){
|
||||||
|
return _content->read((char*)buf, maxLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncResponseStream::write(const uint8_t *data, size_t len){
|
||||||
|
if(_started())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(len > _content->room()){
|
||||||
|
size_t needed = len - _content->room();
|
||||||
|
_content->resizeAdd(needed);
|
||||||
|
}
|
||||||
|
size_t written = _content->write((const char*)data, len);
|
||||||
|
_contentLength += written;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncResponseStream::write(uint8_t data){
|
||||||
|
return write(&data, 1);
|
||||||
|
}
|
||||||
193
lib/ESPAsyncWebServer/src/WebServer.cpp
Normal file
193
lib/ESPAsyncWebServer/src/WebServer.cpp
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
Asynchronous WebServer library for Espressif MCUs
|
||||||
|
|
||||||
|
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
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 "ESPAsyncWebServer.h"
|
||||||
|
#include "WebHandlerImpl.h"
|
||||||
|
|
||||||
|
bool ON_STA_FILTER(AsyncWebServerRequest *request) {
|
||||||
|
return WiFi.localIP() == request->client()->localIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ON_AP_FILTER(AsyncWebServerRequest *request) {
|
||||||
|
return WiFi.localIP() != request->client()->localIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AsyncWebServer::AsyncWebServer(uint16_t port)
|
||||||
|
: _server(port)
|
||||||
|
, _rewrites(LinkedList<AsyncWebRewrite*>([](AsyncWebRewrite* r){ delete r; }))
|
||||||
|
, _handlers(LinkedList<AsyncWebHandler*>([](AsyncWebHandler* h){ delete h; }))
|
||||||
|
{
|
||||||
|
_catchAllHandler = new AsyncCallbackWebHandler();
|
||||||
|
if(_catchAllHandler == NULL)
|
||||||
|
return;
|
||||||
|
_server.onClient([](void *s, AsyncClient* c){
|
||||||
|
if(c == NULL)
|
||||||
|
return;
|
||||||
|
c->setRxTimeout(3);
|
||||||
|
AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c);
|
||||||
|
if(r == NULL){
|
||||||
|
c->close(true);
|
||||||
|
c->free();
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServer::~AsyncWebServer(){
|
||||||
|
reset();
|
||||||
|
end();
|
||||||
|
if(_catchAllHandler) delete _catchAllHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite){
|
||||||
|
_rewrites.add(rewrite);
|
||||||
|
return *rewrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncWebServer::removeRewrite(AsyncWebRewrite *rewrite){
|
||||||
|
return _rewrites.remove(rewrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to){
|
||||||
|
return addRewrite(new AsyncWebRewrite(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler){
|
||||||
|
_handlers.add(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){
|
||||||
|
return _handlers.remove(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::begin(){
|
||||||
|
_server.setNoDelay(true);
|
||||||
|
_server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::end(){
|
||||||
|
_server.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg){
|
||||||
|
_server.onSslFileRequest(cb, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::beginSecure(const char *cert, const char *key, const char *password){
|
||||||
|
_server.beginSecure(cert, key, password);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){
|
||||||
|
delete request;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){
|
||||||
|
for(const auto& r: _rewrites){
|
||||||
|
if (r->match(request)){
|
||||||
|
request->_url = r->toUrl();
|
||||||
|
request->_addGetParams(r->params());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){
|
||||||
|
for(const auto& h: _handlers){
|
||||||
|
if (h->filter(request) && h->canHandle(request)){
|
||||||
|
request->setHandler(h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request->addInterestingHeader("ANY");
|
||||||
|
request->setHandler(_catchAllHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){
|
||||||
|
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
|
||||||
|
handler->setUri(uri);
|
||||||
|
handler->setMethod(method);
|
||||||
|
handler->onRequest(onRequest);
|
||||||
|
handler->onUpload(onUpload);
|
||||||
|
handler->onBody(onBody);
|
||||||
|
addHandler(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){
|
||||||
|
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
|
||||||
|
handler->setUri(uri);
|
||||||
|
handler->setMethod(method);
|
||||||
|
handler->onRequest(onRequest);
|
||||||
|
handler->onUpload(onUpload);
|
||||||
|
addHandler(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){
|
||||||
|
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
|
||||||
|
handler->setUri(uri);
|
||||||
|
handler->setMethod(method);
|
||||||
|
handler->onRequest(onRequest);
|
||||||
|
addHandler(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){
|
||||||
|
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
|
||||||
|
handler->setUri(uri);
|
||||||
|
handler->onRequest(onRequest);
|
||||||
|
addHandler(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control){
|
||||||
|
AsyncStaticWebHandler* handler = new AsyncStaticWebHandler(uri, fs, path, cache_control);
|
||||||
|
addHandler(handler);
|
||||||
|
return *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){
|
||||||
|
_catchAllHandler->onRequest(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn){
|
||||||
|
_catchAllHandler->onUpload(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn){
|
||||||
|
_catchAllHandler->onBody(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServer::reset(){
|
||||||
|
_rewrites.free();
|
||||||
|
_handlers.free();
|
||||||
|
|
||||||
|
if (_catchAllHandler != NULL){
|
||||||
|
_catchAllHandler->onRequest(NULL);
|
||||||
|
_catchAllHandler->onUpload(NULL);
|
||||||
|
_catchAllHandler->onBody(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
627
lib/ESPAsyncWebServer/src/edit.htm
Normal file
627
lib/ESPAsyncWebServer/src/edit.htm
Normal file
@@ -0,0 +1,627 @@
|
|||||||
|
<!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>ESP Editor</title>
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
.cm {
|
||||||
|
z-index: 300;
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
border: 1px solid #444;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
display: none;
|
||||||
|
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
.cm ul {
|
||||||
|
list-style: none;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cm li {
|
||||||
|
position: relative;
|
||||||
|
min-width: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cm span {
|
||||||
|
color: #444;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
.cm li:hover { background: #444; }
|
||||||
|
.cm li:hover span { color: #EEE; }
|
||||||
|
.tvu ul, .tvu li {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.tvu input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.tvu {
|
||||||
|
font: normal 12px Verdana, Arial, Sans-serif;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
color: #444;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.tvu span {
|
||||||
|
margin-bottom:5px;
|
||||||
|
padding: 0 0 0 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
height: 16px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC') no-repeat;
|
||||||
|
background-position: 0px 0px;
|
||||||
|
}
|
||||||
|
.tvu span:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0){
|
||||||
|
.tvu{
|
||||||
|
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes webkit-adjacent-element-selector-bugfix {
|
||||||
|
from {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#uploader {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height:28px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding-left: 10px;
|
||||||
|
background-color: #444;
|
||||||
|
color:#EEE;
|
||||||
|
}
|
||||||
|
#tree {
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width:160px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
#editor, #preview {
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 160px;
|
||||||
|
border-left:1px solid #EEE;
|
||||||
|
}
|
||||||
|
#preview {
|
||||||
|
background-color: #EEE;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
#loader {
|
||||||
|
position: absolute;
|
||||||
|
top: 36%;
|
||||||
|
right: 40%;
|
||||||
|
}
|
||||||
|
.loader {
|
||||||
|
z-index: 10000;
|
||||||
|
border: 8px solid #b5b5b5; /* Grey */
|
||||||
|
border-top: 8px solid #3498db; /* Blue */
|
||||||
|
border-bottom: 8px solid #3498db; /* Blue */
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 240px;
|
||||||
|
height: 240px;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
if (typeof XMLHttpRequest === "undefined") {
|
||||||
|
XMLHttpRequest = function () {
|
||||||
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
|
||||||
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
|
||||||
|
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
|
||||||
|
throw new Error("This browser does not support XMLHttpRequest.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function ge(a){
|
||||||
|
return document.getElementById(a);
|
||||||
|
}
|
||||||
|
function ce(a){
|
||||||
|
return document.createElement(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortByKey(array, key) {
|
||||||
|
return array.sort(function(a, b) {
|
||||||
|
var x = a[key]; var y = b[key];
|
||||||
|
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var QueuedRequester = function () {
|
||||||
|
this.queue = [];
|
||||||
|
this.running = false;
|
||||||
|
this.xmlhttp = null;
|
||||||
|
}
|
||||||
|
QueuedRequester.prototype = {
|
||||||
|
_request: function(req){
|
||||||
|
this.running = true;
|
||||||
|
if(!req instanceof Object) return;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function ajaxCb(x,d){ return function(){
|
||||||
|
if (x.readyState == 4){
|
||||||
|
ge("loader").style.display = "none";
|
||||||
|
d.callback(x.status, x.responseText);
|
||||||
|
if(that.queue.length === 0) that.running = false;
|
||||||
|
if(that.running) that._request(that.queue.shift());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
ge("loader").style.display = "block";
|
||||||
|
|
||||||
|
var p = "";
|
||||||
|
if(req.params instanceof FormData){
|
||||||
|
p = req.params;
|
||||||
|
} else if(req.params instanceof Object){
|
||||||
|
for (var key in req.params) {
|
||||||
|
if(p === "")
|
||||||
|
p += (req.method === "GET")?"?":"";
|
||||||
|
else
|
||||||
|
p += "&";
|
||||||
|
p += encodeURIComponent(key)+"="+encodeURIComponent(req.params[key]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.xmlhttp = new XMLHttpRequest();
|
||||||
|
this.xmlhttp.onreadystatechange = ajaxCb(this.xmlhttp, req);
|
||||||
|
if(req.method === "GET"){
|
||||||
|
this.xmlhttp.open(req.method, req.url+p, true);
|
||||||
|
this.xmlhttp.send();
|
||||||
|
} else {
|
||||||
|
this.xmlhttp.open(req.method, req.url, true);
|
||||||
|
if(p instanceof String)
|
||||||
|
this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
this.xmlhttp.send(p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stop: function(){
|
||||||
|
if(this.running) this.running = false;
|
||||||
|
if(this.xmlhttp && this.xmlhttp.readyState < 4){
|
||||||
|
this.xmlhttp.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
add: function(method, url, params, callback){
|
||||||
|
this.queue.push({url:url,method:method,params:params,callback:callback});
|
||||||
|
if(!this.running){
|
||||||
|
this._request(this.queue.shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var requests = new QueuedRequester();
|
||||||
|
|
||||||
|
function createFileUploader(element, tree, editor){
|
||||||
|
var xmlHttp;
|
||||||
|
|
||||||
|
var refresh = ce("button");
|
||||||
|
refresh.innerHTML = 'Refresh List';
|
||||||
|
ge(element).appendChild(refresh);
|
||||||
|
|
||||||
|
var input = ce("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.multiple = false;
|
||||||
|
input.name = "data";
|
||||||
|
input.id="upload-select";
|
||||||
|
ge(element).appendChild(input);
|
||||||
|
|
||||||
|
var path = ce("input");
|
||||||
|
path.id = "upload-path";
|
||||||
|
path.type = "text";
|
||||||
|
path.name = "path";
|
||||||
|
path.defaultValue = "/";
|
||||||
|
ge(element).appendChild(path);
|
||||||
|
|
||||||
|
var button = ce("button");
|
||||||
|
button.innerHTML = 'Upload';
|
||||||
|
ge(element).appendChild(button);
|
||||||
|
|
||||||
|
var mkfile = ce("button");
|
||||||
|
mkfile.innerHTML = 'Create';
|
||||||
|
ge(element).appendChild(mkfile);
|
||||||
|
|
||||||
|
var filename = ce("input");
|
||||||
|
filename.id = "editor-filename";
|
||||||
|
filename.type = "text";
|
||||||
|
filename.disabled= true;
|
||||||
|
filename.size = 20;
|
||||||
|
ge(element).appendChild(filename);
|
||||||
|
|
||||||
|
var savefile = ce("button");
|
||||||
|
savefile.innerHTML = ' Save ' ;
|
||||||
|
ge(element).appendChild(savefile);
|
||||||
|
|
||||||
|
function httpPostProcessRequest(status, responseText){
|
||||||
|
if(status != 200)
|
||||||
|
alert("ERROR["+status+"]: "+responseText);
|
||||||
|
else
|
||||||
|
tree.refreshPath(path.value);
|
||||||
|
}
|
||||||
|
function createPath(p){
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("path", p);
|
||||||
|
requests.add("PUT", "/edit", formData, httpPostProcessRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
mkfile.onclick = function(e){
|
||||||
|
createPath(path.value);
|
||||||
|
editor.loadUrl(path.value);
|
||||||
|
path.value="/";
|
||||||
|
};
|
||||||
|
|
||||||
|
savefile.onclick = function(e){
|
||||||
|
editor.execCommand('saveCommand');
|
||||||
|
};
|
||||||
|
|
||||||
|
refresh.onclick = function(e){
|
||||||
|
tree.refreshPath(path.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
button.onclick = function(e){
|
||||||
|
if(input.files.length === 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("data", input.files[0], path.value);
|
||||||
|
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||||
|
var uploadPath= ge("upload-path");
|
||||||
|
uploadPath.value="/";
|
||||||
|
var uploadSelect= ge("upload-select");
|
||||||
|
uploadSelect.value="";
|
||||||
|
};
|
||||||
|
input.onchange = function(e){
|
||||||
|
if(input.files.length === 0) return;
|
||||||
|
var filename = input.files[0].name;
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||||
|
var name = /(.*)\.[^.]+$/.exec(filename)[1];
|
||||||
|
if(typeof name !== undefined){
|
||||||
|
filename = name;
|
||||||
|
}
|
||||||
|
path.value = "/"+filename+"."+ext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTree(element, editor){
|
||||||
|
var preview = ge("preview");
|
||||||
|
var treeRoot = ce("div");
|
||||||
|
treeRoot.className = "tvu";
|
||||||
|
ge(element).appendChild(treeRoot);
|
||||||
|
|
||||||
|
function loadDownload(path){
|
||||||
|
ge('download-frame').src = "/edit?download="+path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPreview(path){
|
||||||
|
var edfname = ge("editor-filename");
|
||||||
|
edfname.value=path;
|
||||||
|
ge("editor").style.display = "none";
|
||||||
|
preview.style.display = "block";
|
||||||
|
preview.innerHTML = '<img src="/edit?edit='+path+'&_cb='+Date.now()+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillFileMenu(el, path){
|
||||||
|
var list = ce("ul");
|
||||||
|
el.appendChild(list);
|
||||||
|
var action = ce("li");
|
||||||
|
list.appendChild(action);
|
||||||
|
if(isImageFile(path)){
|
||||||
|
action.innerHTML = "<span>Preview</span>";
|
||||||
|
action.onclick = function(e){
|
||||||
|
loadPreview(path);
|
||||||
|
if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
} else if(isTextFile(path)){
|
||||||
|
action.innerHTML = "<span>Edit</span>";
|
||||||
|
action.onclick = function(e){
|
||||||
|
editor.loadUrl(path);
|
||||||
|
if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var download = ce("li");
|
||||||
|
list.appendChild(download);
|
||||||
|
download.innerHTML = "<span>Download</span>";
|
||||||
|
download.onclick = function(e){
|
||||||
|
loadDownload(path);
|
||||||
|
if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
var delFile = ce("li");
|
||||||
|
list.appendChild(delFile);
|
||||||
|
delFile.innerHTML = "<span>Delete</span>";
|
||||||
|
delFile.onclick = function(e){
|
||||||
|
httpDelete(path);
|
||||||
|
if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function showContextMenu(event, path, isfile){
|
||||||
|
var divContext = ce("div");
|
||||||
|
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
|
||||||
|
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
|
||||||
|
var left = event.clientX + scrollLeft;
|
||||||
|
var top = event.clientY + scrollTop;
|
||||||
|
divContext.className = 'cm';
|
||||||
|
divContext.style.display = 'block';
|
||||||
|
divContext.style.left = left + 'px';
|
||||||
|
divContext.style.top = top + 'px';
|
||||||
|
fillFileMenu(divContext, path);
|
||||||
|
document.body.appendChild(divContext);
|
||||||
|
var width = divContext.offsetWidth;
|
||||||
|
var height = divContext.offsetHeight;
|
||||||
|
divContext.onmouseout = function(e){
|
||||||
|
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
|
||||||
|
if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(divContext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTreeLeaf(path, name, size){
|
||||||
|
var leaf = ce("li");
|
||||||
|
leaf.id = name;
|
||||||
|
var label = ce("span");
|
||||||
|
label.innerHTML = name;
|
||||||
|
leaf.appendChild(label);
|
||||||
|
leaf.onclick = function(e){
|
||||||
|
if(isTextFile(leaf.id.toLowerCase())){
|
||||||
|
editor.loadUrl(leaf.id);
|
||||||
|
} else if(isImageFile(leaf.id.toLowerCase())){
|
||||||
|
loadPreview(leaf.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
leaf.oncontextmenu = function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
showContextMenu(e, leaf.id, true);
|
||||||
|
};
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addList(parent, path, items){
|
||||||
|
sortByKey(items, 'name');
|
||||||
|
var list = ce("ul");
|
||||||
|
parent.appendChild(list);
|
||||||
|
var ll = items.length;
|
||||||
|
for(var i = 0; i < ll; i++){
|
||||||
|
if(items[i].type === "file")
|
||||||
|
list.appendChild(createTreeLeaf(path, items[i].name, items[i].size));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTextFile(path){
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "txt":
|
||||||
|
case "htm":
|
||||||
|
case "html":
|
||||||
|
case "js":
|
||||||
|
case "css":
|
||||||
|
case "xml":
|
||||||
|
case "json":
|
||||||
|
case "conf":
|
||||||
|
case "ini":
|
||||||
|
case "h":
|
||||||
|
case "c":
|
||||||
|
case "cpp":
|
||||||
|
case "php":
|
||||||
|
case "hex":
|
||||||
|
case "ino":
|
||||||
|
case "pde":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isImageFile(path){
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "png":
|
||||||
|
case "jpg":
|
||||||
|
case "gif":
|
||||||
|
case "bmp":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshPath = function(path){
|
||||||
|
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
};
|
||||||
|
|
||||||
|
function delCb(path){
|
||||||
|
return function(status, responseText){
|
||||||
|
if(status != 200){
|
||||||
|
alert("ERROR["+status+"]: "+responseText);
|
||||||
|
} else {
|
||||||
|
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpDelete(filename){
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("path", filename);
|
||||||
|
requests.add("DELETE", "/edit", formData, delCb(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCb(parent, path){
|
||||||
|
return function(status, responseText){
|
||||||
|
if(status == 200)
|
||||||
|
addList(parent, path, JSON.parse(responseText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpGet(parent, path){
|
||||||
|
requests.add("GET", "/edit", { list: path }, getCb(parent, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditor(element, file, lang, theme, type){
|
||||||
|
function getLangFromFilename(filename){
|
||||||
|
var lang = "plain";
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "txt": lang = "plain"; break;
|
||||||
|
case "hex": lang = "plain"; break;
|
||||||
|
case "conf": lang = "plain"; break;
|
||||||
|
case "htm": lang = "html"; break;
|
||||||
|
case "js": lang = "javascript"; break;
|
||||||
|
case "h": lang = "c_cpp"; break;
|
||||||
|
case "c": lang = "c_cpp"; break;
|
||||||
|
case "cpp": lang = "c_cpp"; break;
|
||||||
|
case "css":
|
||||||
|
case "scss":
|
||||||
|
case "php":
|
||||||
|
case "html":
|
||||||
|
case "json":
|
||||||
|
case "xml":
|
||||||
|
case "ini": lang = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof file === "undefined") file = "/index.html";
|
||||||
|
|
||||||
|
if(typeof lang === "undefined"){
|
||||||
|
lang = getLangFromFilename(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof theme === "undefined") theme = "textmate";
|
||||||
|
|
||||||
|
if(typeof type === "undefined"){
|
||||||
|
type = "text/"+lang;
|
||||||
|
if(lang === "c_cpp") type = "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
var editor = ace.edit(element);
|
||||||
|
function httpPostProcessRequest(status, responseText){
|
||||||
|
if(status != 200) alert("ERROR["+status+"]: "+responseText);
|
||||||
|
}
|
||||||
|
function httpPost(filename, data, type){
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("data", new Blob([data], { type: type }), filename);
|
||||||
|
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||||
|
}
|
||||||
|
function httpGetProcessRequest(status, responseText){
|
||||||
|
ge("preview").style.display = "none";
|
||||||
|
ge("editor").style.display = "block";
|
||||||
|
if(status == 200)
|
||||||
|
editor.setValue(responseText);
|
||||||
|
else
|
||||||
|
editor.setValue("");
|
||||||
|
editor.clearSelection();
|
||||||
|
}
|
||||||
|
function httpGet(theUrl){
|
||||||
|
requests.add("GET", "/edit", { edit: theUrl }, httpGetProcessRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
||||||
|
editor.setTheme("ace/theme/"+theme);
|
||||||
|
editor.$blockScrolling = Infinity;
|
||||||
|
editor.getSession().setUseSoftTabs(true);
|
||||||
|
editor.getSession().setTabSize(2);
|
||||||
|
editor.setHighlightActiveLine(true);
|
||||||
|
editor.setShowPrintMargin(false);
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'saveCommand',
|
||||||
|
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
||||||
|
exec: function(editor) {
|
||||||
|
httpPost(file, editor.getValue()+"", type);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'undoCommand',
|
||||||
|
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
|
||||||
|
exec: function(editor) {
|
||||||
|
editor.getSession().getUndoManager().undo(false);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'redoCommand',
|
||||||
|
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
|
||||||
|
exec: function(editor) {
|
||||||
|
editor.getSession().getUndoManager().redo(false);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
editor.loadUrl = function(filename){
|
||||||
|
var edfname = ge("editor-filename");
|
||||||
|
edfname.value=filename;
|
||||||
|
file = filename;
|
||||||
|
lang = getLangFromFilename(file);
|
||||||
|
type = "text/"+lang;
|
||||||
|
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
||||||
|
httpGet(file);
|
||||||
|
};
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
function onBodyLoad(){
|
||||||
|
var vars = {};
|
||||||
|
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
|
||||||
|
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
|
||||||
|
var tree = createTree("tree", editor);
|
||||||
|
createFileUploader("uploader", tree, editor);
|
||||||
|
if(typeof vars.file === "undefined") vars.file = "/index.htm";
|
||||||
|
editor.loadUrl(vars.file);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script>
|
||||||
|
if (typeof ace.edit == "undefined") {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = "/ace.js";
|
||||||
|
script.async = false;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="onBodyLoad();">
|
||||||
|
<div id="loader" class="loader"></div>
|
||||||
|
<div id="uploader"></div>
|
||||||
|
<div id="tree"></div>
|
||||||
|
<div id="editor"></div>
|
||||||
|
<div id="preview" style="display:none;"></div>
|
||||||
|
<iframe id=download-frame style='display:none;'></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -8,26 +8,45 @@
|
|||||||
; Please visit documentation for the other options and examples
|
; Please visit documentation for the other options and examples
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[platformio]
|
||||||
|
default_envs = esp8266
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
lib_deps=
|
framework = arduino
|
||||||
ModuleInterface@3.5.1
|
|
||||||
ArduinoJson@5.*
|
|
||||||
AsyncTCP
|
|
||||||
ESP Async WebServer
|
|
||||||
ESP32Servo
|
|
||||||
Bounce2
|
|
||||||
PubSubClient
|
|
||||||
ESP8266-StringCommand
|
|
||||||
DallasTemperature
|
|
||||||
DHT sensor library for ESPx
|
|
||||||
Adafruit BMP280 Library
|
|
||||||
Adafruit BME280 Library
|
|
||||||
|
|
||||||
board_build.partitions = partitions_custom.csv
|
[env:esp32]
|
||||||
|
|
||||||
[env:esp32dev]
|
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
board_build.partitions = partitions_custom.csv
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
lib_deps =
|
||||||
|
ModuleInterface@3.5.1
|
||||||
|
ArduinoJson@5.*
|
||||||
|
AsyncTCP
|
||||||
|
ESP32Servo
|
||||||
|
Bounce2
|
||||||
|
PubSubClient
|
||||||
|
ESP8266-StringCommand
|
||||||
|
DallasTemperature
|
||||||
|
DHT sensor library for ESPx
|
||||||
|
Adafruit BMP280 Library
|
||||||
|
Adafruit BME280 Library
|
||||||
|
|
||||||
|
[env:esp8266]
|
||||||
|
build_flags =-Wno-deprecated
|
||||||
|
platform = espressif8266
|
||||||
|
board = nodemcuv2
|
||||||
|
monitor_filters = esp8266_exception_decoder
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_deps =
|
||||||
|
ModuleInterface@3.5.1
|
||||||
|
ArduinoJson@5.*
|
||||||
|
ESPAsyncTCP
|
||||||
|
Bounce2
|
||||||
|
PubSubClient
|
||||||
|
ESP8266-StringCommand
|
||||||
|
DallasTemperature
|
||||||
|
DHT sensor library for ESPx
|
||||||
|
Adafruit BMP280 Library
|
||||||
|
Adafruit BME280 Library
|
||||||
|
|||||||
763
src/Cmd.cpp
763
src/Cmd.cpp
@@ -1,412 +1,405 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
#include "push_pushingbox.h"
|
Servo myServo1;
|
||||||
|
Servo myServo2;
|
||||||
|
|
||||||
|
boolean but[NUM_BUTTONS];
|
||||||
|
Bounce *buttons;
|
||||||
|
|
||||||
void CMD_init() {
|
void CMD_init() {
|
||||||
|
sCmd.addCommand("button", button);
|
||||||
|
sCmd.addCommand("buttonSet", buttonSet);
|
||||||
|
sCmd.addCommand("buttonChange", buttonChange);
|
||||||
|
|
||||||
sCmd.addCommand("button", button);
|
sCmd.addCommand("pinSet", pinSet);
|
||||||
sCmd.addCommand("buttonSet", buttonSet);
|
sCmd.addCommand("pinChange", pinChange);
|
||||||
sCmd.addCommand("buttonChange", buttonChange);
|
|
||||||
|
|
||||||
sCmd.addCommand("pinSet", pinSet);
|
sCmd.addCommand("pwm", pwm);
|
||||||
sCmd.addCommand("pinChange", pinChange);
|
sCmd.addCommand("pwmSet", pwmSet);
|
||||||
|
|
||||||
sCmd.addCommand("pwm", pwm);
|
sCmd.addCommand("switch", switch_);
|
||||||
sCmd.addCommand("pwmSet", pwmSet);
|
|
||||||
|
|
||||||
sCmd.addCommand("switch", switch_);
|
|
||||||
|
|
||||||
#ifdef analog_enable
|
#ifdef analog_enable
|
||||||
sCmd.addCommand("analog", analog);
|
sCmd.addCommand("analog", analog);
|
||||||
#endif
|
#endif
|
||||||
#ifdef level_enable
|
#ifdef level_enable
|
||||||
sCmd.addCommand("levelPr", levelPr);
|
sCmd.addCommand("levelPr", levelPr);
|
||||||
sCmd.addCommand("ultrasonicCm", ultrasonicCm);
|
sCmd.addCommand("ultrasonicCm", ultrasonicCm);
|
||||||
#endif
|
#endif
|
||||||
#ifdef dallas_enable
|
#ifdef dallas_enable
|
||||||
sCmd.addCommand("dallas", dallas);
|
sCmd.addCommand("dallas", dallas);
|
||||||
#endif
|
#endif
|
||||||
#ifdef dht_enable
|
#ifdef dht_enable
|
||||||
sCmd.addCommand("dhtT", dhtT);
|
sCmd.addCommand("dhtT", dhtT);
|
||||||
sCmd.addCommand("dhtH", dhtH);
|
sCmd.addCommand("dhtH", dhtH);
|
||||||
sCmd.addCommand("dhtPerception", dhtP);
|
sCmd.addCommand("dhtPerception", dhtP);
|
||||||
sCmd.addCommand("dhtComfort", dhtC);
|
sCmd.addCommand("dhtComfort", dhtC);
|
||||||
sCmd.addCommand("dhtDewpoint", dhtD);
|
sCmd.addCommand("dhtDewpoint", dhtD);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef bmp_enable
|
#ifdef bmp_enable
|
||||||
sCmd.addCommand("bmp280T", bmp280T);
|
sCmd.addCommand("bmp280T", bmp280T);
|
||||||
sCmd.addCommand("bmp280P", bmp280P);
|
sCmd.addCommand("bmp280P", bmp280P);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef bme_enable
|
#ifdef bme_enable
|
||||||
sCmd.addCommand("bme280T", bme280T);
|
sCmd.addCommand("bme280T", bme280T);
|
||||||
sCmd.addCommand("bme280P", bme280P);
|
sCmd.addCommand("bme280P", bme280P);
|
||||||
sCmd.addCommand("bme280H", bme280H);
|
sCmd.addCommand("bme280H", bme280H);
|
||||||
sCmd.addCommand("bme280A", bme280A);
|
sCmd.addCommand("bme280A", bme280A);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef stepper_enable
|
#ifdef stepper_enable
|
||||||
sCmd.addCommand("stepper", stepper);
|
sCmd.addCommand("stepper", stepper);
|
||||||
sCmd.addCommand("stepperSet", stepperSet);
|
sCmd.addCommand("stepperSet", stepperSet);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef servo_enable
|
#ifdef servo_enable
|
||||||
sCmd.addCommand("servo", servo_);
|
sCmd.addCommand("servo", servo_);
|
||||||
sCmd.addCommand("servoSet", servoSet);
|
sCmd.addCommand("servoSet", servoSet);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef serial_enable
|
#ifdef serial_enable
|
||||||
sCmd.addCommand("serialBegin", serialBegin);
|
sCmd.addCommand("serialBegin", serialBegin);
|
||||||
sCmd.addCommand("serialWrite", serialWrite);
|
sCmd.addCommand("serialWrite", serialWrite);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef logging_enable
|
#ifdef logging_enable
|
||||||
sCmd.addCommand("logging", logging);
|
sCmd.addCommand("logging", logging);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sCmd.addCommand("inputDigit", inputDigit);
|
sCmd.addCommand("inputDigit", inputDigit);
|
||||||
sCmd.addCommand("digitSet", digitSet);
|
sCmd.addCommand("digitSet", digitSet);
|
||||||
|
|
||||||
sCmd.addCommand("inputTime", inputTime);
|
sCmd.addCommand("inputTime", inputTime);
|
||||||
sCmd.addCommand("timeSet", timeSet);
|
sCmd.addCommand("timeSet", timeSet);
|
||||||
|
|
||||||
sCmd.addCommand("timerStart", timerStart_);
|
sCmd.addCommand("timerStart", timerStart_);
|
||||||
sCmd.addCommand("timerStop", timerStop_);
|
sCmd.addCommand("timerStop", timerStop_);
|
||||||
|
|
||||||
sCmd.addCommand("text", text);
|
sCmd.addCommand("text", text);
|
||||||
sCmd.addCommand("textSet", textSet);
|
sCmd.addCommand("textSet", textSet);
|
||||||
|
|
||||||
sCmd.addCommand("mqtt", mqttOrderSend);
|
sCmd.addCommand("mqtt", mqttOrderSend);
|
||||||
sCmd.addCommand("http", httpOrderSend);
|
sCmd.addCommand("http", httpOrderSend);
|
||||||
|
|
||||||
#ifdef push_enable
|
#ifdef push_enable
|
||||||
sCmd.addCommand("push", pushControl);
|
sCmd.addCommand("push", pushControl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sCmd.addCommand("firmwareUpdate", firmwareUpdate);
|
sCmd.addCommand("firmwareUpdate", firmwareUpdate);
|
||||||
sCmd.addCommand("firmwareVersion", firmwareVersion);
|
sCmd.addCommand("firmwareVersion", firmwareVersion);
|
||||||
|
|
||||||
handle_time_init();
|
handle_time_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================================================
|
//==========================================================================================================
|
||||||
//==========================================Модуль кнопок===================================================
|
//==========================================Модуль кнопок===================================================
|
||||||
void button() {
|
void button() {
|
||||||
|
String button_number = sCmd.next();
|
||||||
|
String button_param = sCmd.next();
|
||||||
|
String widget_name = sCmd.next();
|
||||||
|
String page_name = sCmd.next();
|
||||||
|
String start_state = sCmd.next();
|
||||||
|
String page_number = sCmd.next();
|
||||||
|
|
||||||
String button_number = sCmd.next();
|
jsonWriteStr(configOptionJson, "button_param" + button_number, button_param);
|
||||||
String button_param = sCmd.next();
|
jsonWriteStr(configLiveJson, "button" + button_number, start_state);
|
||||||
String widget_name = sCmd.next();
|
|
||||||
String page_name = sCmd.next();
|
|
||||||
String start_state = sCmd.next();
|
|
||||||
String page_number = sCmd.next();
|
|
||||||
|
|
||||||
jsonWriteStr(configOptionJson, "button_param" + button_number, button_param);
|
if (isDigitStr(button_param)) {
|
||||||
jsonWriteStr(configLiveJson, "button" + button_number, start_state);
|
pinMode(button_param.toInt(), OUTPUT);
|
||||||
|
digitalWrite(button_param.toInt(), start_state.toInt());
|
||||||
if (isDigitStr (button_param)) {
|
|
||||||
pinMode(button_param.toInt(), OUTPUT);
|
|
||||||
digitalWrite(button_param.toInt(), start_state.toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_param == "scen") {
|
|
||||||
jsonWriteStr(configSetupJson, "scen", start_state);
|
|
||||||
Scenario_init();
|
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_param.indexOf("line") != -1) {
|
|
||||||
String str = button_param;
|
|
||||||
while (str.length() != 0) {
|
|
||||||
if (str == "") return;
|
|
||||||
String tmp = selectToMarker (str, ","); //line1,
|
|
||||||
String number = deleteBeforeDelimiter(tmp, "e"); //1,
|
|
||||||
number.replace(",", "");
|
|
||||||
Serial.println(number);
|
|
||||||
int number_int = number.toInt();
|
|
||||||
scenario_line_status[number_int] = start_state.toInt();
|
|
||||||
str = deleteBeforeDelimiter(str, ",");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
createWidget (widget_name, page_name, page_number, "widgets/widget.toggle.json", "button" + button_number);
|
if (button_param == "scen") {
|
||||||
|
jsonWriteStr(configSetupJson, "scen", start_state);
|
||||||
|
Scenario_init();
|
||||||
|
saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button_param.indexOf("line") != -1) {
|
||||||
|
String str = button_param;
|
||||||
|
while (str.length() != 0) {
|
||||||
|
if (str == "") return;
|
||||||
|
String tmp = selectToMarker(str, ","); //line1,
|
||||||
|
String number = deleteBeforeDelimiter(tmp, "e"); //1,
|
||||||
|
number.replace(",", "");
|
||||||
|
Serial.println(number);
|
||||||
|
int number_int = number.toInt();
|
||||||
|
scenario_line_status[number_int] = start_state.toInt();
|
||||||
|
str = deleteBeforeDelimiter(str, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createWidget(widget_name, page_name, page_number, "widgets/widget.toggle.json", "button" + button_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
void buttonSet() {
|
void buttonSet() {
|
||||||
|
String button_number = sCmd.next();
|
||||||
|
String button_state = sCmd.next();
|
||||||
|
String button_param = jsonReadStr(configOptionJson, "button_param" + button_number);
|
||||||
|
|
||||||
String button_number = sCmd.next();
|
if (button_param != "na" || button_param != "scen" || button_param.indexOf("line") != -1) {
|
||||||
String button_state = sCmd.next();
|
digitalWrite(button_param.toInt(), button_state.toInt());
|
||||||
String button_param = jsonReadStr(configOptionJson, "button_param" + button_number);
|
|
||||||
|
|
||||||
if (button_param != "na" || button_param != "scen" || button_param.indexOf("line") != -1) {
|
|
||||||
digitalWrite(button_param.toInt(), button_state.toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_param == "scen") {
|
|
||||||
jsonWriteStr(configSetupJson, "scen", button_state);
|
|
||||||
Scenario_init();
|
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_param.indexOf("line") != -1) {
|
|
||||||
String str = button_param;
|
|
||||||
while (str.length() != 0) {
|
|
||||||
if (str == "") return;
|
|
||||||
String tmp = selectToMarker (str, ","); //line1,
|
|
||||||
String number = deleteBeforeDelimiter(tmp, "e"); //1,
|
|
||||||
number.replace(",", "");
|
|
||||||
Serial.println(number);
|
|
||||||
int number_int = number.toInt();
|
|
||||||
scenario_line_status[number_int] = button_state.toInt();
|
|
||||||
str = deleteBeforeDelimiter(str, ",");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
eventGen ("button", button_number);
|
if (button_param == "scen") {
|
||||||
|
jsonWriteStr(configSetupJson, "scen", button_state);
|
||||||
|
Scenario_init();
|
||||||
|
saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
jsonWriteStr(configLiveJson, "button" + button_number, button_state);
|
if (button_param.indexOf("line") != -1) {
|
||||||
sendSTATUS("button" + button_number, button_state);
|
String str = button_param;
|
||||||
|
while (str.length() != 0) {
|
||||||
|
if (str == "") return;
|
||||||
|
String tmp = selectToMarker(str, ","); //line1,
|
||||||
|
String number = deleteBeforeDelimiter(tmp, "e"); //1,
|
||||||
|
number.replace(",", "");
|
||||||
|
Serial.println(number);
|
||||||
|
int number_int = number.toInt();
|
||||||
|
scenario_line_status[number_int] = button_state.toInt();
|
||||||
|
str = deleteBeforeDelimiter(str, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventGen("button", button_number);
|
||||||
|
|
||||||
|
jsonWriteStr(configLiveJson, "button" + button_number, button_state);
|
||||||
|
sendSTATUS("button" + button_number, button_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void buttonChange() {
|
void buttonChange() {
|
||||||
String button_number = sCmd.next();
|
String button_number = sCmd.next();
|
||||||
String current_state = jsonReadStr(configLiveJson, "button" + button_number);
|
String current_state = jsonReadStr(configLiveJson, "button" + button_number);
|
||||||
if (current_state == "1") {
|
if (current_state == "1") {
|
||||||
current_state = "0";
|
current_state = "0";
|
||||||
} else if (current_state == "0") {
|
} else if (current_state == "0") {
|
||||||
current_state = "1";
|
current_state = "1";
|
||||||
}
|
}
|
||||||
order_loop += "buttonSet " + button_number + " " + current_state + ",";
|
order_loop += "buttonSet " + button_number + " " + current_state + ",";
|
||||||
jsonWriteStr(configLiveJson, "button" + button_number, current_state);
|
jsonWriteStr(configLiveJson, "button" + button_number, current_state);
|
||||||
sendSTATUS("button" + button_number, current_state);
|
sendSTATUS("button" + button_number, current_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pinSet() {
|
void pinSet() {
|
||||||
String pin_number = sCmd.next();
|
String pin_number = sCmd.next();
|
||||||
String pin_state = sCmd.next();
|
String pin_state = sCmd.next();
|
||||||
pinMode(pin_number.toInt(), OUTPUT);
|
pinMode(pin_number.toInt(), OUTPUT);
|
||||||
digitalWrite(pin_number.toInt(), pin_state.toInt());
|
digitalWrite(pin_number.toInt(), pin_state.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pinChange() {
|
void pinChange() {
|
||||||
String pin_number = sCmd.next();
|
String pin_number = sCmd.next();
|
||||||
pinMode(pin_number.toInt(), OUTPUT);
|
pinMode(pin_number.toInt(), OUTPUT);
|
||||||
digitalWrite(pin_number.toInt(), !digitalRead(pin_number.toInt()));
|
digitalWrite(pin_number.toInt(), !digitalRead(pin_number.toInt()));
|
||||||
}
|
}
|
||||||
//==================================================================================================================
|
//==================================================================================================================
|
||||||
//==========================================Модуль управления ШИМ===================================================
|
//==========================================Модуль управления ШИМ===================================================
|
||||||
void pwm() {
|
void pwm() {
|
||||||
|
//static boolean flag = true;
|
||||||
|
String pwm_number = sCmd.next();
|
||||||
|
String pwm_pin = sCmd.next();
|
||||||
|
String widget_name = sCmd.next();
|
||||||
|
widget_name.replace("#", " ");
|
||||||
|
String page_name = sCmd.next();
|
||||||
|
String start_state = sCmd.next();
|
||||||
|
String page_number = sCmd.next();
|
||||||
|
|
||||||
//static boolean flag = true;
|
uint8_t pwm_pin_int = pwm_pin.toInt();
|
||||||
String pwm_number = sCmd.next();
|
jsonWriteStr(configOptionJson, "pwm_pin" + pwm_number, pwm_pin);
|
||||||
String pwm_pin = sCmd.next();
|
pinMode(pwm_pin_int, INPUT);
|
||||||
String widget_name = sCmd.next();
|
analogWrite(pwm_pin_int, start_state.toInt());
|
||||||
widget_name.replace("#", " ");
|
//analogWriteFreq(32000);
|
||||||
String page_name = sCmd.next();
|
jsonWriteStr(configLiveJson, "pwm" + pwm_number, start_state);
|
||||||
String start_state = sCmd.next();
|
|
||||||
String page_number = sCmd.next();
|
|
||||||
|
|
||||||
|
createWidget(widget_name, page_name, page_number, "widgets/widget.range.json", "pwm" + pwm_number);
|
||||||
uint8_t pwm_pin_int = pwm_pin.toInt();
|
|
||||||
jsonWriteStr(configOptionJson, "pwm_pin" + pwm_number, pwm_pin);
|
|
||||||
pinMode(pwm_pin_int, INPUT);
|
|
||||||
analogWrite(pwm_pin_int, start_state.toInt());
|
|
||||||
//analogWriteFreq(32000);
|
|
||||||
jsonWriteStr(configLiveJson, "pwm" + pwm_number, start_state);
|
|
||||||
|
|
||||||
createWidget (widget_name, page_name, page_number, "widgets/widget.range.json", "pwm" + pwm_number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pwmSet() {
|
void pwmSet() {
|
||||||
|
String pwm_number = sCmd.next();
|
||||||
|
String pwm_state = sCmd.next();
|
||||||
|
int pwm_state_int = pwm_state.toInt();
|
||||||
|
|
||||||
String pwm_number = sCmd.next();
|
int pin = jsonReadInt(configOptionJson, "pwm_pin" + pwm_number);
|
||||||
String pwm_state = sCmd.next();
|
analogWrite(pin, pwm_state_int);
|
||||||
int pwm_state_int = pwm_state.toInt();
|
|
||||||
|
|
||||||
int pin = jsonReadInt(configOptionJson, "pwm_pin" + pwm_number);
|
eventGen("pwm", pwm_number);
|
||||||
analogWrite(pin, pwm_state_int);
|
|
||||||
|
|
||||||
eventGen ("pwm", pwm_number);
|
jsonWriteStr(configLiveJson, "pwm" + pwm_number, pwm_state);
|
||||||
|
sendSTATUS("pwm" + pwm_number, pwm_state);
|
||||||
jsonWriteStr(configLiveJson, "pwm" + pwm_number, pwm_state);
|
|
||||||
sendSTATUS("pwm" + pwm_number, pwm_state);
|
|
||||||
}
|
}
|
||||||
//==================================================================================================================
|
//==================================================================================================================
|
||||||
//==========================================Модуль физической кнопки================================================
|
//==========================================Модуль физической кнопки================================================
|
||||||
void switch_ () {
|
void switch_() {
|
||||||
|
String switch_number = sCmd.next();
|
||||||
|
String switch_pin = sCmd.next();
|
||||||
|
String switch_delay = sCmd.next();
|
||||||
|
|
||||||
String switch_number = sCmd.next();
|
buttons[switch_number.toInt()].attach(switch_pin.toInt());
|
||||||
String switch_pin = sCmd.next();
|
buttons[switch_number.toInt()].interval(switch_delay.toInt());
|
||||||
String switch_delay = sCmd.next();
|
but[switch_number.toInt()] = true;
|
||||||
|
|
||||||
buttons[switch_number.toInt()].attach(switch_pin.toInt());
|
|
||||||
buttons[switch_number.toInt()].interval(switch_delay.toInt());
|
|
||||||
but[switch_number.toInt()] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleButton() {
|
void handleButton() {
|
||||||
|
static uint8_t switch_number = 1;
|
||||||
|
|
||||||
static uint8_t switch_number = 1;
|
if (but[switch_number]) {
|
||||||
|
buttons[switch_number].update();
|
||||||
|
if (buttons[switch_number].fell()) {
|
||||||
|
eventGen("switch", String(switch_number));
|
||||||
|
|
||||||
if (but[switch_number]) {
|
jsonWriteStr(configLiveJson, "switch" + String(switch_number), "1");
|
||||||
buttons[switch_number].update();
|
}
|
||||||
if (buttons[switch_number].fell()) {
|
if (buttons[switch_number].rose()) {
|
||||||
|
eventGen("switch", String(switch_number));
|
||||||
|
|
||||||
eventGen ("switch", String(switch_number));
|
jsonWriteStr(configLiveJson, "switch" + String(switch_number), "0");
|
||||||
|
}
|
||||||
jsonWriteStr(configLiveJson, "switch" + String(switch_number), "1");
|
|
||||||
}
|
}
|
||||||
if (buttons[switch_number].rose()) {
|
switch_number++;
|
||||||
|
if (switch_number == 6) switch_number = 0;
|
||||||
eventGen ("switch", String(switch_number));
|
|
||||||
|
|
||||||
jsonWriteStr(configLiveJson, "switch" + String(switch_number), "0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch_number++;
|
|
||||||
if (switch_number == 6) switch_number = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=====================================================================================================================================
|
//=====================================================================================================================================
|
||||||
//=========================================Добавление окна ввода цифры=================================================================
|
//=========================================Добавление окна ввода цифры=================================================================
|
||||||
void inputDigit() {
|
void inputDigit() {
|
||||||
String value_name = sCmd.next();
|
String value_name = sCmd.next();
|
||||||
String number = value_name.substring(5);
|
String number = value_name.substring(5);
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
widget_name.replace("#", " ");
|
widget_name.replace("#", " ");
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
page_name.replace("#", " ");
|
page_name.replace("#", " ");
|
||||||
String start_state = sCmd.next();
|
String start_state = sCmd.next();
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
jsonWriteStr(configLiveJson, "digit" + number, start_state);
|
jsonWriteStr(configLiveJson, "digit" + number, start_state);
|
||||||
createWidget (widget_name, page_name, page_number, "widgets/widget.inputNum.json", "digit" + number);
|
createWidget(widget_name, page_name, page_number, "widgets/widget.inputNum.json", "digit" + number);
|
||||||
}
|
}
|
||||||
void digitSet() {
|
void digitSet() {
|
||||||
String number = sCmd.next();
|
String number = sCmd.next();
|
||||||
String value = sCmd.next();
|
String value = sCmd.next();
|
||||||
jsonWriteStr(configLiveJson, "digit" + number, value);
|
jsonWriteStr(configLiveJson, "digit" + number, value);
|
||||||
sendSTATUS("digit" + number, value);
|
sendSTATUS("digit" + number, value);
|
||||||
}
|
}
|
||||||
//=====================================================================================================================================
|
//=====================================================================================================================================
|
||||||
//=========================================Добавление окна ввода времени===============================================================
|
//=========================================Добавление окна ввода времени===============================================================
|
||||||
void inputTime() {
|
void inputTime() {
|
||||||
String value_name = sCmd.next();
|
String value_name = sCmd.next();
|
||||||
String number = value_name.substring(4);
|
String number = value_name.substring(4);
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
widget_name.replace("#", " ");
|
widget_name.replace("#", " ");
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
page_name.replace("#", " ");
|
page_name.replace("#", " ");
|
||||||
String start_state = sCmd.next();
|
String start_state = sCmd.next();
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
jsonWriteStr(configLiveJson, "time" + number, start_state);
|
jsonWriteStr(configLiveJson, "time" + number, start_state);
|
||||||
createWidget (widget_name, page_name, page_number, "widgets/widget.inputTime.json", "time" + number);
|
createWidget(widget_name, page_name, page_number, "widgets/widget.inputTime.json", "time" + number);
|
||||||
}
|
}
|
||||||
void timeSet() {
|
void timeSet() {
|
||||||
String number = sCmd.next();
|
String number = sCmd.next();
|
||||||
String value = sCmd.next();
|
String value = sCmd.next();
|
||||||
jsonWriteStr(configLiveJson, "time" + number, value);
|
jsonWriteStr(configLiveJson, "time" + number, value);
|
||||||
sendSTATUS("time" + number, value);
|
sendSTATUS("time" + number, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_time_init() {
|
void handle_time_init() {
|
||||||
ts.add(TIME, 1000, [&](void*) {
|
ts.add(
|
||||||
|
TIME, 1000, [&](void *) {
|
||||||
String tmp = GetTime();
|
String tmp = GetTime();
|
||||||
jsonWriteStr(configLiveJson, "time", tmp);
|
jsonWriteStr(configLiveJson, "time", tmp);
|
||||||
tmp.replace(":", "-");
|
tmp.replace(":", "-");
|
||||||
jsonWriteStr(configLiveJson, "timenow", tmp);
|
jsonWriteStr(configLiveJson, "timenow", tmp);
|
||||||
eventGen ("timenow", "");
|
eventGen("timenow", "");
|
||||||
|
},
|
||||||
}, nullptr, true);
|
nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=====================================================================================================================================
|
//=====================================================================================================================================
|
||||||
//=========================================Добавление текстового виджета============================================================
|
//=========================================Добавление текстового виджета============================================================
|
||||||
void text() {
|
void text() {
|
||||||
|
String number = sCmd.next();
|
||||||
|
String widget_name = sCmd.next();
|
||||||
|
String page_name = sCmd.next();
|
||||||
|
String page_number = sCmd.next();
|
||||||
|
|
||||||
String number = sCmd.next();
|
createWidget(widget_name, page_name, page_number, "widgets/widget.anyData.json", "text" + number);
|
||||||
String widget_name = sCmd.next();
|
|
||||||
String page_name = sCmd.next();
|
|
||||||
String page_number = sCmd.next();
|
|
||||||
|
|
||||||
createWidget (widget_name, page_name, page_number, "widgets/widget.anyData.json", "text" + number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void textSet() {
|
void textSet() {
|
||||||
|
String number = sCmd.next();
|
||||||
|
String text = sCmd.next();
|
||||||
|
text.replace("_", " ");
|
||||||
|
|
||||||
String number = sCmd.next();
|
if (text.indexOf("-time") >= 0) {
|
||||||
String text = sCmd.next();
|
text.replace("-time", "");
|
||||||
text.replace("_", " ");
|
text.replace("#", " ");
|
||||||
|
String time = GetTime();
|
||||||
|
time.replace(":", ".");
|
||||||
|
text = text + " " + GetDataDigital() + " " + time;
|
||||||
|
}
|
||||||
|
|
||||||
if (text.indexOf("-time") >= 0) {
|
jsonWriteStr(configLiveJson, "text" + number, text);
|
||||||
text.replace("-time", "");
|
sendSTATUS("text" + number, text);
|
||||||
text.replace("#", " ");
|
|
||||||
String time = GetTime();
|
|
||||||
time.replace(":", ".");
|
|
||||||
text = text + " " + GetDataDigital() + " " + time;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonWriteStr(configLiveJson, "text" + number, text);
|
|
||||||
sendSTATUS("text" + number, text);
|
|
||||||
}
|
}
|
||||||
//=====================================================================================================================================
|
//=====================================================================================================================================
|
||||||
//=========================================Модуль шагового мотора======================================================================
|
//=========================================Модуль шагового мотора======================================================================
|
||||||
#ifdef stepper_enable
|
#ifdef stepper_enable
|
||||||
//stepper 1 12 13
|
//stepper 1 12 13
|
||||||
void stepper() {
|
void stepper() {
|
||||||
String stepper_number = sCmd.next();
|
String stepper_number = sCmd.next();
|
||||||
String pin_step = sCmd.next();
|
String pin_step = sCmd.next();
|
||||||
String pin_dir = sCmd.next();
|
String pin_dir = sCmd.next();
|
||||||
|
|
||||||
jsonWriteStr(configOptionJson, "stepper" + stepper_number, pin_step + " " + pin_dir);
|
jsonWriteStr(configOptionJson, "stepper" + stepper_number, pin_step + " " + pin_dir);
|
||||||
pinMode(pin_step.toInt(), OUTPUT);
|
pinMode(pin_step.toInt(), OUTPUT);
|
||||||
pinMode(pin_dir.toInt(), OUTPUT);
|
pinMode(pin_dir.toInt(), OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
//stepperSet 1 100 5
|
//stepperSet 1 100 5
|
||||||
void stepperSet() {
|
void stepperSet() {
|
||||||
String stepper_number = sCmd.next();
|
String stepper_number = sCmd.next();
|
||||||
String steps = sCmd.next();
|
String steps = sCmd.next();
|
||||||
jsonWriteStr(configOptionJson, "steps" + stepper_number, steps);
|
jsonWriteStr(configOptionJson, "steps" + stepper_number, steps);
|
||||||
String stepper_speed = sCmd.next();
|
String stepper_speed = sCmd.next();
|
||||||
String pin_step = selectToMarker (jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
|
String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
|
||||||
String pin_dir = deleteBeforeDelimiter (jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
|
String pin_dir = deleteBeforeDelimiter(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
|
||||||
Serial.println(pin_step);
|
Serial.println(pin_step);
|
||||||
Serial.println(pin_dir);
|
Serial.println(pin_dir);
|
||||||
if (steps.toInt() > 0) digitalWrite(pin_dir.toInt(), HIGH);
|
if (steps.toInt() > 0) digitalWrite(pin_dir.toInt(), HIGH);
|
||||||
if (steps.toInt() < 0) digitalWrite(pin_dir.toInt(), LOW);
|
if (steps.toInt() < 0) digitalWrite(pin_dir.toInt(), LOW);
|
||||||
if (stepper_number == "1") {
|
if (stepper_number == "1") {
|
||||||
ts.add(STEPPER1, stepper_speed.toInt(), [&](void*) {
|
ts.add(
|
||||||
int steps_int = abs(jsonReadInt(configOptionJson, "steps1") * 2);
|
STEPPER1, stepper_speed.toInt(), [&](void *) {
|
||||||
static int count;
|
int steps_int = abs(jsonReadInt(configOptionJson, "steps1") * 2);
|
||||||
count++;
|
static int count;
|
||||||
String pin_step = selectToMarker (jsonReadStr(configOptionJson, "stepper1"), " ");
|
count++;
|
||||||
digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
|
String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper1"), " ");
|
||||||
yield();
|
digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
|
||||||
if (count > steps_int) {
|
yield();
|
||||||
digitalWrite(pin_step.toInt(), LOW);
|
if (count > steps_int) {
|
||||||
ts.remove(STEPPER1);
|
digitalWrite(pin_step.toInt(), LOW);
|
||||||
count = 0;
|
ts.remove(STEPPER1);
|
||||||
}
|
count = 0;
|
||||||
}, nullptr, true);
|
}
|
||||||
}
|
},
|
||||||
if (stepper_number == "2") {
|
nullptr, true);
|
||||||
ts.add(STEPPER2, stepper_speed.toInt(), [&](void*) {
|
}
|
||||||
int steps_int = abs(jsonReadInt(configOptionJson, "steps2") * 2);
|
if (stepper_number == "2") {
|
||||||
static int count;
|
ts.add(
|
||||||
count++;
|
STEPPER2, stepper_speed.toInt(), [&](void *) {
|
||||||
String pin_step = selectToMarker (jsonReadStr(configOptionJson, "stepper2"), " ");
|
int steps_int = abs(jsonReadInt(configOptionJson, "steps2") * 2);
|
||||||
digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
|
static int count;
|
||||||
yield();
|
count++;
|
||||||
if (count > steps_int) {
|
String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper2"), " ");
|
||||||
digitalWrite(pin_step.toInt(), LOW);
|
digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
|
||||||
ts.remove(STEPPER2);
|
yield();
|
||||||
count = 0;
|
if (count > steps_int) {
|
||||||
}
|
digitalWrite(pin_step.toInt(), LOW);
|
||||||
}, nullptr, true);
|
ts.remove(STEPPER2);
|
||||||
}
|
count = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nullptr, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//====================================================================================================================================================
|
//====================================================================================================================================================
|
||||||
@@ -414,190 +407,182 @@ void stepperSet() {
|
|||||||
#ifdef servo_enable
|
#ifdef servo_enable
|
||||||
//servo 1 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2
|
//servo 1 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2
|
||||||
void servo_() {
|
void servo_() {
|
||||||
String servo_number = sCmd.next();
|
String servo_number = sCmd.next();
|
||||||
String servo_pin = sCmd.next();
|
String servo_pin = sCmd.next();
|
||||||
String start_state = sCmd.next();
|
String start_state = sCmd.next();
|
||||||
int start_state_int = start_state.toInt();
|
int start_state_int = start_state.toInt();
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
|
|
||||||
String min_value = sCmd.next();
|
String min_value = sCmd.next();
|
||||||
String max_value = sCmd.next();
|
String max_value = sCmd.next();
|
||||||
|
|
||||||
String min_deg = sCmd.next();
|
String min_deg = sCmd.next();
|
||||||
String max_deg = sCmd.next();
|
String max_deg = sCmd.next();
|
||||||
|
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
|
|
||||||
jsonWriteStr(configOptionJson, "servo_pin" + servo_number, servo_pin);
|
jsonWriteStr(configOptionJson, "servo_pin" + servo_number, servo_pin);
|
||||||
start_state_int = map(start_state_int, min_value.toInt(), max_value.toInt(), min_deg.toInt(), max_deg.toInt());
|
start_state_int = map(start_state_int, min_value.toInt(), max_value.toInt(), min_deg.toInt(), max_deg.toInt());
|
||||||
|
|
||||||
if (servo_number == "1") {
|
if (servo_number == "1") {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
myServo1.attach(servo_pin.toInt());
|
myServo1.attach(servo_pin.toInt());
|
||||||
myServo1.write(start_state_int);
|
myServo1.write(start_state_int);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
myServo1.attach(servo_pin.toInt(), 500, 2400);
|
myServo1.attach(servo_pin.toInt(), 500, 2400);
|
||||||
myServo1.write(start_state_int);
|
myServo1.write(start_state_int);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servo_number == "2") {
|
if (servo_number == "2") {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
myServo2.attach(servo_pin.toInt());
|
myServo2.attach(servo_pin.toInt());
|
||||||
myServo2.write(start_state_int);
|
myServo2.write(start_state_int);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
myServo2.attach(servo_pin.toInt(), 500, 2400);
|
myServo2.attach(servo_pin.toInt(), 500, 2400);
|
||||||
myServo2.write(start_state_int);
|
myServo2.write(start_state_int);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonWriteStr(configOptionJson, "s_min_val" + servo_number, min_value);
|
jsonWriteStr(configOptionJson, "s_min_val" + servo_number, min_value);
|
||||||
jsonWriteStr(configOptionJson, "s_max_val" + servo_number, max_value);
|
jsonWriteStr(configOptionJson, "s_max_val" + servo_number, max_value);
|
||||||
jsonWriteStr(configOptionJson, "s_min_deg" + servo_number, min_deg);
|
jsonWriteStr(configOptionJson, "s_min_deg" + servo_number, min_deg);
|
||||||
jsonWriteStr(configOptionJson, "s_max_deg" + servo_number, max_deg);
|
jsonWriteStr(configOptionJson, "s_max_deg" + servo_number, max_deg);
|
||||||
|
|
||||||
jsonWriteStr(configLiveJson, "servo" + servo_number, start_state);
|
jsonWriteStr(configLiveJson, "servo" + servo_number, start_state);
|
||||||
|
|
||||||
createWidgetParam (widget_name, page_name, page_number, "widgets/widget.range.json", "servo" + servo_number, "min", min_value, "max", max_value, "k", "1");
|
createWidgetParam(widget_name, page_name, page_number, "widgets/widget.range.json", "servo" + servo_number, "min", min_value, "max", max_value, "k", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
void servoSet() {
|
void servoSet() {
|
||||||
String servo_number = sCmd.next();
|
String servo_number = sCmd.next();
|
||||||
String servo_state = sCmd.next();
|
String servo_state = sCmd.next();
|
||||||
int servo_state_int = servo_state.toInt();
|
int servo_state_int = servo_state.toInt();
|
||||||
|
|
||||||
//int pin = jsonReadInt(configOptionJson, "servo_pin" + servo_number);
|
//int pin = jsonReadInt(configOptionJson, "servo_pin" + servo_number);
|
||||||
|
|
||||||
servo_state_int = map(servo_state_int,
|
servo_state_int = map(servo_state_int,
|
||||||
jsonReadInt(configOptionJson, "s_min_val" + servo_number),
|
jsonReadInt(configOptionJson, "s_min_val" + servo_number),
|
||||||
jsonReadInt(configOptionJson, "s_max_val" + servo_number),
|
jsonReadInt(configOptionJson, "s_max_val" + servo_number),
|
||||||
jsonReadInt(configOptionJson, "s_min_deg" + servo_number),
|
jsonReadInt(configOptionJson, "s_min_deg" + servo_number),
|
||||||
jsonReadInt(configOptionJson, "s_max_deg" + servo_number));
|
jsonReadInt(configOptionJson, "s_max_deg" + servo_number));
|
||||||
|
|
||||||
if (servo_number == "1") {
|
if (servo_number == "1") {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
myServo1.write(servo_state_int);
|
myServo1.write(servo_state_int);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
myServo1.write(servo_state_int);
|
myServo1.write(servo_state_int);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servo_number == "2") {
|
if (servo_number == "2") {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
myServo2.write(servo_state_int);
|
myServo2.write(servo_state_int);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
myServo2.write(servo_state_int);
|
myServo2.write(servo_state_int);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//Serial.println(servo_state_int);
|
//Serial.println(servo_state_int);
|
||||||
|
|
||||||
eventGen ("servo", servo_number);
|
eventGen("servo", servo_number);
|
||||||
|
|
||||||
jsonWriteStr(configLiveJson, "servo" + servo_number, servo_state);
|
jsonWriteStr(configLiveJson, "servo" + servo_number, servo_state);
|
||||||
sendSTATUS("servo" + servo_number, servo_state);
|
sendSTATUS("servo" + servo_number, servo_state);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//====================================================================================================================================================
|
//====================================================================================================================================================
|
||||||
//===================================================================================serial===========================================================
|
//===================================================================================serial===========================================================
|
||||||
#ifdef serial_enable
|
#ifdef serial_enable
|
||||||
void serialBegin() {
|
void serialBegin() {
|
||||||
//String s_speed = sCmd.next();
|
//String s_speed = sCmd.next();
|
||||||
//String rxPin = sCmd.next();
|
//String rxPin = sCmd.next();
|
||||||
//String txPin = sCmd.next();
|
//String txPin = sCmd.next();
|
||||||
//SoftwareSerial mySerial(rxPin.toInt(), txPin.toInt());
|
//SoftwareSerial mySerial(rxPin.toInt(), txPin.toInt());
|
||||||
//mySerial.begin(s_speed.toInt());
|
//mySerial.begin(s_speed.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialWrite() {
|
void serialWrite() {
|
||||||
//String text = sCmd.next();
|
//String text = sCmd.next();
|
||||||
//mySerial.println(text);
|
//mySerial.println(text);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//====================================================================================================================================================
|
//====================================================================================================================================================
|
||||||
//=================================================Глобальные команды удаленного управления===========================================================
|
//=================================================Глобальные команды удаленного управления===========================================================
|
||||||
|
|
||||||
void mqttOrderSend() {
|
void mqttOrderSend() {
|
||||||
|
String id = sCmd.next();
|
||||||
|
String order = sCmd.next();
|
||||||
|
|
||||||
String id = sCmd.next();
|
String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/order";
|
||||||
String order = sCmd.next();
|
//Serial.print(all_line);
|
||||||
|
//Serial.print("->");
|
||||||
String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/order";
|
//Serial.println(order);
|
||||||
//Serial.print(all_line);
|
client_mqtt.publish(all_line.c_str(), order.c_str(), false);
|
||||||
//Serial.print("->");
|
|
||||||
//Serial.println(order);
|
|
||||||
client_mqtt.publish (all_line.c_str(), order.c_str(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpOrderSend() {
|
void httpOrderSend() {
|
||||||
|
String ip = sCmd.next();
|
||||||
String ip = sCmd.next();
|
String order = sCmd.next();
|
||||||
String order = sCmd.next();
|
order.replace("_", "%20");
|
||||||
order.replace("_", "%20");
|
String url = "http://" + ip + "/cmd?command=" + order;
|
||||||
String url = "http://" + ip + "/cmd?command=" + order;
|
getURL(url);
|
||||||
getURL(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void firmwareUpdate() {
|
void firmwareUpdate() {
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void firmwareVersion() {
|
void firmwareVersion() {
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
jsonWriteStr(configLiveJson, "firmver", firmware_version);
|
jsonWriteStr(configLiveJson, "firmver", firmware_version);
|
||||||
choose_widget_and_create(widget_name, page_name, page_number, "any-data", "firmver");
|
choose_widget_and_create(widget_name, page_name, page_number, "any-data", "firmver");
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================================================
|
//==============================================================================================================================
|
||||||
//============================выполнение команд (в лупе) по очереди из строки order=============================================
|
//============================выполнение команд (в лупе) по очереди из строки order=============================================
|
||||||
void handleCMD_loop() {
|
void handleCMD_loop() {
|
||||||
|
if (order_loop != "") {
|
||||||
if (order_loop != "") {
|
String tmp = selectToMarker(order_loop, ","); //выделяем из страки order первую команду rel 5 1,
|
||||||
|
sCmd.readStr(tmp); //выполняем первую команду
|
||||||
String tmp = selectToMarker(order_loop, ","); //выделяем из страки order первую команду rel 5 1,
|
Serial.println("[ORDER] => " + order_loop);
|
||||||
sCmd.readStr(tmp); //выполняем первую команду
|
order_loop = deleteBeforeDelimiter(order_loop, ","); //осекаем выполненную команду
|
||||||
Serial.println("[ORDER] => " + order_loop);
|
}
|
||||||
order_loop = deleteBeforeDelimiter(order_loop, ","); //осекаем выполненную команду
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======================================================================================================================================
|
//=======================================================================================================================================
|
||||||
//=======================================================================================================================================
|
//=======================================================================================================================================
|
||||||
void txtExecution(String file) {
|
void txtExecution(String file) {
|
||||||
|
String command_all = readFile(file, 2048) + "\r\n";
|
||||||
|
|
||||||
String command_all = readFile(file, 2048) + "\r\n";
|
command_all.replace("\r\n", "\n");
|
||||||
|
command_all.replace("\r", "\n");
|
||||||
|
|
||||||
command_all.replace("\r\n", "\n");
|
while (command_all.length() != 0) {
|
||||||
command_all.replace("\r", "\n");
|
String tmp = selectToMarker(command_all, "\n");
|
||||||
|
sCmd.readStr(tmp);
|
||||||
while (command_all.length() != 0) {
|
command_all = deleteBeforeDelimiter(command_all, "\n");
|
||||||
|
}
|
||||||
String tmp = selectToMarker (command_all, "\n");
|
command_all = "";
|
||||||
sCmd.readStr(tmp);
|
|
||||||
command_all = deleteBeforeDelimiter(command_all, "\n");
|
|
||||||
}
|
|
||||||
command_all = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stringExecution(String str) {
|
void stringExecution(String str) {
|
||||||
|
str = str + "\r\n";
|
||||||
|
|
||||||
str = str + "\r\n";
|
str.replace("\r\n", "\n");
|
||||||
|
str.replace("\r", "\n");
|
||||||
|
|
||||||
str.replace("\r\n", "\n");
|
while (str.length() != 0) {
|
||||||
str.replace("\r", "\n");
|
String tmp = selectToMarker(str, "\n");
|
||||||
|
sCmd.readStr(tmp);
|
||||||
|
|
||||||
while (str.length() != 0) {
|
str = deleteBeforeDelimiter(str, "\n");
|
||||||
|
}
|
||||||
String tmp = selectToMarker (str, "\n");
|
|
||||||
sCmd.readStr(tmp);
|
|
||||||
|
|
||||||
str = deleteBeforeDelimiter(str, "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,57 +1,27 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
#include "JsonUtils.h"
|
/*
|
||||||
|
* Objects.cpp(с данными)
|
||||||
//==============================Objects.cpp(с данными)==================================
|
*/
|
||||||
|
|
||||||
#ifdef WS_enable
|
#ifdef WS_enable
|
||||||
AsyncWebSocket ws;
|
AsyncWebSocket ws;
|
||||||
#endif
|
|
||||||
|
|
||||||
//AsyncEventSource events;
|
//AsyncEventSource events;
|
||||||
|
#endif
|
||||||
TickerScheduler ts(TEST + 1);
|
TickerScheduler ts(TEST + 1);
|
||||||
|
|
||||||
WiFiClient espClient;
|
WiFiClient espClient;
|
||||||
|
|
||||||
PubSubClient client_mqtt(espClient);
|
PubSubClient client_mqtt(espClient);
|
||||||
|
|
||||||
StringCommand sCmd;
|
StringCommand sCmd;
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
//AsyncWebSocket ws("/ws");
|
//AsyncWebSocket ws("/ws");
|
||||||
|
|
||||||
//AsyncEventSource events("/events");
|
//AsyncEventSource events("/events");
|
||||||
|
|
||||||
boolean but[NUM_BUTTONS];
|
|
||||||
Bounce *buttons = new Bounce[NUM_BUTTONS];
|
|
||||||
|
|
||||||
GMedian<10, int> medianFilter;
|
|
||||||
|
|
||||||
OneWire *oneWire;
|
|
||||||
DallasTemperature sensors;
|
DallasTemperature sensors;
|
||||||
|
|
||||||
DHTesp dht;
|
/*
|
||||||
|
* Global vars
|
||||||
Servo myServo1;
|
*/
|
||||||
Servo myServo2;
|
|
||||||
|
|
||||||
Adafruit_BMP280 bmp;
|
|
||||||
Adafruit_Sensor *bmp_temp;
|
|
||||||
Adafruit_Sensor *bmp_pressure;
|
|
||||||
|
|
||||||
Adafruit_BME280 bme;
|
|
||||||
Adafruit_Sensor *bme_temp;
|
|
||||||
Adafruit_Sensor *bme_pressure;
|
|
||||||
Adafruit_Sensor *bme_humidity;
|
|
||||||
|
|
||||||
uptime_interval myUpTime(10);
|
|
||||||
|
|
||||||
////////////////////////////////////// Global vars ////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
boolean just_load = true;
|
boolean just_load = true;
|
||||||
const char *hostName = "IoT Manager";
|
|
||||||
|
|
||||||
// Json
|
// Json
|
||||||
String configSetupJson = "{}";
|
String configSetupJson = "{}";
|
||||||
@@ -89,17 +59,10 @@ int sensors_reading_map[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|||||||
String logging_value_names_list;
|
String logging_value_names_list;
|
||||||
int enter_to_logging_counter;
|
int enter_to_logging_counter;
|
||||||
|
|
||||||
// Ntp and time
|
|
||||||
String current_time;
|
|
||||||
|
|
||||||
// Scenario
|
// Scenario
|
||||||
int scenario_line_status[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
int scenario_line_status[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||||
|
|
||||||
// Errors
|
String last_version = "";
|
||||||
int wifi_lost_error = 0;
|
|
||||||
int mqtt_lost_error = 0;
|
|
||||||
|
|
||||||
String last_version;
|
|
||||||
|
|
||||||
// Async actions
|
// Async actions
|
||||||
boolean upgrade_url = false;
|
boolean upgrade_url = false;
|
||||||
@@ -108,23 +71,3 @@ boolean mqtt_connection = false;
|
|||||||
boolean udp_data_parse = false;
|
boolean udp_data_parse = false;
|
||||||
boolean mqtt_send_settings_to_udp = false;
|
boolean mqtt_send_settings_to_udp = false;
|
||||||
boolean i2c_scanning = false;
|
boolean i2c_scanning = false;
|
||||||
|
|
||||||
//Buttons
|
|
||||||
//boolean but[6];
|
|
||||||
|
|
||||||
// Udp
|
|
||||||
boolean udp_busy = false;
|
|
||||||
unsigned int udp_port = 4210;
|
|
||||||
#ifdef ESP8266
|
|
||||||
IPAddress udp_multicastIP(255, 255, 255, 255);
|
|
||||||
#endif
|
|
||||||
#ifdef ESP32
|
|
||||||
IPAddress udp_multicastIP(239, 255, 255, 255);
|
|
||||||
AsyncUDP udp;
|
|
||||||
#endif
|
|
||||||
String received_ip;
|
|
||||||
String received_udp_line;
|
|
||||||
int udp_period;
|
|
||||||
|
|
||||||
// i2c
|
|
||||||
String i2c_list;
|
|
||||||
|
|||||||
134
src/Init.cpp
134
src/Init.cpp
@@ -1,103 +1,113 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
unsigned long UptimeInterval::_uptime_seconds;
|
||||||
|
|
||||||
|
UptimeInterval myUptime(10);
|
||||||
|
|
||||||
|
void handle_uptime();
|
||||||
|
void handle_statistics();
|
||||||
|
|
||||||
void All_init() {
|
void All_init() {
|
||||||
Device_init();
|
Device_init();
|
||||||
Scenario_init();
|
Scenario_init();
|
||||||
Timer_countdown_init();
|
Timer_countdown_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device_init() {
|
void Device_init() {
|
||||||
|
logging_value_names_list = "";
|
||||||
|
enter_to_logging_counter = LOG1 - 1;
|
||||||
|
|
||||||
logging_value_names_list = "";
|
analog_value_names_list = "";
|
||||||
enter_to_logging_counter = LOG1 - 1;
|
enter_to_analog_counter = 0;
|
||||||
|
|
||||||
analog_value_names_list = "";
|
levelPr_value_name = "";
|
||||||
enter_to_analog_counter = 0;
|
ultrasonicCm_value_name = "";
|
||||||
|
|
||||||
levelPr_value_name = "";
|
dhtT_value_name = "";
|
||||||
ultrasonicCm_value_name = "";
|
dhtH_value_name = "";
|
||||||
|
|
||||||
dhtT_value_name = "";
|
bmp280T_value_name = "";
|
||||||
dhtH_value_name = "";
|
bmp280P_value_name = "";
|
||||||
|
|
||||||
bmp280T_value_name = "";
|
bme280T_value_name = "";
|
||||||
bmp280P_value_name = "";
|
bme280P_value_name = "";
|
||||||
|
bme280H_value_name = "";
|
||||||
|
bme280A_value_name = "";
|
||||||
|
|
||||||
bme280T_value_name = "";
|
int array_sz = sizeof(sensors_reading_map) / sizeof(sensors_reading_map[0]);
|
||||||
bme280P_value_name = "";
|
|
||||||
bme280H_value_name = "";
|
|
||||||
bme280A_value_name = "";
|
|
||||||
|
|
||||||
int array_sz = sizeof(sensors_reading_map) / sizeof(sensors_reading_map[0]);
|
for (int i = 0; i < array_sz; i++) {
|
||||||
|
sensors_reading_map[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < array_sz; i++) {
|
for (int i = LOG1; i <= LOG5; i++) {
|
||||||
sensors_reading_map[i] = 0;
|
ts.remove(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = LOG1; i <= LOG5; i++) {
|
|
||||||
ts.remove(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef layout_in_ram
|
#ifdef layout_in_ram
|
||||||
all_widgets = "";
|
all_widgets = "";
|
||||||
#else
|
#else
|
||||||
SPIFFS.remove("/layout.txt");
|
SPIFFS.remove("/layout.txt");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
txtExecution("firmware.c.txt");
|
txtExecution("firmware.c.txt");
|
||||||
//outcoming_date();
|
//outcoming_date();
|
||||||
}
|
}
|
||||||
//-------------------------------сценарии-----------------------------------------------------
|
//-------------------------------сценарии-----------------------------------------------------
|
||||||
|
|
||||||
void Scenario_init() {
|
void Scenario_init() {
|
||||||
if (jsonReadStr(configSetupJson, "scen") == "1") {
|
if (jsonReadStr(configSetupJson, "scen") == "1") {
|
||||||
scenario = readFile("firmware.s.txt", 2048);
|
scenario = readFile("firmware.s.txt", 2048);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void uptime_init() {
|
void uptime_init() {
|
||||||
ts.add(UPTIME, 5000, [&](void*) {
|
ts.add(
|
||||||
handle_uptime();
|
UPTIME, 5000, [&](void*) {
|
||||||
}, nullptr, true);
|
handle_uptime();
|
||||||
ts.add(STATISTICS, statistics_update, [&](void*) {
|
},
|
||||||
handle_statistics();
|
nullptr, true);
|
||||||
}, nullptr, true);
|
ts.add(
|
||||||
|
STATISTICS, statistics_update, [&](void*) {
|
||||||
|
handle_statistics();
|
||||||
|
},
|
||||||
|
nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_uptime() {
|
void handle_uptime() {
|
||||||
if (myUpTime.check()) {
|
if (myUptime.check()) {
|
||||||
jsonWriteStr(configSetupJson, "uptime", uptime_as_string());
|
jsonWriteStr(configSetupJson, "uptime", prettyMillis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_statistics() {
|
void handle_statistics() {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
String urls = "http://backup.privet.lv/visitors/?";
|
String urls = "http://backup.privet.lv/visitors/?";
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
urls += WiFi.macAddress().c_str();
|
urls += WiFi.macAddress().c_str();
|
||||||
urls += "&";
|
urls += "&";
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
urls += "iot-manager_esp8266";
|
urls += "iot-manager_esp8266";
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
urls += "iot-manager_esp32";
|
urls += "iot-manager_esp32";
|
||||||
#endif
|
#endif
|
||||||
urls += "&";
|
urls += "&";
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
urls += ESP.getResetReason();
|
urls += ESP.getResetReason();
|
||||||
//Serial.println(ESP.getResetReason());
|
//Serial.println(ESP.getResetReason());
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
urls += "Power on";
|
urls += "Power on";
|
||||||
#endif
|
#endif
|
||||||
urls += "&";
|
urls += "&";
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
urls += "ver: ";
|
urls += "ver: ";
|
||||||
urls += String(firmware_version);
|
urls += String(firmware_version);
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
String stat = getURL(urls);
|
String stat = getURL(urls);
|
||||||
//Serial.println(stat);
|
//Serial.println(stat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
283
src/Mqtt.cpp
283
src/Mqtt.cpp
@@ -1,7 +1,10 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
void callback(char* topic, byte* payload, unsigned int length);
|
// Errors
|
||||||
|
int wifi_lost_error = 0;
|
||||||
|
int mqtt_lost_error = 0;
|
||||||
|
|
||||||
|
void callback(char* topic, uint8_t* payload, size_t length);
|
||||||
String stateMQTT();
|
String stateMQTT();
|
||||||
void sendAllData();
|
void sendAllData();
|
||||||
void sendAllWigets();
|
void sendAllWigets();
|
||||||
@@ -10,40 +13,42 @@ void outcoming_date();
|
|||||||
|
|
||||||
//===============================================ИНИЦИАЛИЗАЦИЯ================================================
|
//===============================================ИНИЦИАЛИЗАЦИЯ================================================
|
||||||
void MQTT_init() {
|
void MQTT_init() {
|
||||||
ts.add(WIFI_MQTT_CONNECTION_CHECK, wifi_mqtt_reconnecting, [&](void*) {
|
ts.add(
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
WIFI_MQTT_CONNECTION_CHECK, wifi_mqtt_reconnecting, [&](void*) {
|
||||||
Serial.println("[VV] WiFi-ok");
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
if (client_mqtt.connected()) {
|
Serial.println("[VV] WiFi-ok");
|
||||||
Serial.println("[VV] MQTT-ok");
|
if (client_mqtt.connected()) {
|
||||||
led_blink("off");
|
Serial.println("[VV] MQTT-ok");
|
||||||
} else {
|
led_blink("off");
|
||||||
MQTT_Connecting();
|
} else {
|
||||||
if (!just_load) mqtt_lost_error++;
|
MQTT_Connecting();
|
||||||
}
|
if (!just_load) mqtt_lost_error++;
|
||||||
} else {
|
}
|
||||||
Serial.println("[E] Lost WiFi connection");
|
} else {
|
||||||
wifi_lost_error++;
|
Serial.println("[E] Lost WiFi connection");
|
||||||
ts.remove(WIFI_MQTT_CONNECTION_CHECK);
|
wifi_lost_error++;
|
||||||
StartAPMode();
|
ts.remove(WIFI_MQTT_CONNECTION_CHECK);
|
||||||
}
|
StartAPMode();
|
||||||
}, nullptr, true);
|
}
|
||||||
|
},
|
||||||
|
nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_mqtt_connection() {
|
void do_mqtt_connection() {
|
||||||
if (mqtt_connection) {
|
if (mqtt_connection) {
|
||||||
mqtt_connection = false;
|
mqtt_connection = false;
|
||||||
client_mqtt.disconnect();
|
client_mqtt.disconnect();
|
||||||
MQTT_Connecting();
|
MQTT_Connecting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//================================================ОБНОВЛЕНИЕ====================================================
|
//================================================ОБНОВЛЕНИЕ====================================================
|
||||||
void handleMQTT() {
|
void handleMQTT() {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
if (client_mqtt.connected()) {
|
if (client_mqtt.connected()) {
|
||||||
client_mqtt.loop();
|
client_mqtt.loop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
boolean MQTT_Connecting() {
|
boolean MQTT_Connecting() {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
@@ -79,168 +84,162 @@ boolean MQTT_Connecting() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//=====================================================ВХОДЯЩИЕ ДАННЫЕ========================================================
|
//=====================================================ВХОДЯЩИЕ ДАННЫЕ========================================================
|
||||||
void callback(char* topic, byte * payload, unsigned int length) {
|
void callback(char* topic, uint8_t* payload, size_t length) {
|
||||||
Serial.print("[MQTT] ");
|
Serial.print("[MQTT] ");
|
||||||
Serial.print(topic);
|
Serial.print(topic);
|
||||||
String topic_str = String(topic);
|
String topic_str = String(topic);
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
for (int i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
str += (char)payload[i];
|
str += (char)payload[i];
|
||||||
}
|
}
|
||||||
Serial.println(" => " + str);
|
Serial.println(" => " + str);
|
||||||
|
|
||||||
if (str == "HELLO") outcoming_date();
|
if (str == "HELLO") outcoming_date();
|
||||||
|
|
||||||
//превращает название топика в команду, а значение в параметр команды
|
//превращает название топика в команду, а значение в параметр команды
|
||||||
if (topic_str.indexOf("control") > 0) { //IoTmanager/800324-1458415/button-sw2/control 1 //IoTmanager/800324-1458415/button99/control 1
|
if (topic_str.indexOf("control") > 0) { //IoTmanager/800324-1458415/button-sw2/control 1 //IoTmanager/800324-1458415/button99/control 1
|
||||||
String topic = selectFromMarkerToMarker(topic_str, "/", 3); //button1 //button99
|
String topic = selectFromMarkerToMarker(topic_str, "/", 3); //button1 //button99
|
||||||
topic = add_set(topic); //buttonSet1 //buttonSet99
|
topic = add_set(topic); //buttonSet1 //buttonSet99
|
||||||
String number = selectToMarkerLast(topic, "Set"); //1 //99
|
String number = selectToMarkerLast(topic, "Set"); //1 //99
|
||||||
topic.replace(number, ""); //buttonSet //buttonSet
|
topic.replace(number, ""); //buttonSet //buttonSet
|
||||||
String final_line = topic + " " + number + " " + str; //buttonSet 1 1 //buttonSet 99 1
|
String final_line = topic + " " + number + " " + str; //buttonSet 1 1 //buttonSet 99 1
|
||||||
order_loop += final_line + ",";
|
order_loop += final_line + ",";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topic_str.indexOf("order") > 0) {
|
if (topic_str.indexOf("order") > 0) {
|
||||||
str.replace("_", " ");
|
str.replace("_", " ");
|
||||||
//Serial.println(str);
|
//Serial.println(str);
|
||||||
order_loop += str + ",";
|
order_loop += str + ",";
|
||||||
}
|
}
|
||||||
if (topic_str.indexOf("update") > 0) {
|
if (topic_str.indexOf("update") > 0) {
|
||||||
if (str == "1") {
|
if (str == "1") {
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (topic_str.indexOf("devc") > 0) {
|
||||||
|
writeFile("firmware.c.txt", str);
|
||||||
|
Device_init();
|
||||||
|
}
|
||||||
|
if (topic_str.indexOf("devs") > 0) {
|
||||||
|
writeFile("firmware.s.txt", str);
|
||||||
|
Scenario_init();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (topic_str.indexOf("devc") > 0) {
|
|
||||||
writeFile("firmware.c.txt", str);
|
|
||||||
Device_init();
|
|
||||||
}
|
|
||||||
if (topic_str.indexOf("devs") > 0) {
|
|
||||||
writeFile("firmware.s.txt", str);
|
|
||||||
Scenario_init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//данные которые отправляем при подключении или отбновлении страницы
|
//данные которые отправляем при подключении или отбновлении страницы
|
||||||
void outcoming_date() {
|
void outcoming_date() {
|
||||||
|
sendAllWigets();
|
||||||
sendAllWigets();
|
sendAllData();
|
||||||
sendAllData();
|
|
||||||
|
|
||||||
#ifdef logging_enable
|
#ifdef logging_enable
|
||||||
choose_log_date_and_send();
|
choose_log_date_and_send();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Serial.println("[V] Sending all date to iot manager completed");
|
Serial.println("[V] Sending all date to iot manager completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//======================================CONFIG==================================================
|
//======================================CONFIG==================================================
|
||||||
boolean sendMQTT(String end_of_topik, String data) {
|
boolean sendMQTT(String end_of_topik, String data) {
|
||||||
String topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + end_of_topik;
|
String topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + end_of_topik;
|
||||||
boolean send_status = client_mqtt.beginPublish(topik.c_str(), data.length(), false);
|
boolean send_status = client_mqtt.beginPublish(topik.c_str(), data.length(), false);
|
||||||
client_mqtt.print(data);
|
client_mqtt.print(data);
|
||||||
client_mqtt.endPublish();
|
client_mqtt.endPublish();
|
||||||
return send_status;
|
return send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sendCHART(String topik, String data) {
|
boolean sendCHART(String topik, String data) {
|
||||||
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
||||||
boolean send_status = client_mqtt.beginPublish(topik.c_str(), data.length(), false);
|
boolean send_status = client_mqtt.beginPublish(topik.c_str(), data.length(), false);
|
||||||
client_mqtt.print(data);
|
client_mqtt.print(data);
|
||||||
client_mqtt.endPublish();
|
client_mqtt.endPublish();
|
||||||
return send_status;
|
return send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sendCHART_test(String topik, String data) {
|
boolean sendCHART_test(String topik, String data) {
|
||||||
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
||||||
boolean send_status = client_mqtt.publish (topik.c_str(), data.c_str(), false);
|
boolean send_status = client_mqtt.publish(topik.c_str(), data.c_str(), false);
|
||||||
return send_status;
|
return send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================STATUS==================================================
|
//======================================STATUS==================================================
|
||||||
void sendSTATUS(String topik, String state) {
|
void sendSTATUS(String topik, String state) {
|
||||||
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
topik = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipID + "/" + topik + "/" + "status";
|
||||||
String json_ = "{}";
|
String json_ = "{}";
|
||||||
jsonWriteStr(json_, "status", state);
|
jsonWriteStr(json_, "status", state);
|
||||||
client_mqtt.publish (topik.c_str(), json_.c_str(), false);
|
client_mqtt.publish(topik.c_str(), json_.c_str(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================CONTROL==================================================
|
//======================================CONTROL==================================================
|
||||||
void sendCONTROL(String id, String topik, String state) {
|
void sendCONTROL(String id, String topik, String state) {
|
||||||
String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/" + topik + "/control";
|
String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/" + topik + "/control";
|
||||||
client_mqtt.publish (all_line.c_str(), state.c_str(), false);
|
client_mqtt.publish(all_line.c_str(), state.c_str(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=====================================================ОТПРАВЛЯЕМ ВИДЖЕТЫ========================================================
|
//=====================================================ОТПРАВЛЯЕМ ВИДЖЕТЫ========================================================
|
||||||
|
|
||||||
#ifdef layout_in_ram
|
#ifdef layout_in_ram
|
||||||
void sendAllWigets() {
|
void sendAllWigets() {
|
||||||
if (all_widgets != "") {
|
if (all_widgets != "") {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
String line;
|
String line;
|
||||||
int psn_1 = 0;
|
int psn_1 = 0;
|
||||||
int psn_2;
|
int psn_2;
|
||||||
do {
|
do {
|
||||||
psn_2 = all_widgets.indexOf("\r\n", psn_1); //\r\n
|
psn_2 = all_widgets.indexOf("\r\n", psn_1); //\r\n
|
||||||
line = all_widgets.substring(psn_1, psn_2);
|
line = all_widgets.substring(psn_1, psn_2);
|
||||||
line.replace("\n", "");
|
line.replace("\n", "");
|
||||||
line.replace("\r\n", "");
|
line.replace("\r\n", "");
|
||||||
//jsonWriteStr(line, "id", String(counter));
|
//jsonWriteStr(line, "id", String(counter));
|
||||||
//jsonWriteStr(line, "pageId", String(counter));
|
//jsonWriteStr(line, "pageId", String(counter));
|
||||||
counter++;
|
counter++;
|
||||||
sendMQTT("config", line);
|
sendMQTT("config", line);
|
||||||
Serial.println("[V] " + line);
|
Serial.println("[V] " + line);
|
||||||
psn_1 = psn_2 + 1;
|
psn_1 = psn_2 + 1;
|
||||||
} while (psn_2 + 2 < all_widgets.length());
|
} while (psn_2 + 2 < all_widgets.length());
|
||||||
getMemoryLoad("[i] after send all widgets");
|
getMemoryLoad("[i] after send all widgets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef layout_in_ram
|
#ifndef layout_in_ram
|
||||||
void sendAllWigets() {
|
void sendAllWigets() {
|
||||||
File configFile = SPIFFS.open("/layout.txt", "r");
|
File configFile = SPIFFS.open("/layout.txt", "r");
|
||||||
if (!configFile) {
|
if (!configFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
configFile.seek(0, SeekSet); //поставим курсор в начало файла
|
configFile.seek(0, SeekSet); //поставим курсор в начало файла
|
||||||
while (configFile.position() != configFile.size()) {
|
while (configFile.position() != configFile.size()) {
|
||||||
String widget_to_send = configFile.readStringUntil('\n');
|
String widget_to_send = configFile.readStringUntil('\n');
|
||||||
Serial.println("[V] " + widget_to_send);
|
Serial.println("[V] " + widget_to_send);
|
||||||
sendMQTT("config", widget_to_send);
|
sendMQTT("config", widget_to_send);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//=====================================================ОТПРАВЛЯЕМ ДАННЫЕ В ВИДЖЕТЫ ПРИ ОБНОВЛЕНИИ СТРАНИЦЫ========================================================
|
//=====================================================ОТПРАВЛЯЕМ ДАННЫЕ В ВИДЖЕТЫ ПРИ ОБНОВЛЕНИИ СТРАНИЦЫ========================================================
|
||||||
void sendAllData() { //берет строку json и ключи превращает в топики а значения колючей в них посылает
|
void sendAllData() { //берет строку json и ключи превращает в топики а значения колючей в них посылает
|
||||||
|
|
||||||
String current_config = configLiveJson; //{"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"}
|
String current_config = configLiveJson; //{"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"}
|
||||||
getMemoryLoad("[i] after send all date");
|
getMemoryLoad("[i] after send all date");
|
||||||
current_config.replace("{", "");
|
current_config.replace("{", "");
|
||||||
current_config.replace("}", ""); //"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"
|
current_config.replace("}", ""); //"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"
|
||||||
current_config += ","; //"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1",
|
current_config += ","; //"name":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1",
|
||||||
|
|
||||||
while (current_config.length() != 0) {
|
while (current_config.length() != 0) {
|
||||||
|
String tmp = selectToMarker(current_config, ",");
|
||||||
String tmp = selectToMarker (current_config, ",");
|
String topic = selectToMarker(tmp, ":");
|
||||||
String topic = selectToMarker (tmp, ":");
|
topic.replace("\"", "");
|
||||||
topic.replace("\"", "");
|
String state = selectToMarkerLast(tmp, ":");
|
||||||
String state = selectToMarkerLast (tmp, ":");
|
state.replace("\"", "");
|
||||||
state.replace("\"", "");
|
if (topic != "name" && topic != "lang" && topic != "ip" && topic.indexOf("_in") < 0) {
|
||||||
if (topic != "name" && topic != "lang" && topic != "ip" && topic.indexOf("_in") < 0) {
|
sendSTATUS(topic, state);
|
||||||
sendSTATUS(topic, state);
|
//Serial.println("-->" + topic + " " + state);
|
||||||
//Serial.println("-->" + topic + " " + state);
|
}
|
||||||
|
current_config = deleteBeforeDelimiter(current_config, ",");
|
||||||
}
|
}
|
||||||
current_config = deleteBeforeDelimiter(current_config, ",");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String stateMQTT() {
|
String stateMQTT() {
|
||||||
int state = client_mqtt.state();
|
int state = client_mqtt.state();
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
void Push_init() {
|
void Push_init() {
|
||||||
@@ -14,7 +12,7 @@ void Push_init() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pushControl() {
|
void pushControl() {
|
||||||
String title = sCmd.next();
|
String title = sCmd.next();
|
||||||
title.replace("#", " ");
|
title.replace("#", " ");
|
||||||
String body = sCmd.next();
|
String body = sCmd.next();
|
||||||
140
src/Sensors.cpp
140
src/Sensors.cpp
@@ -1,5 +1,17 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "StringUtils.h"
|
|
||||||
|
OneWire *oneWire;
|
||||||
|
GMedian<10, int> medianFilter;
|
||||||
|
DHTesp dht;
|
||||||
|
|
||||||
|
Adafruit_BMP280 bmp;
|
||||||
|
Adafruit_Sensor *bmp_temp;
|
||||||
|
Adafruit_Sensor *bmp_pressure;
|
||||||
|
|
||||||
|
Adafruit_BME280 bme;
|
||||||
|
Adafruit_Sensor *bme_temp;
|
||||||
|
Adafruit_Sensor *bme_pressure;
|
||||||
|
Adafruit_Sensor *bme_humidity;
|
||||||
|
|
||||||
String perception(byte value);
|
String perception(byte value);
|
||||||
void bmp280T_reading();
|
void bmp280T_reading();
|
||||||
@@ -71,77 +83,77 @@ void sensors_init() {
|
|||||||
#ifdef level_enable
|
#ifdef level_enable
|
||||||
//levelPr p 14 12 Вода#в#баке,#% Датчики fill-gauge 125 20 1
|
//levelPr p 14 12 Вода#в#баке,#% Датчики fill-gauge 125 20 1
|
||||||
void levelPr() {
|
void levelPr() {
|
||||||
String value_name = sCmd.next();
|
String value_name = sCmd.next();
|
||||||
String trig = sCmd.next();
|
String trig = sCmd.next();
|
||||||
String echo = sCmd.next();
|
String echo = sCmd.next();
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
String type = sCmd.next();
|
String type = sCmd.next();
|
||||||
String empty_level = sCmd.next();
|
String empty_level = sCmd.next();
|
||||||
String full_level = sCmd.next();
|
String full_level = sCmd.next();
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
levelPr_value_name = value_name;
|
levelPr_value_name = value_name;
|
||||||
jsonWriteStr(configOptionJson, "e_lev", empty_level);
|
jsonWriteStr(configOptionJson, "e_lev", empty_level);
|
||||||
jsonWriteStr(configOptionJson, "f_lev", full_level);
|
jsonWriteStr(configOptionJson, "f_lev", full_level);
|
||||||
jsonWriteStr(configOptionJson, "trig", trig);
|
jsonWriteStr(configOptionJson, "trig", trig);
|
||||||
jsonWriteStr(configOptionJson, "echo", echo);
|
jsonWriteStr(configOptionJson, "echo", echo);
|
||||||
pinMode(trig.toInt(), OUTPUT);
|
pinMode(trig.toInt(), OUTPUT);
|
||||||
pinMode(echo.toInt(), INPUT);
|
pinMode(echo.toInt(), INPUT);
|
||||||
choose_widget_and_create(widget_name, page_name, page_number, type, value_name);
|
choose_widget_and_create(widget_name, page_name, page_number, type, value_name);
|
||||||
sensors_reading_map[0] = 1;
|
sensors_reading_map[0] = 1;
|
||||||
}
|
}
|
||||||
//ultrasonicCm cm 14 12 Дистанция,#см Датчики fill-gauge 1
|
//ultrasonicCm cm 14 12 Дистанция,#см Датчики fill-gauge 1
|
||||||
void ultrasonicCm() {
|
void ultrasonicCm() {
|
||||||
String value_name = sCmd.next();
|
String value_name = sCmd.next();
|
||||||
String trig = sCmd.next();
|
String trig = sCmd.next();
|
||||||
String echo = sCmd.next();
|
String echo = sCmd.next();
|
||||||
String widget_name = sCmd.next();
|
String widget_name = sCmd.next();
|
||||||
String page_name = sCmd.next();
|
String page_name = sCmd.next();
|
||||||
String type = sCmd.next();
|
String type = sCmd.next();
|
||||||
String empty_level = sCmd.next();
|
String empty_level = sCmd.next();
|
||||||
String full_level = sCmd.next();
|
String full_level = sCmd.next();
|
||||||
String page_number = sCmd.next();
|
String page_number = sCmd.next();
|
||||||
ultrasonicCm_value_name = value_name;
|
ultrasonicCm_value_name = value_name;
|
||||||
jsonWriteStr(configOptionJson, "trig", trig);
|
jsonWriteStr(configOptionJson, "trig", trig);
|
||||||
jsonWriteStr(configOptionJson, "echo", echo);
|
jsonWriteStr(configOptionJson, "echo", echo);
|
||||||
pinMode(trig.toInt(), OUTPUT);
|
pinMode(trig.toInt(), OUTPUT);
|
||||||
pinMode(echo.toInt(), INPUT);
|
pinMode(echo.toInt(), INPUT);
|
||||||
choose_widget_and_create(widget_name, page_name, page_number, type, value_name);
|
choose_widget_and_create(widget_name, page_name, page_number, type, value_name);
|
||||||
sensors_reading_map[0] = 1;
|
sensors_reading_map[0] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultrasonic_reading() {
|
void ultrasonic_reading() {
|
||||||
long duration_;
|
long duration_;
|
||||||
int distance_cm;
|
int distance_cm;
|
||||||
int level;
|
int level;
|
||||||
static int counter;
|
static int counter;
|
||||||
int trig = jsonReadInt(configOptionJson, "trig");
|
int trig = jsonReadInt(configOptionJson, "trig");
|
||||||
int echo = jsonReadInt(configOptionJson, "echo");
|
int echo = jsonReadInt(configOptionJson, "echo");
|
||||||
digitalWrite(trig, LOW);
|
digitalWrite(trig, LOW);
|
||||||
delayMicroseconds(2);
|
delayMicroseconds(2);
|
||||||
digitalWrite(trig, HIGH);
|
digitalWrite(trig, HIGH);
|
||||||
delayMicroseconds(10);
|
delayMicroseconds(10);
|
||||||
digitalWrite(trig, LOW);
|
digitalWrite(trig, LOW);
|
||||||
duration_ = pulseIn(echo, HIGH, 30000); // 3000 µs = 50cm // 30000 µs = 5 m
|
duration_ = pulseIn(echo, HIGH, 30000); // 3000 µs = 50cm // 30000 µs = 5 m
|
||||||
distance_cm = duration_ / 29 / 2;
|
distance_cm = duration_ / 29 / 2;
|
||||||
distance_cm = medianFilter.filtered(distance_cm);//отсечение промахов медианным фильтром
|
distance_cm = medianFilter.filtered(distance_cm); //отсечение промахов медианным фильтром
|
||||||
counter++;
|
counter++;
|
||||||
if (counter > tank_level_times_to_send) {
|
if (counter > tank_level_times_to_send) {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
level = map(distance_cm,
|
level = map(distance_cm,
|
||||||
jsonReadInt(configOptionJson, "e_lev"),
|
jsonReadInt(configOptionJson, "e_lev"),
|
||||||
jsonReadInt(configOptionJson, "f_lev"), 0, 100);
|
jsonReadInt(configOptionJson, "f_lev"), 0, 100);
|
||||||
|
|
||||||
jsonWriteInt(configLiveJson, levelPr_value_name, level);
|
jsonWriteInt(configLiveJson, levelPr_value_name, level);
|
||||||
eventGen (levelPr_value_name, "");
|
eventGen(levelPr_value_name, "");
|
||||||
sendSTATUS(levelPr_value_name, String(level));
|
sendSTATUS(levelPr_value_name, String(level));
|
||||||
Serial.println("[i] sensor '" + levelPr_value_name + "' data: " + String(level));
|
Serial.println("[i] sensor '" + levelPr_value_name + "' data: " + String(level));
|
||||||
|
|
||||||
jsonWriteInt(configLiveJson, ultrasonicCm_value_name, distance_cm);
|
jsonWriteInt(configLiveJson, ultrasonicCm_value_name, distance_cm);
|
||||||
eventGen (ultrasonicCm_value_name, "");
|
eventGen(ultrasonicCm_value_name, "");
|
||||||
sendSTATUS(ultrasonicCm_value_name, String(distance_cm));
|
sendSTATUS(ultrasonicCm_value_name, String(distance_cm));
|
||||||
Serial.println("[i] sensor '" + ultrasonicCm_value_name + "' data: " + String(distance_cm));
|
Serial.println("[i] sensor '" + ultrasonicCm_value_name + "' data: " + String(distance_cm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//=========================================================================================================================================
|
//=========================================================================================================================================
|
||||||
|
|||||||
@@ -1,133 +0,0 @@
|
|||||||
#include "Global.h"
|
|
||||||
|
|
||||||
void Time_Init() {
|
|
||||||
ts.add(TIME_SYNC, 30000, [&](void*) {
|
|
||||||
time_check();
|
|
||||||
}, nullptr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void time_check() {
|
|
||||||
if (GetTimeUnix() == "failed") {
|
|
||||||
Serial.println("[i] Time is not synchronized, start synchronization");
|
|
||||||
reconfigTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void reconfigTime() {
|
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
|
||||||
String ntp = jsonReadStr(configSetupJson, "ntp");
|
|
||||||
configTime(0, 0, ntp.c_str());
|
|
||||||
int i = 0;
|
|
||||||
Serial.println("[i] Awaiting for time ");
|
|
||||||
#ifdef ESP32
|
|
||||||
struct tm timeinfo;
|
|
||||||
while (!getLocalTime(&timeinfo) && i <= 4) {
|
|
||||||
Serial.print(".");
|
|
||||||
i++;
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef ESP8266
|
|
||||||
//while (!time(nullptr) && i < 4) {
|
|
||||||
// Serial.print(".");
|
|
||||||
// i++;
|
|
||||||
delay(2000);
|
|
||||||
//}
|
|
||||||
#endif
|
|
||||||
if (GetTimeUnix() != "failed") {
|
|
||||||
Serial.print("[V] Time synchronized = ");
|
|
||||||
Serial.print(GetDataDigital());
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.println(GetTime());
|
|
||||||
} else {
|
|
||||||
Serial.println("[E] Time server or internet connection error, will try again in 30 sec");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Serial.println("[E] Get time impossible, no wifi connection");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Получаем время в формате linux gmt
|
|
||||||
String GetTimeUnix() {
|
|
||||||
time_t now = time(nullptr);
|
|
||||||
if (now < 30000) {
|
|
||||||
return "failed";
|
|
||||||
} else {
|
|
||||||
return String(now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Получение текущего времени
|
|
||||||
String GetTime() {
|
|
||||||
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
|
||||||
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
|
||||||
now = now + zone;
|
|
||||||
String Time = ""; // Строка для результатов времени
|
|
||||||
Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
|
||||||
int i = Time.indexOf(":"); //Ишем позицию первого символа :
|
|
||||||
Time = Time.substring(i - 2, i + 6); // Выделяем из строки 2 символа перед символом : и 6 символов после
|
|
||||||
return Time; // Возврашаем полученное время
|
|
||||||
}
|
|
||||||
|
|
||||||
String GetTimeWOsec() {
|
|
||||||
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
|
||||||
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
|
||||||
now = now + zone;
|
|
||||||
String Time = ""; // Строка для результатов времени
|
|
||||||
Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
|
||||||
int i = Time.indexOf(":"); //Ишем позицию первого символа :
|
|
||||||
Time = Time.substring(i - 2, i + 3); // Выделяем из строки 2 символа перед символом : и 6 символов после
|
|
||||||
return Time; // Возврашаем полученное время
|
|
||||||
}
|
|
||||||
|
|
||||||
// Получение даты
|
|
||||||
String GetDate() {
|
|
||||||
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
|
||||||
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
|
||||||
now = now + zone;
|
|
||||||
String Data = ""; // Строка для результатов времени
|
|
||||||
Data += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
|
||||||
Data.replace("\n", "");
|
|
||||||
uint8_t i = Data.lastIndexOf(" "); //Ишем позицию последнего символа пробел
|
|
||||||
String Time = Data.substring(i - 8, i + 1); // Выделяем время и пробел
|
|
||||||
Data.replace(Time, ""); // Удаляем из строки 8 символов времени и пробел
|
|
||||||
return Data; // Возврашаем полученную дату
|
|
||||||
}
|
|
||||||
|
|
||||||
String GetDataDigital() {
|
|
||||||
String date = GetDate();
|
|
||||||
|
|
||||||
date = deleteBeforeDelimiter(date, " ");
|
|
||||||
|
|
||||||
date.replace("Jan", "01");
|
|
||||||
date.replace("Feb", "02");
|
|
||||||
date.replace("Mar", "03");
|
|
||||||
date.replace("Apr", "04");
|
|
||||||
date.replace("May", "05");
|
|
||||||
date.replace("Jun", "06");
|
|
||||||
date.replace("Jul", "07");
|
|
||||||
date.replace("Aug", "08");
|
|
||||||
date.replace("Sep", "09");
|
|
||||||
date.replace("Oct", "10");
|
|
||||||
date.replace("Nov", "11");
|
|
||||||
date.replace("Dec", "12");
|
|
||||||
|
|
||||||
String month = date.substring(0, 2);
|
|
||||||
String day = date.substring(3, 5);
|
|
||||||
String year = date.substring(8, 10);
|
|
||||||
|
|
||||||
String out = day;
|
|
||||||
out += ".";
|
|
||||||
out += month;
|
|
||||||
out += ".";
|
|
||||||
out += year;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int timeToMin(String Time) {
|
|
||||||
//"00:00:00" время в секунды
|
|
||||||
long min = selectToMarker(Time, ":").toInt() * 60; //общее количество секунд в полных часах
|
|
||||||
Time = deleteBeforeDelimiter (Time, ":"); // Теперь здесь минуты секунды
|
|
||||||
min += selectToMarker(Time, ":").toInt(); // Добавим секунды из полных минут
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#include "Utils\JsonUtils.h"
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
String jsonReadStr(String& json, String name) {
|
String jsonReadStr(String& json, String name) {
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
#pragma once
|
#include "Utils\StringUtils.h"
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
String selectToMarkerLast(String str, String found) {
|
String selectToMarkerLast(String str, String found) {
|
||||||
int p = str.lastIndexOf(found);
|
int p = str.lastIndexOf(found);
|
||||||
@@ -49,14 +47,14 @@ String selectFromMarkerToMarker(String str, String found, int number) {
|
|||||||
return "not found"; // Достигли пустой строки и ничего не нашли
|
return "not found"; // Достигли пустой строки и ничего не нашли
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t hexStringToUint8(String hex) {
|
uint8_t hexStringToUint8(String hex) {
|
||||||
uint8_t tmp = strtol(hex.c_str(), NULL, 0);
|
uint8_t tmp = strtol(hex.c_str(), NULL, 0);
|
||||||
if (tmp >= 0x00 && tmp <= 0xFF) {
|
if (tmp >= 0x00 && tmp <= 0xFF) {
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t hexStringToUint16(String hex) {
|
uint16_t hexStringToUint16(String hex) {
|
||||||
uint16_t tmp = strtol(hex.c_str(), NULL, 0);
|
uint16_t tmp = strtol(hex.c_str(), NULL, 0);
|
||||||
if (tmp >= 0x0000 && tmp <= 0xFFFF) {
|
if (tmp >= 0x0000 && tmp <= 0xFFFF) {
|
||||||
return tmp;
|
return tmp;
|
||||||
165
src/Utils/TimeUtils.cpp
Normal file
165
src/Utils/TimeUtils.cpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#include "Utils\TimeUtils.h"
|
||||||
|
|
||||||
|
#include "Global.h"
|
||||||
|
#include "Utils\StringUtils.h"
|
||||||
|
|
||||||
|
static const char* TIME_FORMAT PROGMEM = "%2d:%2d:%2d";
|
||||||
|
static const char* TIME_FORMAT_WITH_DAYS PROGMEM = "%dd %2d:%2d";
|
||||||
|
|
||||||
|
void Time_Init() {
|
||||||
|
ts.add(
|
||||||
|
TIME_SYNC, 30000, [&](void*) {
|
||||||
|
time_check();
|
||||||
|
},
|
||||||
|
nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String prettyMillis(unsigned long time_ms) {
|
||||||
|
unsigned long tmp = time_ms;
|
||||||
|
unsigned long seconds;
|
||||||
|
unsigned long minutes;
|
||||||
|
unsigned long hours;
|
||||||
|
unsigned long days;
|
||||||
|
seconds = tmp % 60;
|
||||||
|
tmp = tmp / 60;
|
||||||
|
|
||||||
|
minutes = tmp % 60;
|
||||||
|
tmp = tmp / 60;
|
||||||
|
hours = tmp % 24;
|
||||||
|
days = tmp / 24;
|
||||||
|
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
sprintf_P(buf, TIME_FORMAT, hours, minutes, seconds);
|
||||||
|
} else {
|
||||||
|
sprintf_P(buf, TIME_FORMAT_WITH_DAYS, days, hours, minutes);
|
||||||
|
}
|
||||||
|
return String(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void time_check() {
|
||||||
|
if (GetTimeUnix() == "failed") {
|
||||||
|
Serial.println("[i] Time is not synchronized, start synchronization");
|
||||||
|
reconfigTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reconfigTime() {
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
String ntp = jsonReadStr(configSetupJson, "ntp");
|
||||||
|
configTime(0, 0, ntp.c_str());
|
||||||
|
int i = 0;
|
||||||
|
Serial.println("[i] Awaiting for time ");
|
||||||
|
#ifdef ESP32
|
||||||
|
struct tm timeinfo;
|
||||||
|
while (!getLocalTime(&timeinfo) && i <= 4) {
|
||||||
|
Serial.print(".");
|
||||||
|
i++;
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ESP8266
|
||||||
|
//while (!time(nullptr) && i < 4) {
|
||||||
|
// Serial.print(".");
|
||||||
|
// i++;
|
||||||
|
delay(2000);
|
||||||
|
//}
|
||||||
|
#endif
|
||||||
|
if (GetTimeUnix() != "failed") {
|
||||||
|
Serial.print("[V] Time synchronized = ");
|
||||||
|
Serial.print(GetDataDigital());
|
||||||
|
Serial.print(" ");
|
||||||
|
Serial.println(GetTime());
|
||||||
|
} else {
|
||||||
|
Serial.println("[E] Time server or internet connection error, will try again in 30 sec");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("[E] Get time impossible, no wifi connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Получаем время в формате linux gmt
|
||||||
|
String GetTimeUnix() {
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
if (now < 30000) {
|
||||||
|
return "failed";
|
||||||
|
} else {
|
||||||
|
return String(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetTime() {
|
||||||
|
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
||||||
|
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
||||||
|
now = now + zone;
|
||||||
|
String Time = ""; // Строка для результатов времени
|
||||||
|
Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
||||||
|
int i = Time.indexOf(":"); //Ишем позицию первого символа :
|
||||||
|
Time = Time.substring(i - 2, i + 6); // Выделяем из строки 2 символа перед символом : и 6 символов после
|
||||||
|
return Time; // Возврашаем полученное время
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetTimeWOsec() {
|
||||||
|
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
||||||
|
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
||||||
|
now = now + zone;
|
||||||
|
String Time = ""; // Строка для результатов времени
|
||||||
|
Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
||||||
|
int i = Time.indexOf(":"); //Ишем позицию первого символа :
|
||||||
|
Time = Time.substring(i - 2, i + 3); // Выделяем из строки 2 символа перед символом : и 6 символов после
|
||||||
|
return Time; // Возврашаем полученное время
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение даты
|
||||||
|
String GetDate() {
|
||||||
|
time_t now = time(nullptr); // получаем время с помощью библиотеки time.h
|
||||||
|
int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt();
|
||||||
|
now = now + zone;
|
||||||
|
String Data = ""; // Строка для результатов времени
|
||||||
|
Data += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017
|
||||||
|
Data.replace("\n", "");
|
||||||
|
uint8_t i = Data.lastIndexOf(" "); //Ишем позицию последнего символа пробел
|
||||||
|
String Time = Data.substring(i - 8, i + 1); // Выделяем время и пробел
|
||||||
|
Data.replace(Time, ""); // Удаляем из строки 8 символов времени и пробел
|
||||||
|
return Data; // Возврашаем полученную дату
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetDataDigital() {
|
||||||
|
String date = GetDate();
|
||||||
|
|
||||||
|
date = deleteBeforeDelimiter(date, " ");
|
||||||
|
|
||||||
|
date.replace("Jan", "01");
|
||||||
|
date.replace("Feb", "02");
|
||||||
|
date.replace("Mar", "03");
|
||||||
|
date.replace("Apr", "04");
|
||||||
|
date.replace("May", "05");
|
||||||
|
date.replace("Jun", "06");
|
||||||
|
date.replace("Jul", "07");
|
||||||
|
date.replace("Aug", "08");
|
||||||
|
date.replace("Sep", "09");
|
||||||
|
date.replace("Oct", "10");
|
||||||
|
date.replace("Nov", "11");
|
||||||
|
date.replace("Dec", "12");
|
||||||
|
|
||||||
|
String month = date.substring(0, 2);
|
||||||
|
String day = date.substring(3, 5);
|
||||||
|
String year = date.substring(8, 10);
|
||||||
|
|
||||||
|
String out = day;
|
||||||
|
out += ".";
|
||||||
|
out += month;
|
||||||
|
out += ".";
|
||||||
|
out += year;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timeToMin(String Time) {
|
||||||
|
//"00:00:00" время в секунды
|
||||||
|
long min = selectToMarker(Time, ":").toInt() * 60; //общее количество секунд в полных часах
|
||||||
|
Time = deleteBeforeDelimiter(Time, ":"); // Теперь здесь минуты секунды
|
||||||
|
min += selectToMarker(Time, ":").toInt(); // Добавим секунды из полных минут
|
||||||
|
return min;
|
||||||
|
}
|
||||||
@@ -1,84 +1,83 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
void not_async_actions();
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
File_system_init();
|
File_system_init();
|
||||||
Serial.println("SPIFFS_init");
|
Serial.println("SPIFFS_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
CMD_init();
|
CMD_init();
|
||||||
Serial.println("[V] CMD_init");
|
Serial.println("[V] CMD_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
sensors_init();
|
sensors_init();
|
||||||
Serial.println("[V] sensors_init");
|
Serial.println("[V] sensors_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
All_init();
|
All_init();
|
||||||
Serial.println("[V] All_init");
|
Serial.println("[V] All_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
ROUTER_Connecting();
|
ROUTER_Connecting();
|
||||||
Serial.println("[V] ROUTER_Connecting");
|
Serial.println("[V] ROUTER_Connecting");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
uptime_init();
|
uptime_init();
|
||||||
Serial.println("[V] statistics_init");
|
Serial.println("[V] statistics_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
initUpgrade();
|
initUpgrade();
|
||||||
Serial.println("[V] initUpgrade");
|
Serial.println("[V] initUpgrade");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
Web_server_init();
|
Web_server_init();
|
||||||
Serial.println("[V] Web_server_init");
|
Serial.println("[V] Web_server_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
web_init();
|
web_init();
|
||||||
Serial.println("[V] web_init");
|
Serial.println("[V] web_init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
Time_Init();
|
Time_Init();
|
||||||
Serial.println("[V] Time_Init");
|
Serial.println("[V] Time_Init");
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
#ifdef UDP_enable
|
#ifdef UDP_enable
|
||||||
UDP_init();
|
UDP_init();
|
||||||
Serial.println("[V] UDP_init");
|
Serial.println("[V] UDP_init");
|
||||||
#endif
|
#endif
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
|
|
||||||
|
ts.add(
|
||||||
|
TEST, 10000, [&](void*) {
|
||||||
|
getMemoryLoad("[i] periodic check of");
|
||||||
|
//ws.textAll(json);
|
||||||
|
},
|
||||||
|
nullptr, true);
|
||||||
|
|
||||||
|
just_load = false;
|
||||||
ts.add(TEST, 10000, [&](void*) {
|
|
||||||
getMemoryLoad("[i] periodic check of");
|
|
||||||
//ws.textAll(json);
|
|
||||||
}, nullptr, true);
|
|
||||||
|
|
||||||
|
|
||||||
just_load = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
#ifdef OTA_enable
|
#ifdef OTA_enable
|
||||||
ArduinoOTA.handle();
|
ArduinoOTA.handle();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WS_enable
|
#ifdef WS_enable
|
||||||
ws.cleanupClients();
|
ws.cleanupClients();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
not_async_actions();
|
not_async_actions();
|
||||||
|
|
||||||
handleMQTT();
|
handleMQTT();
|
||||||
handleCMD_loop();
|
handleCMD_loop();
|
||||||
handleButton();
|
handleButton();
|
||||||
handleScenario();
|
handleScenario();
|
||||||
#ifdef UDP_enable
|
#ifdef UDP_enable
|
||||||
handleUdp();
|
handleUdp();
|
||||||
#endif
|
#endif
|
||||||
ts.update();
|
ts.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void not_async_actions() {
|
void not_async_actions() {
|
||||||
do_mqtt_connection();
|
do_mqtt_connection();
|
||||||
do_upgrade_url();
|
do_upgrade_url();
|
||||||
do_upgrade();
|
do_upgrade();
|
||||||
#ifdef UDP_enable
|
#ifdef UDP_enable
|
||||||
do_udp_data_parse();
|
do_udp_data_parse();
|
||||||
do_mqtt_send_settings_to_udp();
|
do_mqtt_send_settings_to_udp();
|
||||||
#endif
|
#endif
|
||||||
do_i2c_scanning();
|
do_i2c_scanning();
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ int count(String str, String found) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isDigitStr(String str) {
|
boolean isDigitStr(String str) {
|
||||||
for (int i = 0; i < str.length(); i++) {
|
for (size_t i = 0; i < str.length(); i++) {
|
||||||
if (!isDigit(str.charAt(i))) {
|
if (!isDigit(str.charAt(i))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
212
src/udp.cpp
212
src/udp.cpp
@@ -1,149 +1,163 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
IPAddress udp_multicastIP(255, 255, 255, 255);
|
||||||
|
ESP8266HTTPUpdateServer httpUpdater;
|
||||||
|
WiFiUDP Udp;
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
IPAddress udp_multicastIP(239, 255, 255, 255);
|
||||||
|
AsyncUDP udp;
|
||||||
|
#endif
|
||||||
|
String received_ip;
|
||||||
|
String received_udp_line;
|
||||||
|
int udp_period;
|
||||||
|
boolean udp_busy = false;
|
||||||
|
unsigned int udp_port = 4210;
|
||||||
|
|
||||||
void handleUdp_esp32();
|
void handleUdp_esp32();
|
||||||
void add_dev_in_list(String fileName, String id, String dev_name, String ip);
|
void add_dev_in_list(String fileName, String id, String dev_name, String ip);
|
||||||
|
|
||||||
#ifdef UDP_enable
|
#ifdef UDP_enable
|
||||||
void UDP_init() {
|
void UDP_init() {
|
||||||
|
SPIFFS.remove("/dev.csv");
|
||||||
SPIFFS.remove("/dev.csv");
|
addFile("dev.csv", "device id;device name;ip address");
|
||||||
addFile("dev.csv", "device id;device name;ip address");
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
Udp.begin(udp_port);
|
Udp.begin(udp_port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
handleUdp_esp32();
|
handleUdp_esp32();
|
||||||
|
|
||||||
randomSeed(micros());
|
randomSeed(micros());
|
||||||
udp_period = random(50000, 60000);
|
udp_period = random(50000, 60000);
|
||||||
|
|
||||||
ts.add(UDP, udp_period, [&](void*) {
|
ts.add(
|
||||||
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
UDP, udp_period, [&](void*) {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
||||||
if (!udp_busy) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
String line_to_send = "iotm;" + chipID + ";" + jsonReadStr(configSetupJson, "name");
|
if (!udp_busy) {
|
||||||
|
String line_to_send = "iotm;" + chipID + ";" + jsonReadStr(configSetupJson, "name");
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
|
Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
|
||||||
Udp.write(line_to_send.c_str());
|
Udp.write(line_to_send.c_str());
|
||||||
Udp.endPacket();
|
Udp.endPacket();
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
udp.broadcast(line_to_send.c_str());
|
udp.broadcast(line_to_send.c_str());
|
||||||
#endif
|
#endif
|
||||||
Serial.println("[UDP<=] dev info send");
|
Serial.println("[UDP<=] dev info send");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, nullptr, false);
|
},
|
||||||
|
nullptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUdp() {
|
void handleUdp() {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
int packetSize = Udp.parsePacket();
|
int packetSize = Udp.parsePacket();
|
||||||
if (packetSize) {
|
if (packetSize) {
|
||||||
char udp_incomingPacket[255];
|
char udp_incomingPacket[255];
|
||||||
Serial.printf("[UDP=>] Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
|
Serial.printf("[UDP=>] Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
|
||||||
received_ip = Udp.remoteIP().toString();
|
received_ip = Udp.remoteIP().toString();
|
||||||
int len = Udp.read(udp_incomingPacket, 255);
|
int len = Udp.read(udp_incomingPacket, 255);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
udp_incomingPacket[len] = 0;
|
udp_incomingPacket[len] = 0;
|
||||||
}
|
}
|
||||||
received_udp_line = String(udp_incomingPacket);
|
received_udp_line = String(udp_incomingPacket);
|
||||||
|
|
||||||
if (received_udp_line.indexOf("iotm;") >= 0) {
|
if (received_udp_line.indexOf("iotm;") >= 0) {
|
||||||
udp_data_parse = true;
|
udp_data_parse = true;
|
||||||
|
}
|
||||||
|
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
||||||
|
udp_data_parse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
|
||||||
udp_data_parse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUdp_esp32() {
|
void handleUdp_esp32() {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
if (udp.listenMulticast(udp_multicastIP, udp_port)) {
|
if (udp.listenMulticast(udp_multicastIP, udp_port)) {
|
||||||
udp.onPacket([](AsyncUDPPacket packet) {
|
udp.onPacket([](AsyncUDPPacket packet) {
|
||||||
received_udp_line = (char*)packet.data();
|
received_udp_line = (char*)packet.data();
|
||||||
received_ip = packet.remoteIP().toString();
|
received_ip = packet.remoteIP().toString();
|
||||||
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
||||||
|
if (received_udp_line.indexOf("iotm;") >= 0) {
|
||||||
if (received_udp_line.indexOf("iotm;") >= 0) {
|
udp_data_parse = true;
|
||||||
udp_data_parse = true;
|
}
|
||||||
}
|
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
||||||
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
udp_data_parse = true;
|
||||||
udp_data_parse = true;
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_udp_data_parse() {
|
void do_udp_data_parse() {
|
||||||
if (udp_data_parse) {
|
if (udp_data_parse) {
|
||||||
udp_data_parse = false;
|
udp_data_parse = false;
|
||||||
Serial.print("[UDP=>] " + received_ip);
|
Serial.print("[UDP=>] " + received_ip);
|
||||||
Serial.print(" ");
|
Serial.print(" ");
|
||||||
Serial.println(received_udp_line);
|
Serial.println(received_udp_line);
|
||||||
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
if (received_udp_line.indexOf("mqttServer") >= 0) {
|
||||||
jsonWriteStr(configSetupJson, "mqttServer", jsonReadStr(received_udp_line, "mqttServer"));
|
jsonWriteStr(configSetupJson, "mqttServer", jsonReadStr(received_udp_line, "mqttServer"));
|
||||||
jsonWriteInt(configSetupJson, "mqttPort", jsonReadInt(received_udp_line, "mqttPort"));
|
jsonWriteInt(configSetupJson, "mqttPort", jsonReadInt(received_udp_line, "mqttPort"));
|
||||||
jsonWriteStr(configSetupJson, "mqttPrefix", jsonReadStr(received_udp_line, "mqttPrefix"));
|
jsonWriteStr(configSetupJson, "mqttPrefix", jsonReadStr(received_udp_line, "mqttPrefix"));
|
||||||
jsonWriteStr(configSetupJson, "mqttUser", jsonReadStr(received_udp_line, "mqttUser"));
|
jsonWriteStr(configSetupJson, "mqttUser", jsonReadStr(received_udp_line, "mqttUser"));
|
||||||
jsonWriteStr(configSetupJson, "mqttPass", jsonReadStr(received_udp_line, "mqttPass"));
|
jsonWriteStr(configSetupJson, "mqttPass", jsonReadStr(received_udp_line, "mqttPass"));
|
||||||
saveConfig();
|
saveConfig();
|
||||||
Serial.println("[V] new mqtt setting received from udp and saved");
|
Serial.println("[V] new mqtt setting received from udp and saved");
|
||||||
mqtt_connection = true;
|
mqtt_connection = true;
|
||||||
|
}
|
||||||
|
if (received_udp_line.indexOf("iotm;") >= 0) {
|
||||||
|
add_dev_in_list("dev.csv", selectFromMarkerToMarker(received_udp_line, ";", 1), selectFromMarkerToMarker(received_udp_line, ";", 2), received_ip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (received_udp_line.indexOf("iotm;") >= 0) {
|
|
||||||
add_dev_in_list("dev.csv", selectFromMarkerToMarker(received_udp_line, ";", 1), selectFromMarkerToMarker(received_udp_line, ";", 2), received_ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_dev_in_list(String fileName, String id, String dev_name, String ip) {
|
void add_dev_in_list(String fileName, String id, String dev_name, String ip) {
|
||||||
File configFile = SPIFFS.open("/" + fileName, "r");
|
File configFile = SPIFFS.open("/" + fileName, "r");
|
||||||
if (!configFile.find(id.c_str())) {
|
if (!configFile.find(id.c_str())) {
|
||||||
addFile(fileName, id + ";" + dev_name + "; <a href=\"http://" + ip + "\" target=\"_blank\"\">" + ip + "</a>");
|
addFile(fileName, id + ";" + dev_name + "; <a href=\"http://" + ip + "\" target=\"_blank\"\">" + ip + "</a>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_mqtt_to_udp() {
|
void send_mqtt_to_udp() {
|
||||||
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
if (jsonReadStr(configSetupJson, "udponoff") == "1") {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
udp_busy = true;
|
udp_busy = true;
|
||||||
String mqtt_data = "{}";
|
String mqtt_data = "{}";
|
||||||
jsonWriteStr(mqtt_data, "mqttServer", jsonReadStr(configSetupJson, "mqttServer"));
|
jsonWriteStr(mqtt_data, "mqttServer", jsonReadStr(configSetupJson, "mqttServer"));
|
||||||
jsonWriteInt(mqtt_data, "mqttPort", jsonReadInt(configSetupJson, "mqttPort"));
|
jsonWriteInt(mqtt_data, "mqttPort", jsonReadInt(configSetupJson, "mqttPort"));
|
||||||
jsonWriteStr(mqtt_data, "mqttPrefix", jsonReadStr(configSetupJson, "mqttPrefix"));
|
jsonWriteStr(mqtt_data, "mqttPrefix", jsonReadStr(configSetupJson, "mqttPrefix"));
|
||||||
jsonWriteStr(mqtt_data, "mqttUser", jsonReadStr(configSetupJson, "mqttUser"));
|
jsonWriteStr(mqtt_data, "mqttUser", jsonReadStr(configSetupJson, "mqttUser"));
|
||||||
jsonWriteStr(mqtt_data, "mqttPass", jsonReadStr(configSetupJson, "mqttPass"));
|
jsonWriteStr(mqtt_data, "mqttPass", jsonReadStr(configSetupJson, "mqttPass"));
|
||||||
Serial.println(mqtt_data);
|
Serial.println(mqtt_data);
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
|
Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
|
||||||
Udp.write(mqtt_data.c_str());
|
Udp.write(mqtt_data.c_str());
|
||||||
Udp.endPacket();
|
Udp.endPacket();
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
udp.broadcast(mqtt_data.c_str());
|
udp.broadcast(mqtt_data.c_str());
|
||||||
#endif
|
#endif
|
||||||
Serial.println("[UDP<=] mqtt info send");
|
Serial.println("[UDP<=] mqtt info send");
|
||||||
udp_busy = false;
|
udp_busy = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_mqtt_send_settings_to_udp() {
|
void do_mqtt_send_settings_to_udp() {
|
||||||
if (mqtt_send_settings_to_udp) {
|
if (mqtt_send_settings_to_udp) {
|
||||||
mqtt_send_settings_to_udp = false;
|
mqtt_send_settings_to_udp = false;
|
||||||
send_mqtt_to_udp();
|
send_mqtt_to_udp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user