Compare commits

...
52 Commits
Author SHA1 Message Date
ESPEasy release bot f59f25ee40 automaticly updated release notes for v2.0-20180510 2018-05-10 04:00:27 +02:00
Gijs NoorlanderandGitHub 14030ec15b Merge pull request #1395 from letscontrolit/revert-1389-patch-1
Revert "Update _P045_MPU6050.ino"
2018-05-09 23:42:50 +02:00
Gijs NoorlanderandGitHub 1fd6179408 Revert "Update _P045_MPU6050.ino" 2018-05-09 23:40:27 +02:00
Gijs NoorlanderandGitHub 22424fb03b Merge pull request #1389 from maartenpaauw/patch-1
Update _P045_MPU6050.ino
2018-05-09 23:33:26 +02:00
Maarten PaauwandGitHub 97cd06440e Update _P045_MPU6050.ino
Fix debug code (commented out code).
2018-05-08 23:14:08 +02:00
ESPEasy release bot 8346e39ac9 automaticly updated release notes for v2.0-20180322 2018-03-22 04:00:24 +01:00
TD-er 22371649a4 [WiFi] Take much more time for initial WiFi connect during setup
Accesspoint is still active, so it may take a lot more time to make the initial connection
2018-03-22 01:05:56 +01:00
Gijs NoorlanderandGitHub 8cbd9a0822 Merge pull request #1148 from TD-er/merge/mega_to_v2.0_0321
Merge/mega to v2.0 0321
2018-03-22 00:24:59 +01:00
TD-er 93f9d11738 [Memory] parseTemplate did not check if markers were found
"Free Mem" reported this function to be using quite a lot of memory.
Maybe that was related to parsing texts without matching ']' or '#'
Just added some checks to see if they were found.
2018-03-22 00:24:17 +01:00
TD-er cf3e0a3f0a [wifi] Make more robust checks and increase timeout
See #1145
2018-03-22 00:12:04 +01:00
s0170071andTD-er ccfd14dbd3 Serial WD crash 2018-03-22 00:11:48 +01:00
Bartlomiej ZimonandTD-er 3034738ad4 - P048 fetch params only when needed 2018-03-22 00:11:30 +01:00
TD-er 178d1c46a2 - P035 move strings to flash 2018-03-22 00:11:21 +01:00
Bartlomiej ZimonandTD-er cdfd1d986e - P023 fix command interpretation 2018-03-22 00:10:55 +01:00
Bartlomiej ZimonandTD-er 4b7aa53692 - P012 fix command interpretation 2018-03-22 00:10:50 +01:00
ESPEasy release bot cc02fa4481 automaticly updated release notes for v2.0-20180321 2018-03-21 04:00:21 +01:00
Gijs NoorlanderandGitHub ab3a406706 [merge issue] Forgotten #endif in merge 2018-03-20 23:46:43 +01:00
Unknown 3edfdbf5f7 [wifi] Setup with factory settings could not complete 2018-03-20 23:27:39 +01:00
ESPEasy release bot 1220c565c8 automaticly updated release notes for v2.0-20180320 2018-03-20 04:00:23 +01:00
Unknown f0987dab41 [issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset
Did not allow for enough time to do background tasks while waiting for wifi connect with DeepSleep enabled.
2018-03-20 00:29:24 +01:00
Unknown af3e353181 Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"
This reverts commit 8ccbdcadf0.
2018-03-19 22:51:23 +01:00
es-kaandUnknown c711d6ea51 Fix wiring description for SN75176 transceiver 2018-03-19 22:50:31 +01:00
ESPEasy release bot 1f084c51cc automaticly updated release notes for v2.0-20180319 2018-03-19 04:00:24 +01:00
Gijs NoorlanderandGitHub 85e8d98da8 Merge pull request #1121 from TD-er/merge/fixes_20180318_to_v2.0
Merge/fixes 20180318 to v2.0
2018-03-19 01:01:42 +01:00
Unknown 6d52a7e03a [merge] MIssing #endif due to merging. 2018-03-19 00:51:05 +01:00
Gijs Noorlander fa513b52f9 Merge pull request #1118 from TD-er/bugfix/mqtt_publish_after_deep_sleep
[issue #1097] MQTT publish after deep sleep
2018-03-19 00:46:03 +01:00
Unknown f98401524f Merge pull request #1116 from TD-er/feature/allow_own_defaults
[issue #1007] Allow user specific data in separate file
2018-03-19 00:45:52 +01:00
Unknown 4090b4f23c Merge pull request #1113 from TD-er/feature/reduce_impact_wifi_disconnect
[Relaxed WiFi] Perform WiFi initialization in steps
2018-03-19 00:42:58 +01:00
Gijs Noorlander b89c00008d Merge pull request #1114 from TD-er/feature/wifi_details_json
[JSON] Add uint name (#1099) and WiFi information (PR #1113)
2018-03-19 00:39:43 +01:00
Gijs Noorlander d57a617138 Merge pull request #1112 from uzi18/fix-p073
Fix p073 - #1111
2018-03-19 00:39:32 +01:00
Gijs Noorlander cefe6b4b7c Changed so that running all tasks immediately with deep sleep enabled… (#1110)
Changed so that running all tasks immediately with deep sleep enabled only happens on first iteration after wake up
2018-03-19 00:38:30 +01:00
Gijs Noorlander 2432740b41 - add encoder write command #1086 (#1103)
- add encoder write command #1086
2018-03-19 00:35:09 +01:00
Gijs Noorlander 44a934651c Add download button for current rule set (#1102)
Add download button for current rule set
2018-03-19 00:34:52 +01:00
ESPEasy release bot 6787bc8c0e automaticly updated release notes for v2.0-20180316 2018-03-16 04:00:23 +01:00
Gijs NoorlanderandGitHub cf644b45b1 Merge pull request #1095 from TD-er/merge/PR_1092_1093_1094
Merge/pr 1092 1093 1094
2018-03-16 00:43:16 +01:00
Unknown e6fe1c63a9 [issue #951] Changed System#Initialized => System#Wake
Changed System#Initialized  => System#Wake
New event name makes more sense and Initialized may be used later to indicate all needed connections, etc. are ready.
2018-03-16 00:38:00 +01:00
Unknown df978036f0 [issue #993] variable in MQTT subscribe topic
As [noted](https://github.com/letscontrolit/ESPEasy/issues/993#issuecomment-373140135) by @kluszcyn
2018-03-16 00:37:54 +01:00
Unknown 7cb375833d [issue #1057] AM PM display issue
X:XX PM (for hours 1...9)
X:XX AM (for hours 1...9)
XX:XX PM (for hours 10...12)
XX:XX AM (for hours 10...12)

Added for H:MM (without seconds) notations:
- `%systm_hm%`
-`%systm_hm_am%`
2018-03-16 00:37:45 +01:00
Gijs NoorlanderandGitHub 3218ea9839 Merge pull request #1091 from TD-er/merge/fixes_1073_1079_1081 into v2.0
Merge/fixes 1073 1079 1081 into v2.0
2018-03-15 23:05:06 +01:00
Gijs Noorlander eca8901fca Fixed multi instance problem on SHT3x #433 (#1081)
Fixed multi instance problem on SHT3x #433
2018-03-15 23:02:04 +01:00
Gijs Noorlander 6635eafe91 [issue #1066] Fix Webserver handle_control (#1079)
[issue #1066] Fix Webserver handle_control
2018-03-15 23:01:52 +01:00
Gijs Noorlander fe4d1f952f MCP3221 allow values for calibration (#1073)
MCP3221 allow values for calibration
2018-03-15 23:01:39 +01:00
Gijs NoorlanderandGitHub 4475a225cc Merge pull request #1090 from TD-er/merge/split_globals_v2.0
Merge/split globals v2.0
2018-03-15 22:46:46 +01:00
Unknown 2aece1c143 [v2.0 split globals] Base split on v2.0 version of ESPEasy.ino 2018-03-15 22:23:59 +01:00
Bartlomiej ZimonandUnknown 70df225e7e Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega
# Conflicts:
#	src/ESPEasy.ino
2018-03-15 22:05:36 +01:00
Unknown 19af52a3ef - move all structs from ESPEasy.ino into header file
- add some fix for headers
- add const to rtttl notes array
2018-03-15 22:05:22 +01:00
Gijs NoorlanderandGitHub 3d396575ff Merge pull request #1088 from TD-er/merge/rules_fix__and_globalsync_toV2.0
Merge/rules fix  and globalsync to v2.0
2018-03-15 21:52:41 +01:00
mvdbroandUnknown 826deaac89 Rules fix 2018-03-14 21:28:24 +01:00
mvdbroandUnknown cce621cff8 #893, part 2 receiving 2018-03-14 21:28:15 +01:00
mvdbroandUnknown 57eb38dbd0 Custom controller GUI option 2018-03-14 21:28:08 +01:00
mvdbroandUnknown fd2451bb07 #893 part1, send messages 2018-03-14 21:27:50 +01:00
ESPEasy release bot cc0b3dac26 automaticly updated release notes for v2.0-20180313 2018-03-13 04:00:23 +01:00
24 changed files with 1977 additions and 1479 deletions
+120
View File
@@ -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
View File
@@ -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);
}
}
+985
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"));
+5 -6
View File
@@ -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);
+1 -1
View File
@@ -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)
+20
View File
@@ -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;
}
+2 -2
View File
@@ -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(" &#8793; ");
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(" &#8793; ");
addTextBox(string, F("plugin_060_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
+8 -8
View File
@@ -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
View File
@@ -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;
}
+12
View File
@@ -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;