mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
52
Commits
mega-20180315
...
v2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f59f25ee40 | ||
|
|
14030ec15b | ||
|
|
1fd6179408 | ||
|
|
22424fb03b | ||
|
|
97cd06440e | ||
|
|
8346e39ac9 | ||
|
|
22371649a4 | ||
|
|
8cbd9a0822 | ||
|
|
93f9d11738 | ||
|
|
cf3e0a3f0a | ||
|
|
ccfd14dbd3 | ||
|
|
3034738ad4 | ||
|
|
178d1c46a2 | ||
|
|
cdfd1d986e | ||
|
|
4b7aa53692 | ||
|
|
cc02fa4481 | ||
|
|
ab3a406706 | ||
|
|
3edfdbf5f7 | ||
|
|
1220c565c8 | ||
|
|
f0987dab41 | ||
|
|
af3e353181 | ||
|
|
c711d6ea51 | ||
|
|
1f084c51cc | ||
|
|
85e8d98da8 | ||
|
|
6d52a7e03a | ||
|
|
fa513b52f9 | ||
|
|
f98401524f | ||
|
|
4090b4f23c | ||
|
|
b89c00008d | ||
|
|
d57a617138 | ||
|
|
cefe6b4b7c | ||
|
|
2432740b41 | ||
|
|
44a934651c | ||
|
|
6787bc8c0e | ||
|
|
cf644b45b1 | ||
|
|
e6fe1c63a9 | ||
|
|
df978036f0 | ||
|
|
7cb375833d | ||
|
|
3218ea9839 | ||
|
|
eca8901fca | ||
|
|
6635eafe91 | ||
|
|
fe4d1f952f | ||
|
|
4475a225cc | ||
|
|
2aece1c143 | ||
|
|
70df225e7e | ||
|
|
19af52a3ef | ||
|
|
3d396575ff | ||
|
|
826deaac89 | ||
|
|
cce621cff8 | ||
|
|
57eb38dbd0 | ||
|
|
fd2451bb07 | ||
|
|
cc0b3dac26 |
Vendored
+120
@@ -1,3 +1,123 @@
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180510 (since v2.0-20180322)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu May 10 04:00:27 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Revert "Update _P045_MPU6050.ino"
|
||||
|
||||
Maarten Paauw (1):
|
||||
Update _P045_MPU6050.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180322 (since v2.0-20180321)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Mar 22 04:00:24 CET 2018
|
||||
|
||||
Bartlomiej Zimon (3):
|
||||
- P012 fix command interpretation
|
||||
- P023 fix command interpretation
|
||||
- P048 fetch params only when needed
|
||||
|
||||
TD-er (4):
|
||||
- P035 move strings to flash
|
||||
[wifi] Make more robust checks and increase timeout
|
||||
[Memory] parseTemplate did not check if markers were found
|
||||
[WiFi] Take much more time for initial WiFi connect during setup
|
||||
|
||||
s0170071 (1):
|
||||
Serial WD crash
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180321 (since v2.0-20180320)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Mar 21 04:00:21 CET 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[merge issue] Forgotten #endif in merge
|
||||
|
||||
Unknown (1):
|
||||
[wifi] Setup with factory settings could not complete
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180320 (since v2.0-20180319)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Mar 20 04:00:23 CET 2018
|
||||
|
||||
Unknown (2):
|
||||
Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"
|
||||
[issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset
|
||||
|
||||
es-ka (1):
|
||||
Fix wiring description for SN75176 transceiver
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180319 (since v2.0-20180316)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Mar 19 04:00:24 CET 2018
|
||||
|
||||
Gijs Noorlander (6):
|
||||
Add download button for current rule set (#1102)
|
||||
- add encoder write command #1086 (#1103)
|
||||
Changed so that running all tasks immediately with deep sleep enabled… (#1110)
|
||||
Merge pull request #1112 from uzi18/fix-p073
|
||||
Merge pull request #1114 from TD-er/feature/wifi_details_json
|
||||
Merge pull request #1118 from TD-er/bugfix/mqtt_publish_after_deep_sleep
|
||||
|
||||
Unknown (3):
|
||||
Merge pull request #1113 from TD-er/feature/reduce_impact_wifi_disconnect
|
||||
Merge pull request #1116 from TD-er/feature/allow_own_defaults
|
||||
[merge] MIssing #endif due to merging.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180316 (since v2.0-20180313)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Mar 16 04:00:23 CET 2018
|
||||
|
||||
Bartlomiej Zimon (1):
|
||||
Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega
|
||||
|
||||
Gijs Noorlander (3):
|
||||
MCP3221 allow values for calibration (#1073)
|
||||
[issue #1066] Fix Webserver handle_control (#1079)
|
||||
Fixed multi instance problem on SHT3x #433 (#1081)
|
||||
|
||||
Unknown (5):
|
||||
- move all structs from ESPEasy.ino into header file
|
||||
[v2.0 split globals] Base split on v2.0 version of ESPEasy.ino
|
||||
[issue #1057] AM PM display issue
|
||||
[issue #993] variable in MQTT subscribe topic
|
||||
[issue #951] Changed System#Initialized => System#Wake
|
||||
|
||||
mvdbro (4):
|
||||
#893 part1, send messages
|
||||
Custom controller GUI option
|
||||
#893, part 2 receiving
|
||||
Rules fix
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180313 (since v2.0-20180312)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Mar 13 04:00:23 CET 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
- fix for #1065
|
||||
- remove double trimm()
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180312 (since v2.0-20180311)
|
||||
-------------------------------------------------
|
||||
|
||||
@@ -22,6 +22,10 @@ SOFTWARE.
|
||||
|
||||
See more at http://blog.squix.ch
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_PLAIN_FONT_H
|
||||
#define DIALOG_PLAIN_FONT_H
|
||||
|
||||
// OLED library version >= 3.0.0
|
||||
// Created by http://oleddisplay.squix.ch/ Consider a donation
|
||||
// In case of problems make sure that you are using the font file with the correct version!
|
||||
@@ -481,3 +485,6 @@ const char Dialog_plain_12[] PROGMEM = {
|
||||
0x00,0x00,0xFC,0x7F,0x40,0x04,0x20,0x08,0x20,0x08,0x60,0x0C,0xC0,0x07, // 254
|
||||
0x00,0x00,0xE0,0x40,0x04,0x47,0x00,0x38,0x84,0x07,0xE0 // 255
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef OLED_SSD1306_SH1106_IMAGES_H
|
||||
#define OLED_SSD1306_SH1106_IMAGES_H
|
||||
|
||||
#define espeasy_logo_width 36
|
||||
#define espeasy_logo_height 36
|
||||
const char espeasy_logo_bits[] PROGMEM= {
|
||||
@@ -38,3 +41,5 @@ const char inactiveSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+2
-5
@@ -7,9 +7,6 @@ void sendData(struct EventStruct *event)
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(event->TaskIndex);
|
||||
|
||||
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
|
||||
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
|
||||
if (Settings.UseValueLogger && Settings.InitSPI && Settings.Pin_sd_cs >= 0)
|
||||
SendValueLogger(event->TaskIndex);
|
||||
|
||||
@@ -137,7 +134,7 @@ bool MQTTConnect(int controller_idx)
|
||||
|
||||
String LWTTopic = ControllerSettings.Subscribe;
|
||||
LWTTopic.replace(F("/#"), F("/status"));
|
||||
LWTTopic.replace(F("%sysname%"), Settings.Name);
|
||||
parseSystemVariables(LWTTopic, false);
|
||||
LWTTopic += F("/LWT"); // Extend the topic for status updates of connected/disconnected status.
|
||||
|
||||
boolean MQTTresult = false;
|
||||
@@ -246,7 +243,7 @@ void MQTTStatus(String& status)
|
||||
LoadControllerSettings(enabledMqttController, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
String pubname = ControllerSettings.Subscribe;
|
||||
pubname.replace(F("/#"), F("/status"));
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
parseSystemVariables(pubname, false);
|
||||
MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,985 @@
|
||||
|
||||
#ifndef ESPEASY_GLOBALS_H_
|
||||
#define ESPEASY_GLOBALS_H_
|
||||
// ********************************************************************************
|
||||
// User specific configuration
|
||||
// ********************************************************************************
|
||||
|
||||
// Set default configuration settings if you want (not mandatory)
|
||||
// You can always change these during runtime and save to eeprom
|
||||
// After loading firmware, issue a 'reset' command to load the defaults.
|
||||
|
||||
// --- Basic Config Settings ------------------------------------------------------------------------
|
||||
#define DEFAULT_NAME "ESP_Easy" // Enter your device friendly name
|
||||
#define UNIT 0 // Unit Number
|
||||
#define DEFAULT_DELAY 60 // Sleep Delay in seconds
|
||||
|
||||
// --- Wifi AP Mode (when your Wifi Network is not reachable) ----------------------------------------
|
||||
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
|
||||
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
|
||||
|
||||
// --- Wifi Client Mode -----------------------------------------------------------------------------
|
||||
#define DEFAULT_SSID "ssid" // Enter your Wifi network SSID
|
||||
#define DEFAULT_KEY "wpakey" // Enter your Wifi network WPA key
|
||||
|
||||
#define DEFAULT_USE_STATIC_IP false // (true|false) enabled or disabled static IP
|
||||
#define DEFAULT_IP "192.168.0.50" // Enter your IP address
|
||||
#define DEFAULT_DNS "192.168.0.1" // Enter your DNS
|
||||
#define DEFAULT_GW "192.168.0.1" // Enter your Gateway
|
||||
#define DEFAULT_SUBNET "255.255.255.0" // Enter your Subnet
|
||||
|
||||
#define DEFAULT_WIFI_CONNECTION_TIMEOUT 10000 // minimum timeout in ms for WiFi to be connected.
|
||||
|
||||
// --- Default Controller ------------------------------------------------------------------------------
|
||||
#define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller defaults
|
||||
// using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol !
|
||||
#define DEFAULT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
|
||||
#define DEFAULT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
|
||||
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
|
||||
#define DEFAULT_PORT 8080 // Enter your Server port value
|
||||
|
||||
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
|
||||
// 1 = Domoticz HTTP
|
||||
// 2 = Domoticz MQTT
|
||||
// 3 = Nodo Telnet
|
||||
// 4 = ThingSpeak
|
||||
// 5 = OpenHAB MQTT
|
||||
// 6 = PiDome MQTT
|
||||
// 7 = EmonCMS
|
||||
// 8 = Generic HTTP
|
||||
// 9 = FHEM HTTP
|
||||
|
||||
|
||||
// --- Advanced Settings ---------------------------------------------------------------------------------
|
||||
#define DEFAULT_USE_RULES false // (true|false) Enable Rules?
|
||||
|
||||
#define DEFAULT_MQTT_RETAIN false // (true|false) Retain MQTT messages?
|
||||
#define DEFAULT_MQTT_DELAY 1000 // Time in milliseconds to retain MQTT messages
|
||||
|
||||
#define DEFAULT_USE_NTP false // (true|false) Use NTP Server
|
||||
#define DEFAULT_NTP_HOST "" // NTP Server Hostname
|
||||
#define DEFAULT_TIME_ZONE 0 // Time Offset (in minutes)
|
||||
#define DEFAULT_USE_DST false // (true|false) Use Daily Time Saving
|
||||
|
||||
#define LOG_TO_SERIAL 1
|
||||
#define LOG_TO_SYSLOG 2
|
||||
#define LOG_TO_WEBLOG 3
|
||||
#define LOG_TO_SDCARD 4
|
||||
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
|
||||
#define DEFAULT_SYSLOG_LEVEL 0 // Syslog Log Level
|
||||
#define DEFAULT_SERIAL_LOG_LEVEL LOG_LEVEL_INFO // Serial Log Level
|
||||
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
|
||||
#define DEFAULT_SD_LOG_LEVEL 0 // SD Card Log Level
|
||||
#define DEFAULT_USE_SD_LOG false // (true|false) Enable Logging to the SD card
|
||||
|
||||
#define DEFAULT_USE_SERIAL true // (true|false) Enable Logging to the Serial Port
|
||||
#define DEFAULT_SERIAL_BAUD 115200 // Serial Port Baud Rate
|
||||
|
||||
/*
|
||||
// --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------
|
||||
#define DEFAULT_USE_GLOBAL_SYNC false // (true|false)
|
||||
#define DEFAULT_SYNC_UDP_PORT 0 //
|
||||
#define DEFAULT_IP_OCTET 0 //
|
||||
#define DEFAULT_WD_IC2_ADDRESS 0 //
|
||||
#define DEFAULT_USE_SSDP false // (true|false)
|
||||
#define DEFAULT_CON_FAIL_THRES 0 //
|
||||
#define DEFAULT_I2C_CLOCK_LIMIT 0 //
|
||||
*/
|
||||
|
||||
|
||||
// Enable FEATURE_ADC_VCC to measure supply voltage using the analog pin
|
||||
// Please note that the TOUT pin has to be disconnected in this mode
|
||||
// Use the "System Info" device to read the VCC value
|
||||
#ifndef FEATURE_ADC_VCC
|
||||
#define FEATURE_ADC_VCC false
|
||||
#endif
|
||||
|
||||
|
||||
//enable Arduino OTA updating.
|
||||
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
|
||||
// #define FEATURE_ARDUINO_OTA
|
||||
|
||||
//enable mDNS mode (adds about 6kb ram and some bytes IRAM)
|
||||
// #define FEATURE_MDNS
|
||||
|
||||
|
||||
//enable reporting status to ESPEasy developers.
|
||||
//this informs us of crashes and stability issues.
|
||||
// not finished yet!
|
||||
// #define FEATURE_REPORTING
|
||||
|
||||
//Select which plugin sets you want to build.
|
||||
//These are normally automaticly set via the Platformio build environment.
|
||||
//If you use ArduinoIDE you might need to uncomment some of them, depending on your needs
|
||||
//If you dont select any, a version with a minimal number of plugins will be biult for 512k versions.
|
||||
//(512k is NOT finsihed or tested yet as of v2.0.0-dev6)
|
||||
|
||||
//build all the normal stable plugins (on by default)
|
||||
#define PLUGIN_BUILD_NORMAL
|
||||
|
||||
//build all plugins that are in test stadium
|
||||
//#define PLUGIN_BUILD_TESTING
|
||||
|
||||
//build all plugins that still are being developed and are broken or incomplete
|
||||
//#define PLUGIN_BUILD_DEV
|
||||
|
||||
// ********************************************************************************
|
||||
// DO NOT CHANGE ANYTHING BELOW THIS LINE
|
||||
// ********************************************************************************
|
||||
#include "core_version.h"
|
||||
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
|
||||
#error ESPEasy v2.0 only support Arduino core 2.3.0. (Use the ESPEasy development branch to fix this)
|
||||
#endif
|
||||
|
||||
#define ESP_PROJECT_PID 2016110801L
|
||||
#define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to config system.
|
||||
#define BUILD 20000 // git version 2.0.0
|
||||
#define BUILD_NOTES " - Mega"
|
||||
|
||||
#ifndef BUILD_GIT
|
||||
#define BUILD_GIT "(custom)"
|
||||
#endif
|
||||
|
||||
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
|
||||
|
||||
#define NODE_TYPE_ID_ESP_EASY_STD 1
|
||||
#define NODE_TYPE_ID_ESP_EASYM_STD 17
|
||||
#define NODE_TYPE_ID_ESP_EASY32_STD 33
|
||||
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
|
||||
#define NODE_TYPE_ID_NANO_EASY_STD 81
|
||||
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
|
||||
|
||||
#define PLUGIN_INIT_ALL 1
|
||||
#define PLUGIN_INIT 2
|
||||
#define PLUGIN_READ 3
|
||||
#define PLUGIN_ONCE_A_SECOND 4
|
||||
#define PLUGIN_TEN_PER_SECOND 5
|
||||
#define PLUGIN_DEVICE_ADD 6
|
||||
#define PLUGIN_EVENTLIST_ADD 7
|
||||
#define PLUGIN_WEBFORM_SAVE 8
|
||||
#define PLUGIN_WEBFORM_LOAD 9
|
||||
#define PLUGIN_WEBFORM_SHOW_VALUES 10
|
||||
#define PLUGIN_GET_DEVICENAME 11
|
||||
#define PLUGIN_GET_DEVICEVALUENAMES 12
|
||||
#define PLUGIN_WRITE 13
|
||||
#define PLUGIN_EVENT_OUT 14
|
||||
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
|
||||
#define PLUGIN_SERIAL_IN 16
|
||||
#define PLUGIN_UDP_IN 17
|
||||
#define PLUGIN_CLOCK_IN 18
|
||||
#define PLUGIN_TIMER_IN 19
|
||||
#define PLUGIN_FIFTY_PER_SECOND 20
|
||||
#define PLUGIN_SET_CONFIG 21
|
||||
#define PLUGIN_GET_DEVICEGPIONAMES 22
|
||||
#define PLUGIN_EXIT 23
|
||||
#define PLUGIN_GET_CONFIG 24
|
||||
|
||||
#define CPLUGIN_PROTOCOL_ADD 1
|
||||
#define CPLUGIN_PROTOCOL_TEMPLATE 2
|
||||
#define CPLUGIN_PROTOCOL_SEND 3
|
||||
#define CPLUGIN_PROTOCOL_RECV 4
|
||||
#define CPLUGIN_GET_DEVICENAME 5
|
||||
#define CPLUGIN_WEBFORM_SAVE 6
|
||||
#define CPLUGIN_WEBFORM_LOAD 7
|
||||
#define CPLUGIN_GET_PROTOCOL_DISPLAY_NAME 8
|
||||
#define CPLUGIN_TASK_CHANGE_NOTIFICATION 9
|
||||
#define CPLUGIN_INIT 10
|
||||
#define CPLUGIN_UDP_IN 11
|
||||
|
||||
#define CONTROLLER_HOSTNAME 1
|
||||
#define CONTROLLER_IP 2
|
||||
#define CONTROLLER_PORT 3
|
||||
#define CONTROLLER_USER 4
|
||||
#define CONTROLLER_PASS 5
|
||||
#define CONTROLLER_SUBSCRIBE 6
|
||||
#define CONTROLLER_PUBLISH 7
|
||||
|
||||
#define NPLUGIN_PROTOCOL_ADD 1
|
||||
#define NPLUGIN_GET_DEVICENAME 2
|
||||
#define NPLUGIN_WEBFORM_SAVE 3
|
||||
#define NPLUGIN_WEBFORM_LOAD 4
|
||||
#define NPLUGIN_WRITE 5
|
||||
#define NPLUGIN_NOTIFY 6
|
||||
#define NPLUGIN_NOT_FOUND 255
|
||||
|
||||
|
||||
#define LOG_LEVEL_ERROR 1
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#define LOG_LEVEL_DEBUG 3
|
||||
#define LOG_LEVEL_DEBUG_MORE 4
|
||||
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
|
||||
|
||||
#define CMD_REBOOT 89
|
||||
#define CMD_WIFI_DISCONNECT 135
|
||||
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define DEVICES_MAX 72
|
||||
#else
|
||||
#define DEVICES_MAX 64
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#define TASKS_MAX 12 // max 12!
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define TASKS_MAX 32
|
||||
#endif
|
||||
|
||||
#define CONTROLLER_MAX 3 // max 4!
|
||||
#define NOTIFICATION_MAX 3 // max 4!
|
||||
#define VARS_PER_TASK 4
|
||||
#define PLUGIN_MAX DEVICES_MAX
|
||||
#define PLUGIN_CONFIGVAR_MAX 8
|
||||
#define PLUGIN_CONFIGFLOATVAR_MAX 4
|
||||
#define PLUGIN_CONFIGLONGVAR_MAX 4
|
||||
#define PLUGIN_EXTRACONFIGVAR_MAX 16
|
||||
#define CPLUGIN_MAX 16
|
||||
#define NPLUGIN_MAX 4
|
||||
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
|
||||
#define RULES_TIMER_MAX 8
|
||||
#define SYSTEM_TIMER_MAX 8
|
||||
#define SYSTEM_CMD_TIMER_MAX 2
|
||||
#define PINSTATE_TABLE_MAX 32
|
||||
#define RULES_MAX_SIZE 2048
|
||||
#define RULES_MAX_NESTING_LEVEL 3
|
||||
#define RULESETS_MAX 4
|
||||
#define RULES_BUFFER_SIZE 64
|
||||
|
||||
#define PIN_MODE_UNDEFINED 0
|
||||
#define PIN_MODE_INPUT 1
|
||||
#define PIN_MODE_OUTPUT 2
|
||||
#define PIN_MODE_PWM 3
|
||||
#define PIN_MODE_SERVO 4
|
||||
|
||||
#define SEARCH_PIN_STATE true
|
||||
#define NO_SEARCH_PIN_STATE false
|
||||
|
||||
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
|
||||
#define DEVICE_TYPE_DUAL 2 // connected through 2 datapins
|
||||
#define DEVICE_TYPE_TRIPLE 3 // connected through 3 datapins
|
||||
#define DEVICE_TYPE_ANALOG 10 // AIN/tout pin
|
||||
#define DEVICE_TYPE_I2C 20 // connected through I2C
|
||||
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
|
||||
|
||||
#define SENSOR_TYPE_SINGLE 1
|
||||
#define SENSOR_TYPE_TEMP_HUM 2
|
||||
#define SENSOR_TYPE_TEMP_BARO 3
|
||||
#define SENSOR_TYPE_TEMP_HUM_BARO 4
|
||||
#define SENSOR_TYPE_DUAL 5
|
||||
#define SENSOR_TYPE_TRIPLE 6
|
||||
#define SENSOR_TYPE_QUAD 7
|
||||
#define SENSOR_TYPE_SWITCH 10
|
||||
#define SENSOR_TYPE_DIMMER 11
|
||||
#define SENSOR_TYPE_LONG 20
|
||||
#define SENSOR_TYPE_WIND 21
|
||||
|
||||
#define VALUE_SOURCE_SYSTEM 1
|
||||
#define VALUE_SOURCE_SERIAL 2
|
||||
#define VALUE_SOURCE_HTTP 3
|
||||
#define VALUE_SOURCE_MQTT 4
|
||||
#define VALUE_SOURCE_UDP 5
|
||||
|
||||
#define BOOT_CAUSE_MANUAL_REBOOT 0
|
||||
#define BOOT_CAUSE_COLD_BOOT 1
|
||||
#define BOOT_CAUSE_DEEP_SLEEP 2
|
||||
#define BOOT_CAUSE_EXT_WD 10
|
||||
|
||||
#define DAT_TASKS_SIZE 2048
|
||||
#define DAT_TASKS_CUSTOM_OFFSET 1024
|
||||
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
|
||||
#define DAT_CONTROLLER_SIZE 1024
|
||||
#define DAT_NOTIFICATION_SIZE 1024
|
||||
|
||||
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
|
||||
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
|
||||
#define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max.
|
||||
|
||||
|
||||
/*
|
||||
To modify the stock configuration without changing this repo file :
|
||||
- define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
|
||||
- add a "Custom.h" file in this folder.
|
||||
*/
|
||||
#ifdef USE_CUSTOM_H
|
||||
#include "Custom.h"
|
||||
#endif
|
||||
|
||||
#define FILE_CONFIG "config.dat"
|
||||
#define FILE_SECURITY "security.dat"
|
||||
#define FILE_NOTIFICATION "notification.dat"
|
||||
#define FILE_RULES "rules1.dat"
|
||||
#include "ESPEasyTimeTypes.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
#include <DNSServer.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#ifdef FEATURE_MDNS
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <PubSubClient.h>
|
||||
// #include <ArduinoJson.h>
|
||||
// #include <LiquidCrystal_I2C.h>
|
||||
#include <Servo.h>
|
||||
#define FS_NO_GLOBALS
|
||||
#include <FS.h>
|
||||
#include <SD.h>
|
||||
#include <ESP8266HTTPUpdateServer.h>
|
||||
ESP8266HTTPUpdateServer httpUpdater(true);
|
||||
#include <base64.h>
|
||||
#if FEATURE_ADC_VCC
|
||||
ADC_MODE(ADC_VCC);
|
||||
#endif
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
#define LWIP_OPEN_SRC
|
||||
#endif
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "include/UdpContext.h"
|
||||
#include "limits.h"
|
||||
|
||||
extern "C" {
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
bool ArduinoOTAtriggered=false;
|
||||
#endif
|
||||
|
||||
|
||||
// Setup DNS, only used if the ESP has no valid WiFi config
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(DEFAULT_AP_IP);
|
||||
DNSServer dnsServer;
|
||||
#ifdef FEATURE_MDNS
|
||||
MDNSResponder mdns;
|
||||
#endif
|
||||
|
||||
// MQTT client
|
||||
WiFiClient mqtt;
|
||||
PubSubClient MQTTclient(mqtt);
|
||||
bool MQTTclient_should_reconnect = true;
|
||||
|
||||
// WebServer
|
||||
ESP8266WebServer WebServer(80);
|
||||
|
||||
// udp protocol stuff (syslog, global sync, node info list, ntp time)
|
||||
WiFiUDP portUDP;
|
||||
|
||||
// Forward declarations.
|
||||
bool WiFiConnected(uint32_t timeout_ms);
|
||||
bool hostReachable(const IPAddress& ip);
|
||||
bool hostReachable(const String& hostname);
|
||||
|
||||
extern "C" {
|
||||
#include "spi_flash.h"
|
||||
}
|
||||
extern "C" uint32_t _SPIFFS_start;
|
||||
extern "C" uint32_t _SPIFFS_end;
|
||||
extern "C" uint32_t _SPIFFS_page;
|
||||
extern "C" uint32_t _SPIFFS_block;
|
||||
|
||||
struct SecurityStruct
|
||||
{
|
||||
SecurityStruct() {
|
||||
memset(WifiSSID, 0, sizeof(WifiSSID));
|
||||
memset(WifiKey, 0, sizeof(WifiKey));
|
||||
memset(WifiSSID2, 0, sizeof(WifiSSID2));
|
||||
memset(WifiKey2, 0, sizeof(WifiKey2));
|
||||
memset(WifiAPKey, 0, sizeof(WifiAPKey));
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
memset(ControllerUser[i], 0, sizeof(ControllerUser[i]));
|
||||
memset(ControllerPassword[i], 0, sizeof(ControllerPassword[i]));
|
||||
}
|
||||
memset(Password, 0, sizeof(Password));
|
||||
}
|
||||
char WifiSSID[32];
|
||||
char WifiKey[64];
|
||||
char WifiSSID2[32];
|
||||
char WifiKey2[64];
|
||||
char WifiAPKey[64];
|
||||
char ControllerUser[CONTROLLER_MAX][26];
|
||||
char ControllerPassword[CONTROLLER_MAX][64];
|
||||
char Password[26];
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
} SecuritySettings;
|
||||
|
||||
struct SettingsStruct
|
||||
{
|
||||
SettingsStruct() :
|
||||
PID(0), Version(0), Build(0), IP_Octet(0), Unit(0), Delay(0),
|
||||
Pin_i2c_sda(-1), Pin_i2c_scl(-1), Pin_status_led(-1), Pin_sd_cs(-1),
|
||||
UDPPort(0), SyslogLevel(0), SerialLogLevel(0), WebLogLevel(0), SDLogLevel(0),
|
||||
BaudRate(0), MessageDelay(0), deepSleep(0),
|
||||
CustomCSS(false), DST(false), WDI2CAddress(0),
|
||||
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
|
||||
WireClockStretchLimit(0), ConnectionFailuresThreshold(0),
|
||||
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
|
||||
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
|
||||
DST_Start(0), DST_End(0)
|
||||
{
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
Protocol[i] = 0;
|
||||
ControllerEnabled[i] = false;
|
||||
for (byte task = 0; task < TASKS_MAX; ++task) {
|
||||
TaskDeviceID[i][task] = 0;
|
||||
TaskDeviceSendData[i][task] = false;
|
||||
}
|
||||
}
|
||||
for (byte task = 0; task < TASKS_MAX; ++task) {
|
||||
TaskDeviceNumber[task] = 0;
|
||||
OLD_TaskDeviceID[task] = 0;
|
||||
TaskDevicePin1PullUp[task] = false;
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfig[task][cv] = 0;
|
||||
}
|
||||
TaskDevicePin1Inversed[task] = false;
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfigFloat[task][cv] = 0.0;
|
||||
}
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfigLong[task][cv] = 0;
|
||||
}
|
||||
OLD_TaskDeviceSendData[task] = false;
|
||||
TaskDeviceGlobalSync[task] = false;
|
||||
TaskDeviceDataFeed[task] = 0;
|
||||
TaskDeviceTimer[task] = 0;
|
||||
TaskDeviceEnabled[task] = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long PID;
|
||||
int Version;
|
||||
int16_t Build;
|
||||
byte IP[4];
|
||||
byte Gateway[4];
|
||||
byte Subnet[4];
|
||||
byte DNS[4];
|
||||
byte IP_Octet;
|
||||
byte Unit;
|
||||
char Name[26];
|
||||
char NTPHost[64];
|
||||
unsigned long Delay;
|
||||
int8_t Pin_i2c_sda;
|
||||
int8_t Pin_i2c_scl;
|
||||
int8_t Pin_status_led;
|
||||
int8_t Pin_sd_cs;
|
||||
int8_t PinBootStates[17];
|
||||
byte Syslog_IP[4];
|
||||
unsigned int UDPPort;
|
||||
byte SyslogLevel;
|
||||
byte SerialLogLevel;
|
||||
byte WebLogLevel;
|
||||
byte SDLogLevel;
|
||||
unsigned long BaudRate;
|
||||
unsigned long MessageDelay;
|
||||
byte deepSleep;
|
||||
boolean CustomCSS;
|
||||
boolean DST;
|
||||
byte WDI2CAddress;
|
||||
boolean UseRules;
|
||||
boolean UseSerial;
|
||||
boolean UseSSDP;
|
||||
boolean UseNTP;
|
||||
unsigned long WireClockStretchLimit;
|
||||
boolean _GlobalSync; // obsolete!
|
||||
unsigned long ConnectionFailuresThreshold;
|
||||
int16_t TimeZone;
|
||||
boolean MQTTRetainFlag;
|
||||
boolean InitSPI;
|
||||
byte Protocol[CONTROLLER_MAX];
|
||||
byte Notification[NOTIFICATION_MAX]; //notifications, point to a NPLUGIN id
|
||||
byte TaskDeviceNumber[TASKS_MAX];
|
||||
unsigned int OLD_TaskDeviceID[TASKS_MAX];
|
||||
union {
|
||||
struct {
|
||||
int8_t TaskDevicePin1[TASKS_MAX];
|
||||
int8_t TaskDevicePin2[TASKS_MAX];
|
||||
int8_t TaskDevicePin3[TASKS_MAX];
|
||||
byte TaskDevicePort[TASKS_MAX];
|
||||
};
|
||||
int8_t TaskDevicePin[4][TASKS_MAX];
|
||||
};
|
||||
boolean TaskDevicePin1PullUp[TASKS_MAX];
|
||||
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
|
||||
boolean TaskDevicePin1Inversed[TASKS_MAX];
|
||||
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
|
||||
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
|
||||
boolean OLD_TaskDeviceSendData[TASKS_MAX];
|
||||
boolean TaskDeviceGlobalSync[TASKS_MAX];
|
||||
byte TaskDeviceDataFeed[TASKS_MAX];
|
||||
unsigned long TaskDeviceTimer[TASKS_MAX];
|
||||
boolean TaskDeviceEnabled[TASKS_MAX];
|
||||
boolean ControllerEnabled[CONTROLLER_MAX];
|
||||
boolean NotificationEnabled[NOTIFICATION_MAX];
|
||||
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean Pin_status_led_Inversed;
|
||||
boolean deepSleepOnFail;
|
||||
boolean UseValueLogger;
|
||||
uint16_t DST_Start;
|
||||
uint16_t DST_End;
|
||||
//its safe to extend this struct, up to several bytes, default values in config are 0
|
||||
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
|
||||
//TODO: document config.dat somewhere here
|
||||
} Settings;
|
||||
|
||||
struct ControllerSettingsStruct
|
||||
{
|
||||
ControllerSettingsStruct() : UseDNS(false), Port(0) {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
IP[i] = 0;
|
||||
}
|
||||
memset(HostName, 0, sizeof(HostName));
|
||||
memset(Publish, 0, sizeof(Publish));
|
||||
memset(Subscribe, 0, sizeof(Subscribe));
|
||||
}
|
||||
boolean UseDNS;
|
||||
byte IP[4];
|
||||
unsigned int Port;
|
||||
char HostName[65];
|
||||
char Publish[129];
|
||||
char Subscribe[129];
|
||||
|
||||
IPAddress getIP() const {
|
||||
IPAddress host(IP[0], IP[1], IP[2], IP[3]);
|
||||
return host;
|
||||
}
|
||||
|
||||
String getHost() const {
|
||||
if (UseDNS) {
|
||||
return HostName;
|
||||
}
|
||||
return getIP().toString();
|
||||
}
|
||||
|
||||
void setHostname(const String& controllerhostname) {
|
||||
strncpy(HostName, controllerhostname.c_str(), sizeof(HostName));
|
||||
updateIPcache();
|
||||
}
|
||||
|
||||
boolean checkHostReachable(bool quick) {
|
||||
if (!WiFiConnected(10)) {
|
||||
return false; // Not connected, so no use in wasting time to connect to a host.
|
||||
}
|
||||
if (quick && ipSet()) return true;
|
||||
if (UseDNS) {
|
||||
if (!updateIPcache()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return hostReachable(getIP());
|
||||
}
|
||||
|
||||
boolean connectToHost(WiFiClient &client) {
|
||||
if (!checkHostReachable(true)) {
|
||||
return false; // Host not reachable
|
||||
}
|
||||
byte retry = 2;
|
||||
bool connected = false;
|
||||
while (retry > 0 && !connected) {
|
||||
--retry;
|
||||
connected = client.connect(getIP(), Port);
|
||||
if (connected) return true;
|
||||
if (!checkHostReachable(false))
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int beginPacket(WiFiUDP &client) {
|
||||
if (!checkHostReachable(true)) {
|
||||
return 0; // Host not reachable
|
||||
}
|
||||
byte retry = 2;
|
||||
int connected = 0;
|
||||
while (retry > 0 && !connected) {
|
||||
--retry;
|
||||
connected = client.beginPacket(getIP(), Port);
|
||||
if (connected != 0) return connected;
|
||||
if (!checkHostReachable(false))
|
||||
return false;
|
||||
delay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String getHostPortString() const {
|
||||
String result = getHost();
|
||||
result += ":";
|
||||
result += Port;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
bool ipSet() {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
if (IP[i] != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updateIPcache() {
|
||||
if (!UseDNS) {
|
||||
return true;
|
||||
}
|
||||
IPAddress tmpIP;
|
||||
if (WiFi.hostByName(HostName, tmpIP)) {
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
IP[x] = tmpIP[x];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct NotificationSettingsStruct
|
||||
{
|
||||
NotificationSettingsStruct() : Port(0), Pin1(0), Pin2(0) {
|
||||
memset(Server, 0, sizeof(Server));
|
||||
memset(Domain, 0, sizeof(Domain));
|
||||
memset(Sender, 0, sizeof(Sender));
|
||||
memset(Receiver, 0, sizeof(Receiver));
|
||||
memset(Subject, 0, sizeof(Subject));
|
||||
memset(Body, 0, sizeof(Body));
|
||||
memset(User, 0, sizeof(User));
|
||||
memset(Pass, 0, sizeof(Pass));
|
||||
}
|
||||
|
||||
char Server[65];
|
||||
unsigned int Port;
|
||||
char Domain[65];
|
||||
char Sender[65];
|
||||
char Receiver[65];
|
||||
char Subject[129];
|
||||
char Body[513];
|
||||
byte Pin1;
|
||||
byte Pin2;
|
||||
char User[49];
|
||||
char Pass[33];
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
};
|
||||
|
||||
struct ExtraTaskSettingsStruct
|
||||
{
|
||||
ExtraTaskSettingsStruct() : TaskIndex(0) {
|
||||
TaskDeviceName[0] = 0;
|
||||
for (byte i = 0; i < VARS_PER_TASK; ++i) {
|
||||
for (byte j = 0; j < 41; ++j) {
|
||||
TaskDeviceFormula[i][j] = 0;
|
||||
TaskDeviceValueNames[i][j] = 0;
|
||||
TaskDeviceValueDecimals[i] = 0;
|
||||
}
|
||||
}
|
||||
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
|
||||
TaskDevicePluginConfigLong[i] = 0;
|
||||
TaskDevicePluginConfig[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
byte TaskIndex;
|
||||
char TaskDeviceName[41];
|
||||
char TaskDeviceFormula[VARS_PER_TASK][41];
|
||||
char TaskDeviceValueNames[VARS_PER_TASK][41];
|
||||
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
|
||||
byte TaskDeviceValueDecimals[VARS_PER_TASK];
|
||||
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
|
||||
} ExtraTaskSettings;
|
||||
|
||||
struct EventStruct
|
||||
{
|
||||
EventStruct() :
|
||||
Source(0), TaskIndex(0), ControllerIndex(0), ProtocolIndex(0), NotificationIndex(0),
|
||||
BaseVarIndex(0), idx(0), sensorType(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0),
|
||||
OriginTaskIndex(0), Data(NULL) {}
|
||||
byte Source;
|
||||
byte TaskIndex; // index position in TaskSettings array, 0-11
|
||||
byte ControllerIndex; // index position in Settings.Controller, 0-3
|
||||
byte ProtocolIndex; // index position in protocol array, depending on which controller plugins are loaded.
|
||||
byte NotificationIndex; // index position in Settings.Notification, 0-3
|
||||
//Edwin: Not needed, and wasnt used. We can determine the protocol index with getNotificationProtocolIndex(NotificationIndex)
|
||||
// byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
|
||||
byte BaseVarIndex;
|
||||
int idx;
|
||||
byte sensorType;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
int Par4;
|
||||
int Par5;
|
||||
byte OriginTaskIndex;
|
||||
String String1;
|
||||
String String2;
|
||||
String String3;
|
||||
byte *Data;
|
||||
};
|
||||
|
||||
#define LOG_STRUCT_MESSAGE_SIZE 128
|
||||
#define LOG_STRUCT_MESSAGE_LINES 20
|
||||
|
||||
struct LogStruct {
|
||||
LogStruct() : write_idx(0), read_idx(0) {
|
||||
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
|
||||
memset(Message[i], 0, LOG_STRUCT_MESSAGE_SIZE);
|
||||
timeStamp[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void add(const char *line) {
|
||||
write_idx = (write_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
if (write_idx == read_idx) {
|
||||
// Buffer full, move read_idx to overwrite oldest entry.
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
}
|
||||
timeStamp[write_idx] = millis();
|
||||
strncpy(Message[write_idx], line, LOG_STRUCT_MESSAGE_SIZE-1);
|
||||
}
|
||||
|
||||
// Read the next item and append it to the given string.
|
||||
// Returns whether new lines are available.
|
||||
bool get(String& output, const String& lineEnd) {
|
||||
if (!isEmpty()) {
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
output += formatLine(read_idx, lineEnd);
|
||||
}
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
bool get(String& output, const String& lineEnd, int line) {
|
||||
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
}
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
bool getAll(String& output, const String& lineEnd) {
|
||||
int tmpread((write_idx + 1) % LOG_STRUCT_MESSAGE_LINES);
|
||||
bool someAdded = false;
|
||||
while (tmpread != write_idx) {
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
someAdded = true;
|
||||
}
|
||||
tmpread = (tmpread + 1)% LOG_STRUCT_MESSAGE_LINES;
|
||||
}
|
||||
return someAdded;
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return (write_idx == read_idx);
|
||||
}
|
||||
|
||||
private:
|
||||
String formatLine(int index, const String& lineEnd) {
|
||||
String output;
|
||||
output += timeStamp[index];
|
||||
output += " : ";
|
||||
output += Message[index];
|
||||
output += lineEnd;
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
int write_idx;
|
||||
int read_idx;
|
||||
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
|
||||
char Message[LOG_STRUCT_MESSAGE_LINES][LOG_STRUCT_MESSAGE_SIZE];
|
||||
|
||||
} Logging;
|
||||
|
||||
struct DeviceStruct
|
||||
{
|
||||
DeviceStruct() :
|
||||
Number(0), Type(0), VType(0), Ports(0),
|
||||
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
|
||||
ValueCount(0), Custom(false), SendDataOption(false), GlobalSyncOption(false),
|
||||
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
|
||||
byte Number;
|
||||
byte Type;
|
||||
byte VType;
|
||||
byte Ports;
|
||||
boolean PullUpOption;
|
||||
boolean InverseLogicOption;
|
||||
boolean FormulaOption;
|
||||
byte ValueCount;
|
||||
boolean Custom;
|
||||
boolean SendDataOption;
|
||||
boolean GlobalSyncOption;
|
||||
boolean TimerOption;
|
||||
boolean TimerOptional;
|
||||
boolean DecimalsOnly;
|
||||
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
|
||||
|
||||
struct ProtocolStruct
|
||||
{
|
||||
ProtocolStruct() :
|
||||
Number(0), usesMQTT(false), usesAccount(false), usesPassword(false),
|
||||
defaultPort(0), usesTemplate(false), usesID(false), Custom(false) {}
|
||||
byte Number;
|
||||
boolean usesMQTT;
|
||||
boolean usesAccount;
|
||||
boolean usesPassword;
|
||||
int defaultPort;
|
||||
boolean usesTemplate;
|
||||
boolean usesID;
|
||||
boolean Custom;
|
||||
} Protocol[CPLUGIN_MAX];
|
||||
|
||||
struct NotificationStruct
|
||||
{
|
||||
NotificationStruct() :
|
||||
Number(0), usesMessaging(false), usesGPIO(0) {}
|
||||
byte Number;
|
||||
boolean usesMessaging;
|
||||
byte usesGPIO;
|
||||
} Notification[NPLUGIN_MAX];
|
||||
|
||||
struct NodeStruct
|
||||
{
|
||||
NodeStruct() :
|
||||
age(0), build(0), nodeName(NULL), nodeType(0)
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i) ip[i] = 0;
|
||||
}
|
||||
byte ip[4];
|
||||
byte age;
|
||||
uint16_t build;
|
||||
char* nodeName;
|
||||
byte nodeType;
|
||||
} Nodes[UNIT_MAX];
|
||||
|
||||
struct systemTimerStruct
|
||||
{
|
||||
systemTimerStruct() :
|
||||
timer(0), plugin(0), Par1(0), Par2(0), Par3(0) {}
|
||||
|
||||
unsigned long timer;
|
||||
byte plugin;
|
||||
byte Par1;
|
||||
byte Par2;
|
||||
byte Par3;
|
||||
} systemTimers[SYSTEM_TIMER_MAX];
|
||||
|
||||
struct systemCMDTimerStruct
|
||||
{
|
||||
systemCMDTimerStruct() : timer(0) {}
|
||||
unsigned long timer;
|
||||
String action;
|
||||
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
|
||||
|
||||
struct pinStatesStruct
|
||||
{
|
||||
byte plugin;
|
||||
byte index;
|
||||
byte mode;
|
||||
uint16_t value;
|
||||
} pinStates[PINSTATE_TABLE_MAX];
|
||||
|
||||
|
||||
// this offsets are in blocks, bytes = blocks * 4
|
||||
#define RTC_BASE_STRUCT 64
|
||||
#define RTC_BASE_USERVAR 74
|
||||
|
||||
//max 40 bytes: ( 74 - 64 ) * 4
|
||||
struct RTCStruct
|
||||
{
|
||||
byte ID1;
|
||||
byte ID2;
|
||||
boolean unused1;
|
||||
byte factoryResetCounter;
|
||||
byte deepSleepState;
|
||||
byte unused2;
|
||||
byte flashDayCounter;
|
||||
unsigned long flashCounter;
|
||||
unsigned long bootCounter;
|
||||
} RTC;
|
||||
|
||||
|
||||
int deviceCount = -1;
|
||||
int protocolCount = -1;
|
||||
int notificationCount = -1;
|
||||
|
||||
boolean printToWeb = false;
|
||||
String printWebString = "";
|
||||
boolean printToWebJSON = false;
|
||||
|
||||
float UserVar[VARS_PER_TASK * TASKS_MAX];
|
||||
unsigned long RulesTimer[RULES_TIMER_MAX];
|
||||
|
||||
unsigned long timerSensor[TASKS_MAX];
|
||||
unsigned long timer100ms;
|
||||
unsigned long timer20ms;
|
||||
unsigned long timer1s;
|
||||
unsigned long timerwd;
|
||||
unsigned long timermqtt;
|
||||
unsigned long timermqtt_interval;
|
||||
unsigned long lastSend;
|
||||
unsigned long lastWeb;
|
||||
unsigned int NC_Count = 0;
|
||||
unsigned int C_Count = 0;
|
||||
byte cmd_within_mainloop = 0;
|
||||
unsigned long connectionFailures;
|
||||
unsigned long wdcounter = 0;
|
||||
unsigned long timerAPoff = 0;
|
||||
unsigned long timerAwakeFromDeepSleep = 0;
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
float vcc = -1.0;
|
||||
#endif
|
||||
|
||||
boolean WebLoggedIn = false;
|
||||
int WebLoggedInTimer = 300;
|
||||
|
||||
boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte Plugin_id[PLUGIN_MAX];
|
||||
|
||||
boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte CPlugin_id[CPLUGIN_MAX];
|
||||
|
||||
boolean (*NPlugin_ptr[NPLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte NPlugin_id[NPLUGIN_MAX];
|
||||
|
||||
String dummyString = "";
|
||||
|
||||
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
|
||||
|
||||
boolean wifiSetup = false;
|
||||
boolean wifiSetupConnect = false;
|
||||
uint8_t lastBSSID[6] = {0};
|
||||
boolean wifiConnected = false;
|
||||
unsigned long wifi_connect_timer = 0;
|
||||
unsigned int wifi_connect_attempt = 0;
|
||||
uint8_t lastWiFiSettings = 0;
|
||||
|
||||
|
||||
|
||||
unsigned long start = 0;
|
||||
unsigned long elapsed = 0;
|
||||
unsigned long loopCounter = 0;
|
||||
unsigned long loopCounterLast = 0;
|
||||
unsigned long loopCounterMax = 1;
|
||||
|
||||
unsigned long dailyResetCounter = 0;
|
||||
|
||||
String eventBuffer = "";
|
||||
|
||||
uint16_t lowestRAM = 0;
|
||||
String lowestRAMfunction = "";
|
||||
|
||||
bool shouldReboot=false;
|
||||
bool firstLoop=true;
|
||||
|
||||
boolean activeRuleSets[RULESETS_MAX];
|
||||
|
||||
#endif /* ESPEASY_GLOBALS_H_ */
|
||||
+22
-990
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
#ifndef ESPEASY_TIMETYPES_H_
|
||||
#define ESPEASY_TIMETYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct timeStruct {
|
||||
@@ -59,3 +62,8 @@ struct TimeChangeRule {
|
||||
void applyTimeZone(uint32_t curTime = 0);
|
||||
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime = 0);
|
||||
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
|
||||
String getTimeString(char delimiter, bool show_seconds=true);
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds=true);
|
||||
|
||||
|
||||
#endif /* ESPEASY_TIMETYPES_H_ */
|
||||
|
||||
+67
-64
@@ -1320,74 +1320,76 @@ String parseTemplate(String &tmpString, byte lineSize)
|
||||
newString += tmpString.substring(0, leftBracketIndex);
|
||||
tmpString = tmpString.substring(leftBracketIndex + 1);
|
||||
int rightBracketIndex = tmpString.indexOf(']');
|
||||
if (rightBracketIndex)
|
||||
if (rightBracketIndex >= 0)
|
||||
{
|
||||
tmpStringMid = tmpString.substring(0, rightBracketIndex);
|
||||
tmpString = tmpString.substring(rightBracketIndex + 1);
|
||||
int hashtagIndex = tmpStringMid.indexOf('#');
|
||||
String deviceName = tmpStringMid.substring(0, hashtagIndex);
|
||||
String valueName = tmpStringMid.substring(hashtagIndex + 1);
|
||||
String valueFormat = "";
|
||||
hashtagIndex = valueName.indexOf('#');
|
||||
if (hashtagIndex >= 0)
|
||||
{
|
||||
valueFormat = valueName.substring(hashtagIndex + 1);
|
||||
valueName = valueName.substring(0, hashtagIndex);
|
||||
}
|
||||
for (byte y = 0; y < TASKS_MAX; y++)
|
||||
{
|
||||
if (Settings.TaskDeviceEnabled[y])
|
||||
if (hashtagIndex >= 0) {
|
||||
String deviceName = tmpStringMid.substring(0, hashtagIndex);
|
||||
String valueName = tmpStringMid.substring(hashtagIndex + 1);
|
||||
String valueFormat = "";
|
||||
hashtagIndex = valueName.indexOf('#');
|
||||
if (hashtagIndex >= 0)
|
||||
{
|
||||
LoadTaskSettings(y);
|
||||
if (ExtraTaskSettings.TaskDeviceName[0] != 0)
|
||||
valueFormat = valueName.substring(hashtagIndex + 1);
|
||||
valueName = valueName.substring(0, hashtagIndex);
|
||||
}
|
||||
for (byte y = 0; y < TASKS_MAX; y++)
|
||||
{
|
||||
if (Settings.TaskDeviceEnabled[y])
|
||||
{
|
||||
if (deviceName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName))
|
||||
LoadTaskSettings(y);
|
||||
if (ExtraTaskSettings.TaskDeviceName[0] != 0)
|
||||
{
|
||||
boolean match = false;
|
||||
for (byte z = 0; z < VARS_PER_TASK; z++)
|
||||
if (valueName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceValueNames[z]))
|
||||
{
|
||||
// here we know the task and value, so find the uservar
|
||||
match = true;
|
||||
String value = "";
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
|
||||
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG)
|
||||
value = (unsigned long)UserVar[y * VARS_PER_TASK + z] + ((unsigned long)UserVar[y * VARS_PER_TASK + z + 1] << 16);
|
||||
else
|
||||
value = toString(UserVar[y * VARS_PER_TASK + z], ExtraTaskSettings.TaskDeviceValueDecimals[z]);
|
||||
|
||||
int oidx;
|
||||
if ((oidx = valueFormat.indexOf('O'))>=0) // Output
|
||||
{
|
||||
valueFormat.remove(oidx);
|
||||
oidx = valueFormat.indexOf('!'); // inverted or active low
|
||||
float val = value.toFloat();
|
||||
if (oidx >= 0) {
|
||||
valueFormat.remove(oidx);
|
||||
value = val == 0 ? " ON" : "OFF";
|
||||
} else {
|
||||
value = val == 0 ? "OFF" : " ON";
|
||||
}
|
||||
}
|
||||
|
||||
if (valueFormat == "R")
|
||||
{
|
||||
int filler = lineSize - newString.length() - value.length() - tmpString.length() ;
|
||||
for (byte f = 0; f < filler; f++)
|
||||
newString += " ";
|
||||
}
|
||||
newString += String(value);
|
||||
break;
|
||||
}
|
||||
if (!match) // try if this is a get config request
|
||||
if (deviceName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName))
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.TaskIndex = y;
|
||||
String tmpName = valueName;
|
||||
if (PluginCall(PLUGIN_GET_CONFIG, &TempEvent, tmpName))
|
||||
newString += tmpName;
|
||||
boolean match = false;
|
||||
for (byte z = 0; z < VARS_PER_TASK; z++)
|
||||
if (valueName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceValueNames[z]))
|
||||
{
|
||||
// here we know the task and value, so find the uservar
|
||||
match = true;
|
||||
String value = "";
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
|
||||
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG)
|
||||
value = (unsigned long)UserVar[y * VARS_PER_TASK + z] + ((unsigned long)UserVar[y * VARS_PER_TASK + z + 1] << 16);
|
||||
else
|
||||
value = toString(UserVar[y * VARS_PER_TASK + z], ExtraTaskSettings.TaskDeviceValueDecimals[z]);
|
||||
|
||||
int oidx;
|
||||
if ((oidx = valueFormat.indexOf('O'))>=0) // Output
|
||||
{
|
||||
valueFormat.remove(oidx);
|
||||
oidx = valueFormat.indexOf('!'); // inverted or active low
|
||||
float val = value.toFloat();
|
||||
if (oidx >= 0) {
|
||||
valueFormat.remove(oidx);
|
||||
value = val == 0 ? " ON" : "OFF";
|
||||
} else {
|
||||
value = val == 0 ? "OFF" : " ON";
|
||||
}
|
||||
}
|
||||
|
||||
if (valueFormat == "R")
|
||||
{
|
||||
int filler = lineSize - newString.length() - value.length() - tmpString.length() ;
|
||||
for (byte f = 0; f < filler; f++)
|
||||
newString += " ";
|
||||
}
|
||||
newString += String(value);
|
||||
break;
|
||||
}
|
||||
if (!match) // try if this is a get config request
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.TaskIndex = y;
|
||||
String tmpName = valueName;
|
||||
if (PluginCall(PLUGIN_GET_CONFIG, &TempEvent, tmpName))
|
||||
newString += tmpName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1806,10 +1808,11 @@ String rulesProcessingFile(String fileName, String& event)
|
||||
// This to avoid waisting CPU time...
|
||||
line = parseTemplate(line, line.length());
|
||||
}
|
||||
line.trim();
|
||||
|
||||
String lineOrg = line; // store original line for future use
|
||||
line.toLowerCase(); // convert all to lower case to make checks easier
|
||||
line.trim();
|
||||
|
||||
|
||||
String eventTrigger = "";
|
||||
String action = "";
|
||||
@@ -1853,9 +1856,9 @@ String rulesProcessingFile(String fileName, String& event)
|
||||
{
|
||||
isCommand = false;
|
||||
codeBlock = false;
|
||||
match = false;
|
||||
match = false;
|
||||
}
|
||||
|
||||
|
||||
if (Settings.SerialLogLevel == LOG_LEVEL_DEBUG_DEV){
|
||||
Serial.print(F("RuleDebug: "));
|
||||
Serial.print(codeBlock);
|
||||
@@ -1864,7 +1867,7 @@ String rulesProcessingFile(String fileName, String& event)
|
||||
Serial.print(": ");
|
||||
Serial.println(line);
|
||||
}
|
||||
|
||||
|
||||
if (match) // rule matched for one action or a block of actions
|
||||
{
|
||||
int split = lcAction.indexOf("if "); // check for optional "if" condition
|
||||
@@ -2314,7 +2317,7 @@ void play_rtttl(uint8_t _pin, char *p )
|
||||
#define OCTAVE_OFFSET 0
|
||||
// Absolutely no error checking in here
|
||||
|
||||
int notes[] = { 0,
|
||||
const int notes[] = { 0,
|
||||
262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
|
||||
523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
|
||||
1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976,
|
||||
|
||||
+6
-166
@@ -32,35 +32,6 @@ void syslog(const char *message)
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Structs for UDP messaging
|
||||
\*********************************************************************************************/
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
//TODO: add sysinfoStruct
|
||||
|
||||
/*********************************************************************************************\
|
||||
Check UDP messages (ESPEasy propiertary protocol)
|
||||
\*********************************************************************************************/
|
||||
@@ -97,22 +68,10 @@ void checkUDP()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetBuffer[1] > 1 && packetBuffer[1] < 6)
|
||||
{
|
||||
String log = (F("UDP : Sensor msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)packetBuffer[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
// binary data!
|
||||
switch (packetBuffer[1])
|
||||
{
|
||||
|
||||
//TODO: use a nice struct for it
|
||||
case 1: // sysinfo message
|
||||
{
|
||||
byte mac[6];
|
||||
@@ -149,70 +108,13 @@ void checkUDP()
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.Data = (byte*)packetBuffer;
|
||||
TempEvent.Par1 = remoteIP[3];
|
||||
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
|
||||
CPluginCall(CPLUGIN_UDP_IN, &TempEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,73 +123,6 @@ void checkUDP()
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task info using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
infoReply.destUnit = x;
|
||||
sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task data using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
dataReply.destUnit = x;
|
||||
sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send event using UDP message
|
||||
\*********************************************************************************************/
|
||||
@@ -747,6 +582,11 @@ bool WiFiConnected(uint32_t timeout_ms) {
|
||||
yield(); // Allow at least once time for backgroundtasks
|
||||
min_delay = 10;
|
||||
}
|
||||
if (!wifiConnected) {
|
||||
// Apparently something needs network, perform check to see if it is ready now.
|
||||
if (tryConnectWiFi())
|
||||
checkWifiJustConnected();
|
||||
}
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
if (timeOutReached(timer)) {
|
||||
return false;
|
||||
|
||||
@@ -288,6 +288,8 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
|
||||
if (s.indexOf(F("%sys")) != -1) {
|
||||
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
|
||||
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
|
||||
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
|
||||
SMART_REPL(F("%systime%"), getTimeString(':'))
|
||||
SMART_REPL(F("%systime_am%"), getTimeString_ampm(':'))
|
||||
repl(F("%sysname%"), Settings.Name, s, useURLencode);
|
||||
|
||||
+21
-11
@@ -390,30 +390,40 @@ String getDateString()
|
||||
|
||||
// returns the current Time separated by the given delimiter
|
||||
// time format example with ':' delimiter: 23:59:59 (HH:MM:SS)
|
||||
String getTimeString(const timeStruct& ts, char delimiter, bool am_pm)
|
||||
String getTimeString(const timeStruct& ts, char delimiter, bool am_pm, bool show_seconds)
|
||||
{
|
||||
char TimeString[20]; //19 digits plus the null char
|
||||
if (am_pm) {
|
||||
uint8_t hour(ts.Hour % 12);
|
||||
if (hour == 0) { hour = 12; }
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d%cm"),
|
||||
hour, delimiter, ts.Minute, delimiter, ts.Second,
|
||||
ts.Hour < 12 ? 'a' : 'p');
|
||||
const char a_or_p = ts.Hour < 12 ? 'A' : 'P';
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, delimiter, ts.Second, a_or_p);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, a_or_p);
|
||||
}
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute);
|
||||
}
|
||||
}
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String getTimeString(char delimiter)
|
||||
String getTimeString(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter, false);
|
||||
return getTimeString(tm, delimiter, false, show_seconds);
|
||||
}
|
||||
|
||||
String getTimeString_ampm(char delimiter)
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter, true);
|
||||
return getTimeString(tm, delimiter, true, show_seconds);
|
||||
}
|
||||
|
||||
// returns the current Time without delimiter
|
||||
@@ -436,7 +446,7 @@ String getDateTimeString(const timeStruct& ts, char dateDelimiter, char timeDeli
|
||||
String ret = getDateString(ts, dateDelimiter);
|
||||
if (dateTimeDelimiter != '\0')
|
||||
ret += dateTimeDelimiter;
|
||||
ret += getTimeString(ts, timeDelimiter, am_pm);
|
||||
ret += getTimeString(ts, timeDelimiter, am_pm, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+115
-83
@@ -76,6 +76,15 @@ public:
|
||||
}
|
||||
|
||||
void startStream() {
|
||||
startStream(false);
|
||||
}
|
||||
|
||||
void startJsonStream() {
|
||||
startStream(true);
|
||||
}
|
||||
|
||||
private:
|
||||
void startStream(bool json) {
|
||||
maxCoreUsage = maxServerUsage = 0;
|
||||
initialRam = ESP.getFreeHeap();
|
||||
beforeTXRam = initialRam;
|
||||
@@ -87,7 +96,7 @@ public:
|
||||
tcpCleanup();
|
||||
return;
|
||||
} else
|
||||
sendHeaderBlocking();
|
||||
sendHeaderBlocking(json);
|
||||
}
|
||||
|
||||
void trackTotalMem() {
|
||||
@@ -96,6 +105,8 @@ public:
|
||||
maxServerUsage = initialRam - beforeTXRam;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void trackCoreMem() {
|
||||
duringTXRam = ESP.getFreeHeap();
|
||||
if ((initialRam - duringTXRam) > maxCoreUsage)
|
||||
@@ -156,14 +167,14 @@ void sendContentBlocking(String& data) {
|
||||
data = "";
|
||||
}
|
||||
|
||||
void sendHeaderBlocking() {
|
||||
void sendHeaderBlocking(bool json) {
|
||||
checkRAM(F("sendHeaderBlocking"));
|
||||
#if defined(ESP8266) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
|
||||
WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
WebServer.sendHeader("Content-Type", "text/html", true);
|
||||
WebServer.sendHeader("Accept-Ranges", "none");
|
||||
WebServer.sendHeader("Cache-Control", "no-cache");
|
||||
WebServer.sendHeader("Transfer-Encoding", "chunked");
|
||||
WebServer.sendHeader(F("Content-Type"), json ? F("application/json") : F("text/html"), true);
|
||||
WebServer.sendHeader(F("Accept-Ranges"), F("none"));
|
||||
WebServer.sendHeader(F("Cache-Control"), F("no-cache"));
|
||||
WebServer.sendHeader(F("Transfer-Encoding"), F("chunked"));
|
||||
WebServer.send(200);
|
||||
#else
|
||||
unsigned int timeout = 0;
|
||||
@@ -172,8 +183,8 @@ void sendHeaderBlocking() {
|
||||
if (freeBeforeSend < 4000) timeout = 1000;
|
||||
const uint32_t beginWait = millis();
|
||||
WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
WebServer.sendHeader("Content-Type", "text/html", true);
|
||||
WebServer.sendHeader("Cache-Control", "no-cache");
|
||||
WebServer.sendHeader(F("Content-Type"), json ? F("application/json") : F("text/html"), true);
|
||||
WebServer.sendHeader(F("Cache-Control"), F("no-cache"));
|
||||
WebServer.send(200);
|
||||
// dont wait on 2.3.0. Memory returns just too slow.
|
||||
while ((ESP.getFreeHeap() < freeBeforeSend) &&
|
||||
@@ -1069,6 +1080,7 @@ void handle_controllers() {
|
||||
copyFormPassword(F("controllerpassword"), SecuritySettings.ControllerPassword[controllerindex], sizeof(SecuritySettings.ControllerPassword[0]));
|
||||
strncpy(ControllerSettings.Subscribe, controllersubscribe.c_str(), sizeof(ControllerSettings.Subscribe));
|
||||
strncpy(ControllerSettings.Publish, controllerpublish.c_str(), sizeof(ControllerSettings.Publish));
|
||||
CPlugin_ptr[ProtocolIndex](CPLUGIN_INIT, &TempEvent, dummyString);
|
||||
}
|
||||
}
|
||||
addHtmlError( TXBuffer.buf, SaveControllerSettings(controllerindex, (byte*)&ControllerSettings, sizeof(ControllerSettings)));
|
||||
@@ -1147,57 +1159,61 @@ void handle_controllers() {
|
||||
options[0] = F("Use IP address");
|
||||
options[1] = F("Use Hostname");
|
||||
|
||||
addFormSelector(TXBuffer.buf, F("Locate Controller"), F("usedns"), 2, options, NULL, NULL, choice, true);
|
||||
|
||||
if (ControllerSettings.UseDNS)
|
||||
{
|
||||
addFormTextBox(TXBuffer.buf, F("Controller Hostname"), F("controllerhostname"), ControllerSettings.HostName, sizeof(ControllerSettings.HostName)-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
addFormIPBox(TXBuffer.buf, F("Controller IP"), F("controllerip"), ControllerSettings.IP);
|
||||
}
|
||||
|
||||
addFormNumericBox(TXBuffer.buf, F("Controller Port"), F("controllerport"), ControllerSettings.Port, 1, 65535);
|
||||
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[controllerindex]);
|
||||
if (Protocol[ProtocolIndex].usesAccount)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_USER, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller User");
|
||||
if (!Protocol[ProtocolIndex].Custom){
|
||||
|
||||
addFormSelector(TXBuffer.buf, F("Locate Controller"), F("usedns"), 2, options, NULL, NULL, choice, true);
|
||||
|
||||
if (ControllerSettings.UseDNS)
|
||||
{
|
||||
addFormTextBox(TXBuffer.buf, F("Controller Hostname"), F("controllerhostname"), ControllerSettings.HostName, sizeof(ControllerSettings.HostName)-1);
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controlleruser"), SecuritySettings.ControllerUser[controllerindex], sizeof(SecuritySettings.ControllerUser[0])-1);
|
||||
}
|
||||
if (Protocol[ProtocolIndex].usesPassword)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_PASS, protoDisplayName)) {
|
||||
// It is not a regular password, thus use normal text field.
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllerpassword"), SecuritySettings.ControllerPassword[controllerindex], sizeof(SecuritySettings.ControllerPassword[0])-1);
|
||||
} else {
|
||||
addFormPasswordBox(TXBuffer.buf, F("Controller Password"), F("controllerpassword"), SecuritySettings.ControllerPassword[controllerindex], sizeof(SecuritySettings.ControllerPassword[0])-1);
|
||||
else
|
||||
{
|
||||
addFormIPBox(TXBuffer.buf, F("Controller IP"), F("controllerip"), ControllerSettings.IP);
|
||||
}
|
||||
|
||||
addFormNumericBox(TXBuffer.buf, F("Controller Port"), F("controllerport"), ControllerSettings.Port, 1, 65535);
|
||||
|
||||
if (Protocol[ProtocolIndex].usesAccount)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_USER, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller User");
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controlleruser"), SecuritySettings.ControllerUser[controllerindex], sizeof(SecuritySettings.ControllerUser[0])-1);
|
||||
}
|
||||
if (Protocol[ProtocolIndex].usesPassword)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_PASS, protoDisplayName)) {
|
||||
// It is not a regular password, thus use normal text field.
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllerpassword"), SecuritySettings.ControllerPassword[controllerindex], sizeof(SecuritySettings.ControllerPassword[0])-1);
|
||||
} else {
|
||||
addFormPasswordBox(TXBuffer.buf, F("Controller Password"), F("controllerpassword"), SecuritySettings.ControllerPassword[controllerindex], sizeof(SecuritySettings.ControllerPassword[0])-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_SUBSCRIBE, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller Subscribe");
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllersubscribe"), ControllerSettings.Subscribe, sizeof(ControllerSettings.Subscribe)-1);
|
||||
}
|
||||
|
||||
if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_PUBLISH, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller Publish");
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllerpublish"), ControllerSettings.Publish, sizeof(ControllerSettings.Publish)-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_SUBSCRIBE, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller Subscribe");
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllersubscribe"), ControllerSettings.Subscribe, sizeof(ControllerSettings.Subscribe)-1);
|
||||
}
|
||||
|
||||
if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
String protoDisplayName;
|
||||
if (!getControllerProtocolDisplayName(ProtocolIndex, CONTROLLER_PUBLISH, protoDisplayName)) {
|
||||
protoDisplayName = F("Controller Publish");
|
||||
}
|
||||
addFormTextBox(TXBuffer.buf, protoDisplayName, F("controllerpublish"), ControllerSettings.Publish, sizeof(ControllerSettings.Publish)-1);
|
||||
}
|
||||
|
||||
addFormCheckBox(TXBuffer.buf, F("Enabled"), F("controllerenabled"), Settings.ControllerEnabled[controllerindex]);
|
||||
|
||||
TempEvent.ControllerIndex = controllerindex;
|
||||
@@ -1705,18 +1721,6 @@ void handle_devices() {
|
||||
if (Device[DeviceIndex].InverseLogicOption)
|
||||
Settings.TaskDevicePin1Inversed[taskIndex] = (WebServer.arg(F("TDPI")) == F("on"));
|
||||
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
if (Device[DeviceIndex].GlobalSyncOption)
|
||||
Settings.TaskDeviceGlobalSync[taskIndex] = (WebServer.arg(F("TDGS")) == F("on"));
|
||||
|
||||
// Send task info if set global
|
||||
if (Settings.TaskDeviceGlobalSync[taskIndex])
|
||||
{
|
||||
SendUDPTaskInfo(0, taskIndex, taskIndex);
|
||||
}
|
||||
}
|
||||
|
||||
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
||||
{
|
||||
|
||||
@@ -1744,6 +1748,18 @@ void handle_devices() {
|
||||
|
||||
//allow the plugin to save plugin-specific form settings.
|
||||
PluginCall(PLUGIN_WEBFORM_SAVE, &TempEvent, dummyString);
|
||||
|
||||
// notify controllers: CPLUGIN_TASK_CHANGE_NOTIFICATION
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
{
|
||||
TempEvent.ControllerIndex = x;
|
||||
if (Settings.TaskDeviceSendData[TempEvent.ControllerIndex][TempEvent.TaskIndex] &&
|
||||
Settings.ControllerEnabled[TempEvent.ControllerIndex] && Settings.Protocol[TempEvent.ControllerIndex])
|
||||
{
|
||||
TempEvent.ProtocolIndex = getProtocolIndex(Settings.Protocol[TempEvent.ControllerIndex]);
|
||||
CPlugin_ptr[TempEvent.ProtocolIndex](CPLUGIN_TASK_CHANGE_NOTIFICATION, &TempEvent, dummyString);
|
||||
}
|
||||
}
|
||||
}
|
||||
addHtmlError( SaveTaskSettings(taskIndex));
|
||||
|
||||
@@ -1942,11 +1958,6 @@ void handle_devices() {
|
||||
|
||||
addFormCheckBox(TXBuffer.buf, F("Enabled"), F("TDE"), Settings.TaskDeviceEnabled[taskIndex]); //="taskdeviceenabled"
|
||||
|
||||
if (Settings.GlobalSync && Device[DeviceIndex].GlobalSyncOption && Settings.TaskDeviceDataFeed[taskIndex] == 0 && Settings.UDPPort != 0)
|
||||
{
|
||||
addFormCheckBox(TXBuffer.buf, F("Global Sync"), F("TDGS"), Settings.TaskDeviceGlobalSync[taskIndex]); //="taskdeviceglobalsync"
|
||||
}
|
||||
|
||||
// section: Sensor / Actuator
|
||||
if (!Device[DeviceIndex].Custom && Settings.TaskDeviceDataFeed[taskIndex] == 0 &&
|
||||
((Device[DeviceIndex].Ports != 0) || (Device[DeviceIndex].PullUpOption) || (Device[DeviceIndex].InverseLogicOption) || (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)) )
|
||||
@@ -3290,8 +3301,7 @@ void handle_login() {
|
||||
//********************************************************************************
|
||||
void handle_control() {
|
||||
//TXBuffer.startStream(true); // true= json
|
||||
// sendHeadandTail(F("TmplStd"),_HEAD);
|
||||
|
||||
// sendHeadandTail(F("TmplStd"),_HEAD);
|
||||
String webrequest = WebServer.arg(F("cmd"));
|
||||
|
||||
// in case of event, store to buffer and return...
|
||||
@@ -3310,18 +3320,18 @@ void handle_control() {
|
||||
printToWeb = true;
|
||||
printWebString = "";
|
||||
|
||||
if (printToWebJSON)
|
||||
TXBuffer.startJsonStream();
|
||||
else
|
||||
TXBuffer.startStream();
|
||||
|
||||
if (PluginCall(PLUGIN_WRITE, &TempEvent, webrequest));
|
||||
else if (remoteConfig(&TempEvent, webrequest));
|
||||
else
|
||||
TXBuffer += F("Unknown or restricted command!");
|
||||
|
||||
TXBuffer += printWebString;
|
||||
|
||||
if (printToWebJSON)
|
||||
WebServer.send(200, "application/json");
|
||||
else
|
||||
WebServer.send(200, "text/html");
|
||||
TXBuffer += printWebString;
|
||||
TXBuffer.endStream();
|
||||
|
||||
printWebString = "";
|
||||
printToWeb = false;
|
||||
@@ -3347,10 +3357,34 @@ void handle_json()
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Unit"), String(Settings.Unit));
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Name"), String(Settings.Name));
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Uptime"), String(wdcounter / 2));
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Free RAM"), String(ESP.getFreeHeap()));
|
||||
reply += F("\n},\n");
|
||||
|
||||
reply += F("\"WiFi\":{\n");
|
||||
reply += to_json_object_value(F("Hostname"), WiFi.hostname());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("IP"), WiFi.localIP().toString());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Subnet Mask"), WiFi.subnetMask().toString());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("Gateway IP"), WiFi.gatewayIP().toString());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("MAC address"), WiFi.macAddress());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("DNS 1"), WiFi.dnsIP(0).toString());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("DNS 2"), WiFi.dnsIP(1).toString());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("SSID"), WiFi.SSID());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("BSSID"), WiFi.BSSIDstr());
|
||||
reply += F(",\n");
|
||||
reply += to_json_object_value(F("RSSI"), String(WiFi.RSSI()));
|
||||
reply += F("\n},\n");
|
||||
}
|
||||
|
||||
byte taskNr = tasknr.toInt();
|
||||
@@ -3443,7 +3477,6 @@ void handle_advanced() {
|
||||
String usessdp = WebServer.arg(F("usessdp"));
|
||||
String edit = WebServer.arg(F("edit"));
|
||||
String wireclockstretchlimit = WebServer.arg(F("wireclockstretchlimit"));
|
||||
String globalsync = WebServer.arg(F("globalsync"));
|
||||
String userules = WebServer.arg(F("userules"));
|
||||
String cft = WebServer.arg(F("cft"));
|
||||
String MQTTRetainFlag = WebServer.arg(F("mqttretainflag"));
|
||||
@@ -3475,7 +3508,6 @@ void handle_advanced() {
|
||||
Settings.UseSSDP = (usessdp == "on");
|
||||
Settings.WireClockStretchLimit = wireclockstretchlimit.toInt();
|
||||
Settings.UseRules = (userules == "on");
|
||||
Settings.GlobalSync = (globalsync == "on");
|
||||
Settings.ConnectionFailuresThreshold = cft.toInt();
|
||||
Settings.MQTTRetainFlag = (MQTTRetainFlag == "on");
|
||||
|
||||
@@ -3530,9 +3562,8 @@ void handle_advanced() {
|
||||
addFormNumericBox(TXBuffer.buf, F("Baud Rate"), F("baudrate"), Settings.BaudRate, 0, 1000000);
|
||||
|
||||
|
||||
addFormSubHeader(TXBuffer.buf, F("Inter-ESPEasy Network (experimental)"));
|
||||
addFormSubHeader(TXBuffer.buf, F("Inter-ESPEasy Network"));
|
||||
|
||||
addFormCheckBox( TXBuffer.buf, F("Global Sync"), F("globalsync"), Settings.GlobalSync);
|
||||
addFormNumericBox(TXBuffer.buf, F("UDP port"), F("udpport"), Settings.UDPPort, 0, 65535);
|
||||
|
||||
|
||||
@@ -4469,6 +4500,7 @@ void handle_rules() {
|
||||
|
||||
TXBuffer += F("<TR><TD>Edit: ");
|
||||
addSelector(TXBuffer.buf, F("set"), RULESETS_MAX, options, optionValues, NULL, choice, true);
|
||||
addButton(TXBuffer.buf, fileName, F("Download to file"));
|
||||
addHelpButton(TXBuffer.buf, F("Tutorial_Rules"));
|
||||
|
||||
// load form data from flash
|
||||
|
||||
+269
-108
@@ -4,7 +4,7 @@
|
||||
String WifiGetAPssid()
|
||||
{
|
||||
String ssid(Settings.Name);
|
||||
ssid+=F("_");
|
||||
ssid+=F("-");
|
||||
ssid+=Settings.Unit;
|
||||
return (ssid);
|
||||
}
|
||||
@@ -27,7 +27,10 @@ void WifiAPconfig()
|
||||
{
|
||||
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
|
||||
// setup ssid for AP Mode when needed
|
||||
WiFi.softAP(WifiGetAPssid().c_str(), SecuritySettings.WifiAPKey);
|
||||
|
||||
String softAPSSID=WifiGetAPssid();
|
||||
String pwd = SecuritySettings.WifiAPKey;
|
||||
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
|
||||
// We start in STA mode
|
||||
WifiAPMode(false);
|
||||
|
||||
@@ -75,10 +78,9 @@ void WifiAPMode(boolean state)
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
// Set Wifi config
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
bool prepareWiFi() {
|
||||
String log = "";
|
||||
char hostname[40];
|
||||
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
|
||||
@@ -98,132 +100,284 @@ boolean WifiConnect(byte connectAttempts)
|
||||
IPAddress dns = Settings.DNS;
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
return selectValidWiFiSettings();
|
||||
}
|
||||
|
||||
//try to connect to one of the access points
|
||||
if (WifiConnectSSID(SecuritySettings.WifiSSID, SecuritySettings.WifiKey, connectAttempts) ||
|
||||
WifiConnectSSID(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2, connectAttempts))
|
||||
{
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
//********************************************************************************
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
if (prepareWiFi()) {
|
||||
//try to connect to one of the access points
|
||||
bool connected = WifiConnectAndWait(connectAttempts);
|
||||
if (!connected) {
|
||||
if (selectNextWiFiSettings()) {
|
||||
connected = WifiConnectAndWait(connectAttempts);
|
||||
}
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("WiFi#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
return(true);
|
||||
if (connected) {
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
|
||||
//everything failed, activate AP mode (will deactivate automaticly after a while if its connected again)
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Start connect to WiFi and check later to see if connected.
|
||||
//********************************************************************************
|
||||
void WiFiConnectRelaxed() {
|
||||
wifiConnected = false;
|
||||
wifi_connect_attempt = 0;
|
||||
if (prepareWiFi()) {
|
||||
tryConnectWiFi();
|
||||
return;
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP, no valid WiFi settings!"));
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Manage WiFi credentials
|
||||
//********************************************************************************
|
||||
const char* getLastWiFiSettingsSSID() {
|
||||
return lastWiFiSettings == 0 ? SecuritySettings.WifiSSID : SecuritySettings.WifiSSID2;
|
||||
}
|
||||
|
||||
const char* getLastWiFiSettingsPassphrase() {
|
||||
return lastWiFiSettings == 0 ? SecuritySettings.WifiKey : SecuritySettings.WifiKey2;
|
||||
}
|
||||
|
||||
bool anyValidWifiSettings() {
|
||||
if (wifiSettingsValid(SecuritySettings.WifiSSID, SecuritySettings.WifiKey))
|
||||
return true;
|
||||
if (wifiSettingsValid(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2))
|
||||
return true;
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool selectNextWiFiSettings() {
|
||||
uint8_t tmp = lastWiFiSettings;
|
||||
lastWiFiSettings = (lastWiFiSettings + 1) % 2;
|
||||
if (!wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase())) {
|
||||
// other settings are not correct, switch back.
|
||||
lastWiFiSettings = tmp;
|
||||
return false; // Nothing changed.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool selectValidWiFiSettings() {
|
||||
if (wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase()))
|
||||
return true;
|
||||
return selectNextWiFiSettings();
|
||||
}
|
||||
|
||||
bool wifiSettingsValid(const char* ssid, const char* pass) {
|
||||
if (ssid[0] == 0 || (strcasecmp(ssid, "ssid") == 0)) {
|
||||
return false;
|
||||
}
|
||||
if (pass[0] == 0) return false;
|
||||
if (strlen(ssid) > 32) return false;
|
||||
if (strlen(pass) > 64) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wifiConnectTimeoutReached() {
|
||||
if (wifi_connect_attempt == 0) return true;
|
||||
if (wifiSetupConnect) {
|
||||
// Initial setup of WiFi, may take much longer since accesspoint is still active.
|
||||
return timeOutReached(wifi_connect_timer + 20000);
|
||||
}
|
||||
// wait until it connects + add some device specific random offset to prevent
|
||||
// all nodes overloading the accesspoint when turning on at the same time.
|
||||
const unsigned int randomOffset_in_sec = wifi_connect_attempt == 1 ? 0 : 1000 * ((ESP.getChipId() & 0xF));
|
||||
return timeOutReached(wifi_connect_timer + DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_sec);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Simply start the WiFi connection sequence
|
||||
//********************************************************************************
|
||||
bool tryConnectWiFi() {
|
||||
if (wifiSetup && !wifiSetupConnect)
|
||||
return false;
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true); //already connected, need to disconnect first
|
||||
if (!wifiConnectTimeoutReached())
|
||||
return true; // timeout not reached yet, thus no need to retry again.
|
||||
if (!anyValidWifiSettings())
|
||||
return false;
|
||||
|
||||
if (wifi_connect_attempt != 0 && ((wifi_connect_attempt % 3) == 0)) {
|
||||
// Change to other wifi settings.
|
||||
if (selectNextWiFiSettings())
|
||||
WiFi.disconnect();
|
||||
}
|
||||
if (wifi_connect_attempt > 6) {
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
}
|
||||
String ssid;
|
||||
ssid.reserve(32);
|
||||
String passphrase;
|
||||
passphrase.reserve(64);
|
||||
ssid = getLastWiFiSettingsSSID();
|
||||
passphrase = getLastWiFiSettingsPassphrase();
|
||||
String log = F("WIFI : Connecting ");
|
||||
log += ssid;
|
||||
log += F(" attempt #");
|
||||
log += wifi_connect_attempt;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
wifi_connect_timer = millis();
|
||||
switch (wifi_connect_attempt) {
|
||||
case 0:
|
||||
if (lastBSSID[0] == 0)
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str());
|
||||
else
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str(), 0, &lastBSSID[0]);
|
||||
break;
|
||||
default:
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str());
|
||||
}
|
||||
++wifi_connect_attempt;
|
||||
switch (WiFi.status()) {
|
||||
case WL_NO_SSID_AVAIL: {
|
||||
log = F("WIFI : No SSID found matching: ");
|
||||
log += ssid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
return false;
|
||||
}
|
||||
case WL_CONNECT_FAILED: {
|
||||
log = F("WIFI : Connection failed to: ");
|
||||
log += ssid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
return false;
|
||||
}
|
||||
case WL_CONNECTED:
|
||||
checkWifiJustConnected();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true; // Sent
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Connect to Wifi specific SSID
|
||||
//********************************************************************************
|
||||
boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
boolean WifiConnectAndWait(byte connectAttempts)
|
||||
{
|
||||
String log;
|
||||
|
||||
//already connected, need to disconnect first
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true);
|
||||
|
||||
//no ssid specified
|
||||
if ((WifiSSID[0] == 0) || (strcasecmp(WifiSSID, "ssid") == 0))
|
||||
return(false);
|
||||
|
||||
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
|
||||
wifiConnected = false;
|
||||
wifi_connect_attempt = 0;
|
||||
for (byte tryConnect = 0; tryConnect < connectAttempts; tryConnect++)
|
||||
{
|
||||
log = F("WIFI : Connecting ");
|
||||
log += WifiSSID;
|
||||
log += F(" attempt #");
|
||||
log += tryConnect;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (tryConnect == 1)
|
||||
WiFi.begin(WifiSSID, WifiKey);
|
||||
else
|
||||
WiFi.begin();
|
||||
|
||||
//wait until it connects
|
||||
for (byte x = 0; x < 200; x++)
|
||||
{
|
||||
if (!WiFiConnected(50))
|
||||
{
|
||||
statusLED(false);
|
||||
// No delay needed, since the WiFi check has a delay
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (tryConnectWiFi()) {
|
||||
do {
|
||||
if (checkWifiJustConnected())
|
||||
return true;
|
||||
delay(50);
|
||||
} while (!wifiConnectTimeoutReached());
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
if (Settings.UseNTP) {
|
||||
initTime();
|
||||
}
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
log += str;
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(")");
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
#if defined(ESP8266)
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
#endif
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkWifiJustConnected() {
|
||||
if (wifiConnected) return true;
|
||||
delay(1);
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
statusLED(false);
|
||||
return false;
|
||||
}
|
||||
wifiConnected = true;
|
||||
String log = F("WIFI : WiFi connect attempt took: ");
|
||||
log += timePassedSince(wifi_connect_timer);
|
||||
log += F(" ms");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
}
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
|
||||
// First try to get the time, since that may be used in logs
|
||||
if (Settings.UseNTP) {
|
||||
initTime();
|
||||
}
|
||||
uint8_t* curBSSID = WiFi.BSSID();
|
||||
bool changed = false;
|
||||
for (byte i=0; i < 6; ++i) {
|
||||
if (lastBSSID[i] != *(curBSSID + i)) {
|
||||
changed = true;
|
||||
lastBSSID[i] = *(curBSSID + i);
|
||||
}
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
if (changed) {
|
||||
String event = F("WiFi#ChangedAccesspoint");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
String event = F("WiFi#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
log += formatIP(WiFi.localIP());
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(") AP: ");
|
||||
log += WiFi.SSID();
|
||||
log += F(" AP BSSID: ");
|
||||
log += WiFi.BSSIDstr();
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Disconnect from Wifi AP
|
||||
@@ -231,6 +385,7 @@ boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
void WifiDisconnect()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
wifiConnected = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +427,6 @@ void WifiScan()
|
||||
//********************************************************************************
|
||||
void WifiCheck()
|
||||
{
|
||||
|
||||
if(wifiSetup)
|
||||
return;
|
||||
|
||||
@@ -282,8 +436,11 @@ void WifiCheck()
|
||||
//give it time to automaticly reconnect
|
||||
if (NC_Count > 2)
|
||||
{
|
||||
WifiConnect(2);
|
||||
|
||||
if (wifiConnected) {
|
||||
wifi_connect_attempt = 0;
|
||||
wifiConnected = false;
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
C_Count=0;
|
||||
NC_Count = 0;
|
||||
}
|
||||
@@ -298,4 +455,8 @@ void WifiCheck()
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
if (!wifiConnected) {
|
||||
if (tryConnectWiFi())
|
||||
checkWifiJustConnected();
|
||||
}
|
||||
}
|
||||
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 013: ESPEasy P2P network ################################
|
||||
//#######################################################################################################
|
||||
|
||||
#define CPLUGIN_013
|
||||
#define CPLUGIN_ID_013 13
|
||||
#define CPLUGIN_NAME_013 "ESPEasy P2P Networking"
|
||||
|
||||
WiFiUDP C013_portUDP;
|
||||
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
|
||||
boolean CPlugin_013(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_013;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesTemplate = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesPassword = false;
|
||||
Protocol[protocolCount].defaultPort = 65501;
|
||||
Protocol[protocolCount].usesID = false;
|
||||
Protocol[protocolCount].Custom = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(CPLUGIN_NAME_013);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_TEMPLATE:
|
||||
{
|
||||
event->String1 = "";
|
||||
event->String2 = "";
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
//C013_portUDP.begin(Settings.UDPPort);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_TASK_CHANGE_NOTIFICATION:
|
||||
{
|
||||
C013_SendUDPTaskInfo(0, event->TaskIndex, event->TaskIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
C013_Send(event, 0, UserVar[event->BaseVarIndex], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_UDP_IN:
|
||||
{
|
||||
C013_Receive(event);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Generic UDP message
|
||||
//********************************************************************************
|
||||
void C013_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
statusLED(true);
|
||||
C013_SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
infoReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
dataReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send UDP message (unit 255=broadcast)
|
||||
\*********************************************************************************************/
|
||||
void C013_sendUDP(byte unit, byte* data, byte size)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
if (unit != 255)
|
||||
if (Nodes[unit].ip[0] == 0)
|
||||
return;
|
||||
String log = "C013 : Send UDP message to ";
|
||||
log += unit;
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
statusLED(true);
|
||||
|
||||
IPAddress remoteNodeIP;
|
||||
if (unit == 255)
|
||||
remoteNodeIP = {255, 255, 255, 255};
|
||||
else
|
||||
remoteNodeIP = Nodes[unit].ip;
|
||||
C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort);
|
||||
C013_portUDP.write(data, size);
|
||||
C013_portUDP.endPacket();
|
||||
}
|
||||
|
||||
void C013_Receive(struct EventStruct *event) {
|
||||
|
||||
if (event->Data[1] > 1 && event->Data[1] < 6)
|
||||
{
|
||||
String log = (F("C013 : msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)event->Data[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
switch (event->Data[1]) {
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
//SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)event->Data, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x = 0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
//SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)event->Data, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-17
@@ -226,7 +226,22 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
if (argIndex)
|
||||
tmpString = tmpString.substring(0, argIndex);
|
||||
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCD")))
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCDCMD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
if (tmpString.equalsIgnoreCase(F("Off"))){
|
||||
lcd->noBacklight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("On"))){
|
||||
lcd->backlight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear"))){
|
||||
lcd->clear();
|
||||
}
|
||||
}
|
||||
else if (lcd && tmpString.equalsIgnoreCase(F("LCD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
@@ -281,22 +296,6 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCDCMD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
if (tmpString.equalsIgnoreCase(F("Off"))){
|
||||
lcd->noBacklight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("On"))){
|
||||
lcd->backlight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear"))){
|
||||
lcd->clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -184,14 +184,6 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
int argIndex = tmpString.indexOf(',');
|
||||
if (argIndex)
|
||||
tmpString = tmpString.substring(0, argIndex);
|
||||
if (tmpString.equalsIgnoreCase(F("OLED")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
String newString = P023_parseTemplate(tmpString, 16);
|
||||
Plugin_023_sendStrXY(newString.c_str(), event->Par1 - 1, event->Par2 - 1);
|
||||
}
|
||||
if (tmpString.equalsIgnoreCase(F("OLEDCMD")))
|
||||
{
|
||||
success = true;
|
||||
@@ -204,9 +196,16 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear")))
|
||||
Plugin_023_clear_display();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("OLED")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
String newString = P023_parseTemplate(tmpString, 16);
|
||||
Plugin_023_sendStrXY(newString.c_str(), event->Par1 - 1, event->Par2 - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
+7
-7
@@ -199,13 +199,13 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
|
||||
if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1
|
||||
if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1);
|
||||
|
||||
if (IrType.equalsIgnoreCase("NEC")) Plugin_035_irSender->sendNEC(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("JVC")) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
|
||||
if (IrType.equalsIgnoreCase("RC5")) Plugin_035_irSender->sendRC5(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("RC6")) Plugin_035_irSender->sendRC6(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("SAMSUNG")) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("SONY")) Plugin_035_irSender->sendSony(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("PANASONIC")) Plugin_035_irSender->sendPanasonic(IrBits, IrCode);
|
||||
if (IrType.equalsIgnoreCase(F("NEC"))) Plugin_035_irSender->sendNEC(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("JVC"))) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
|
||||
if (IrType.equalsIgnoreCase(F("RC5"))) Plugin_035_irSender->sendRC5(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("RC6"))) Plugin_035_irSender->sendRC6(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("SAMSUNG"))) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("SONY"))) Plugin_035_irSender->sendSony(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("PANASONIC"))) Plugin_035_irSender->sendPanasonic(IrBits, IrCode);
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("IRTX :IR Code Sent"));
|
||||
|
||||
@@ -102,18 +102,17 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
|
||||
String tmpString = string;
|
||||
|
||||
String cmd = parseString(tmpString, 1);
|
||||
String param1 = parseString(tmpString, 2);
|
||||
String param2 = parseString(tmpString, 3);
|
||||
String param3 = parseString(tmpString, 4);
|
||||
String param4 = parseString(tmpString, 5);
|
||||
String param5 = parseString(tmpString, 6);
|
||||
|
||||
|
||||
// Commands:
|
||||
// MotorShieldCMD,<DCMotor>,<Motornumber>,<Forward/Backward/Release>,<Speed>
|
||||
|
||||
if (cmd.equalsIgnoreCase(F("MotorShieldCMD")))
|
||||
{
|
||||
String param1 = parseString(tmpString, 2);
|
||||
String param2 = parseString(tmpString, 3);
|
||||
String param3 = parseString(tmpString, 4);
|
||||
String param4 = parseString(tmpString, 5);
|
||||
String param5 = parseString(tmpString, 6);
|
||||
|
||||
// Create the motor shield object with the default I2C address
|
||||
AFMS = Adafruit_MotorShield(Plugin_048_MotorShield_address);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
// Transceiver:
|
||||
// SN75176 or MAX485 or LT1785 or ...
|
||||
// Pin 5: GND
|
||||
// Pin 2, 3, 5: +5V
|
||||
// Pin 2, 3, 8: +5V
|
||||
// Pin 4: to ESP D4
|
||||
// Pin 6: DMX+ (hot)
|
||||
// Pin 7: DMX- (cold)
|
||||
|
||||
@@ -167,6 +167,26 @@ boolean Plugin_059(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (Plugin_059_QE)
|
||||
{
|
||||
String log = "";
|
||||
String command = parseString(string, 1);
|
||||
if (command == F("encwrite"))
|
||||
{
|
||||
if (event->Par1 >= 0)
|
||||
{
|
||||
log = String(F("QEI : ")) + string;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Plugin_059_QE->write(event->Par1);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -81,11 +81,11 @@ boolean Plugin_060(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_060_cal"), CONFIG(3));
|
||||
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_060_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_060_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 4095);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_060_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_060_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 4095);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
|
||||
|
||||
+8
-8
@@ -87,7 +87,7 @@ void SHT3X::get()
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
SHT3X* Plugin_068_SHT3x = NULL;
|
||||
SHT3X* Plugin_068_SHT3x[TASKS_MAX] = { NULL, };
|
||||
|
||||
|
||||
//==============================================
|
||||
@@ -148,9 +148,9 @@ boolean Plugin_068(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Plugin_068_SHT3x)
|
||||
delete Plugin_068_SHT3x;
|
||||
Plugin_068_SHT3x = new SHT3X(CONFIG(0));
|
||||
if (Plugin_068_SHT3x[event->TaskIndex])
|
||||
delete Plugin_068_SHT3x[event->TaskIndex];
|
||||
Plugin_068_SHT3x[event->TaskIndex] = new SHT3X(CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -158,12 +158,12 @@ boolean Plugin_068(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!Plugin_068_SHT3x)
|
||||
if (!Plugin_068_SHT3x[event->TaskIndex])
|
||||
return success;
|
||||
|
||||
Plugin_068_SHT3x->get();
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_068_SHT3x->tmp;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_068_SHT3x->hum;
|
||||
Plugin_068_SHT3x[event->TaskIndex]->get();
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_068_SHT3x[event->TaskIndex]->tmp;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_068_SHT3x[event->TaskIndex]->hum;
|
||||
String log = F("SHT3x: Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex + 0];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
+4
-2
@@ -41,7 +41,7 @@ class p073_7dgt
|
||||
byte brightness;
|
||||
boolean timesep;
|
||||
};
|
||||
p073_7dgt *Plugin_073_7dgt;
|
||||
p073_7dgt *Plugin_073_7dgt = NULL;
|
||||
//---------------------------------------------------
|
||||
|
||||
uint8_t p073_showbuffer[8];
|
||||
@@ -236,6 +236,7 @@ boolean Plugin_073(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
} else if (tmpString.equalsIgnoreCase(F("7dt"))) {
|
||||
if (Plugin_073_7dgt->output != 0)
|
||||
break;
|
||||
@@ -291,6 +292,7 @@ boolean Plugin_073(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
} else {
|
||||
bool p073_validcmd = false;
|
||||
bool p073_displayon;
|
||||
@@ -317,6 +319,7 @@ boolean Plugin_073(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
if (p073_validcmd) {
|
||||
success = true;
|
||||
switch (Plugin_073_7dgt->type)
|
||||
{
|
||||
case 0:
|
||||
@@ -331,7 +334,6 @@ boolean Plugin_073(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ void CPluginInit(void)
|
||||
#endif
|
||||
|
||||
CPluginCall(CPLUGIN_PROTOCOL_ADD, 0);
|
||||
CPluginCall(CPLUGIN_INIT, 0);
|
||||
}
|
||||
|
||||
byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
@@ -152,6 +153,17 @@ byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
CPlugin_ptr[x](Function, event, dummyString);
|
||||
return true;
|
||||
break;
|
||||
|
||||
// calls to active plugins
|
||||
case CPLUGIN_INIT:
|
||||
case CPLUGIN_UDP_IN:
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
if (Settings.Protocol[x] != 0 && Settings.ControllerEnabled[x]) {
|
||||
event->ProtocolIndex = getProtocolIndex(Settings.Protocol[x]);
|
||||
CPlugin_ptr[event->ProtocolIndex](Function, event, dummyString);
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user