diff --git a/.travis.yml b/.travis.yml index e9d9d4ee7..c33d680d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,12 +72,11 @@ script: - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP32_4M316k - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP8266_4M1M_VCC #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP8266_4M1M_VCC_MDNS_SD - #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_16M - - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_4M1M + #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_16M_LittleFS + #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_4M1M before_deploy: - ./before_deploy - - export RELEASE_FILE=$(ls ESPEasy*.zip) deploy: provider: releases @@ -85,7 +84,7 @@ deploy: api_key: secure: bZeuKI7evXeZYmGayfcvIC1fThBGcksAyOrCbZ8kAGeTbHGJqFLBBy8to5UpNBSZVfeDWo25Iqy8Pfbyb7p2c1hg6fG9jS0UzQkLnoUNMxpUM1dJACkZxvFdP4Br3Y3vUPWtrWUbo8rN/b3E6tjSNLE7vQiwsarj+eWTO2V6BGcsN0eHc04/UCM2+DcHvJ4y7Ec36yIUaClNAWMal1osBYaViruylOdBKT/WDs1ZMoJMceXCfxMQ/8J2moYvymKfSkXSmoMGmzlTuq8v5N4AweutjpC4Zba2BbxIJv+PwWjhfIgTviHFggSU90UPTKVWYv13vms92VVKz1CDVrUQNn+YQes9+ROPUnrMc9bJ+q7E1lWJRZeDMqGECB+8BjUtUk6H81K+XhOnW1mtZiMnvMCwkmE0OT1eBObGMcpR962/DUBoQDmulMs2IieB0dLobmUBhpc1syrKEPKxjY7yhhQMr6In82jODVLR3qDkNQ8xtIfevzCo/ocUjiOrXW4b/pDMy28Yh109DMb/KSWEsjjkkpXhsT1YVy2MwOa7FRhHFW+SNKX4Us8T75H+pO4mQ4afnPEtjYKodj7XD92zqNxKfMx3elEx5RK6HKekHjpXdYtuXzGONB9StA+2T43/2llt3n5fzv4BRfCumBEJ77/ufB0U/uhsCe6lVwJf34U= file_glob: true - file: "${RELEASE_FILE}" + file: ESPEasy*.zip skip_cleanup: true on: diff --git a/before_deploy b/before_deploy index ea9bda889..26caaf7b6 100755 --- a/before_deploy +++ b/before_deploy @@ -47,8 +47,6 @@ if [ -d "docs/build" ]; then echo "### Created ESPEasy_docs_$VERSION.zip" fi -cp -r build_output/bin/* ${TMP_DIST}/bin - #create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki) #rm -rf dist/Source 2>/dev/null @@ -63,13 +61,28 @@ cp *.txt ${TMP_DIST}/source/ cp *.csv ${TMP_DIST}/source/ cp README* ${TMP_DIST}/source/ +cp -r build_output/bin/* ${TMP_DIST}/bin +rm -f ${TMP_DIST}/bin/*ESP32* cd ${TMP_DIST} -echo -zip -qq ${CURPATH}/ESPEasy_$VERSION.zip -r . -echo "### Created ESPEasy_$VERSION.zip" +if [ "$(ls -A ${TMP_DIST}/bin/)" ]; then + echo + zip -qq ${CURPATH}/ESPEasy_ESP82xx_$VERSION.zip -r . + echo "### Created ESPEasy_ESP82xx_$VERSION.zip" +fi +cd ${CURPATH} +rm -f ${TMP_DIST}/bin/* +cp -r build_output/bin/*ESP32* ${TMP_DIST}/bin + +cd ${TMP_DIST} + +if [ "$(ls -A ${TMP_DIST}/bin/)" ]; then + echo + zip -qq ${CURPATH}/ESPEasy_ESP32_$VERSION.zip -r . + echo "### Created ESPEasy_ESP32_$VERSION.zip" +fi rm -Rf ${TMP_DIST}/* 2>/dev/null rmdir ${TMP_DIST} diff --git a/dist/README.txt b/dist/README.txt index 9b84b2196..02af8582d 100644 --- a/dist/README.txt +++ b/dist/README.txt @@ -95,6 +95,11 @@ do that. More information about the tool is found here: https://github.com/Grovkillen/ESP_Easy_Flasher You can also have custom serial commands entered in a txt file. One command per line. + +For flashing ESP32 you need Espressif's own Flash Download Tools. +The latest version can be downloaded from: https://www.espressif.com/en/support/download/other-tools + + Further reading: For more information, see: https://github.com/letscontrolit/ESPEasy Or our forum: https://www.letscontrolit.com/forum/ diff --git a/dist/Release_notes.txt b/dist/Release_notes.txt index 9e86b3ae5..8b934ba2e 100644 --- a/dist/Release_notes.txt +++ b/dist/Release_notes.txt @@ -1,3 +1,207 @@ +------------------------------------------------- +Changes in release mega-20200703 (since mega-20200608) +------------------------------------------------- + +Release date: vr 3 jul 2020 13:15:58 CEST + +Florin (1): + Disable Arduino OTA by default for ESP32 + +Gijs Noorlander (31): + [ESP32] Only define FEATURE_ARDUINO_OTA in build config, not in .h files + [Build] Disable test_beta_ESP8266_4M1M for now as it is too big + [PIO] Use espressif8266@2.5.2 with fixed esp8266_stack_decoder + [Controller] Memory optimization for sending SENSOR_TYPE_STRING + [Controller] Check if controller host/IP is set before MQTT connect + [MQTT] Add function to check MQTT queue full state + [Cleanup] Free ControllerSettings as soon as possible to free memory + [Cleanup] Try to use move constructor when adding to controller queue + [Controller] Cache needed controller info to reduce memory usage + [MQTT] More efficient MQTT copy incoming messages + [Controller] Check if MakeControllerSettings failed due to low RAM + [MQTT import] Check if MakeControllerSettings failed due to out of RAM + Fix merge issue WiFiConnected changed to NetworkConnected + [P001 Switch] Reduce stack usage on PLUGIN_WEBFORM_LOAD + [Blynk] Reduce stack usage on Blynk_get + [Web Frontend] Reduce stack usage on DST configuration + [Python] Update package versions in requirements.txt + addFormSelectorI2C Fix high stack usage (#3130) + Minimize stack allocation in plugins + [Build] Add LittleFS to lib_ignore + [build] Exclude function from build for minimal OTA + [C011] Generic HTTP Advanced Reduce stack usage (#3123) + [Controller] Check success of controller settings allocation processing queue + [HTTP controller] Memory optimization, prevent copy queue element + [Build] Allow building using SD support for special debug builds + [Frontend] Use stringProvider on some more strings + [Domoticz HTTP] Make sending slightly more efficient + [Web interface] Fix bug in I2C address selector + [Rules] Fix rules handling of set 2...4 when using admin login (#3113) + [Syslog] Fix high stack usage for Syslog (#3128) + [Documentation] Add documentation on the log settings. + +Grzegorz Dziubak (1): + Update _P047_i2c-soil-moisture-sensor.ino + +Michał Obrembski (10): + Initial Ethernet support + Added displaying Ethernet parameter in sysinfo and root page + Added configuration of Eth Phy via Hardware settings web page + Added Olimex ESP32-PoE board to DeviceModel and default settings + Increased BUILD number to 20107 + Fix build on devices without Ethernet. + Remove ifdefs for Ethernet in settings + Renamed functions in ESPEasyEth, added eth* prefix + Moved WifiGetHostname into more generic createRFCCompliantHostname + Added basic implementation of Ethernet Static IP + +Pavel Moravec (1): + Fixed IP address range checking + +Peter Kretz (24): + atlas Sensor for pH an Redox (ORP) added + - Atlas EZO new webserver added - Serial --> logging - No [TESTING] + Extended the great work from Michał Obrembski mobrembski, so that: - mqtt works - WifiConnected works as EthernetConnected + - Moved ETHEvent from ESPEasy.ino to ESPEasyEthEvent.ino - Corrected Hostname Setting - ESPEasy P2P works now with some minor changes for IP-Address Handling in Network.ino + Change requested by TD-er review: clarification of build file https://github.com/letscontrolit/ESPEasy/pull/2962/files/8ba2bb88eadb98c4691cbb1f40c4d5466cb7b5b8 + ESP32 with Ethernet or Wifi, not both at the same time configurable via Hardware Page. - ESP P2P is working - Only ETH.beginPacket() with Standard Parameter is working at the moment, configuration will follow. - Network.in not cpp/h files but this will be changed in future - Some TODO: PKR: comments will be removed in the future, too + Removed some comments Build now working with HAS_ETHERNET not defined + - Ethernet Commands - remove useless comments - ETH.config moved after ETH.begin - Added note: Be aware with ESPEasyP2P Network, since IP Address will change. There could be conflicts. - Ethernet JSON - Ethernet Variables + - ETHEvents moved to WifiEvents, because they are the same type + ESPEasyEth.ino --> ESPEasyEth.cpp/h Network.ino --> Network.cpp/h + ESPEasyWiFi_credentials.ino --> cpp/h ESPEasyWiFi_ProcessEvent.ino --> cpp/h ESPEasyWiFi.ino --> cpp/h + Network.h/cpp --> ESPEasyNetwork.h/cpp + removed upload flags + - New events: ETHERNET#Connected and ETHERNET#Disconnected + Fixed https://travis-ci.org/github/letscontrolit/ESPEasy/builds/680698472 ci build error + Fixed ci compile bug https://travis-ci.org/github/letscontrolit/ESPEasy/builds/680724129 + Fixed bug reported by mobremski + - UDP / ESPEasyP2P now works for ETHERNET - Hostname Handling refactored for better overview: - String NetworkGetHostNameFromSettings() returns Settings.getHostname() - String NetworkCreateRFCCompliantHostname() creates a RFCcompliant Hostname from Settings.cpp - String NetworkGetHostname() returns the Hostname prevoiusly set in ETH or Wifi dependong on Mode - MacAddress Handling refactored - String NetworkMacAddress() returns the Mac addres of ETH or Wifi depending on Mode - String WifiSoftAPmacAddress() returns WiFi.softAPmacAddress(mac) as String + This String function is not needed, because there is a ETH.macAddress() which returns a String. I changed it to the byte version of the function and now uint8_t * NetworkMacAddressAsBytes(uint8_t* mac) returns either this in Ethernet mode or WiFi.macAddress(mac) in Wifi mode. + Check changed as requested by TD-er + addFormNote(F("Be aware with ESPEasyP2P Network, since IP Address will change. There could be conflicts.")); not used anymore because P2P UDP works good + removede personal upload flags + _P124_Atlas_EZO_pH.ino and _P222_Atlas_EZO_ORP.ino deleted since ther are not in ESPEasy but in Playground. There is another Issu, to put them in ESPEasy mega + - Error in Network Name fpr WiFi fixed - logging improvements + +bccrew (1): + Change FormSubHeader to clarify difference between IP settings of LAN or WiFi + +tonhuisman (5): + [P064] Gesture - APDS-9960 plugin: Added switching plugin mode and settings to fine-tune without recompiling source [APDS-9960 library] Added extensions and applied fixes from original Github project (including not merged yet improvements) [P064] Added/updated documentation for Gesture - APDS-9960 plugin [Documentation] Updated footer copyright notice to show 2018..2020 + [P064] Made code-readability and other improvements as TD-er suggested, fixed a swapped argument bug + [Tasks] Call PLUGIN_INIT/PLUGIN_EXIT using TaskEnable/TaskDisable from rules + [Transformation] Add P/p (Password display) + [Transformation] Optimizations for Password transformation + + +------------------------------------------------- +Changes in release mega-20200608 (since mega-20200515) +------------------------------------------------- + +Release date: ma 8 jun 2020 22:51:44 CEST + +Bartlomiej Zimon (11): + rfid events update for P008/P017/P040, plus send event after log line. + PN532: remove hardcoded scl/sda pins reading and use hardware configuration instead + PN532: update comment + Webserver - add port number setting into Advanced options, resolves #3031 and #573 + P2P: send and receive webserver port number, add port to link on rootpage #2252 + NodeStruct: init webgui_portnumber value + p2p infopacket - use low/highByte + Webserver - increase BUILD number and set default value for port number + Webserver port setting - add reboot note + MDNS - send service with actual webserver port + P2P: respect also build number in condition + +Florin (7): + Adding buzzer capabilities back to ESP32. + Allow to set the Latitude and longitude when resetting the firmware from custom.h or using the build_flags + clean up code and variables when NOTIFIER_SET_NONE is defined. + ESP32: Allow to select one of the two available SPI ports + clean up code and variables when NOTIFIER_SET_NONE is defined. + Fix for allowing negative timeOffset from UTC in constructor + rename the tone to toneESP32 to be more specific + +Gijs Noorlander (27): + [MQTT] Process publish LWT connect message asynchronous + [MQTT] Stop trying to send LWT connected when client disconnects + [LittleFS] Make switching between SPIFFS and LittleFS easy to do + [ESPEasySerial] Update to v2.0.3 adding I2C UART to ESP32 + fix bug ESP32 + [Build] Fix merge error + [PIO] Move to esp8266/Arduino core 2.7.1 + [PIO] Hide deprecated warning for SPIFFS + [Vagrant] Fix vagrant build installing all required Python packages + [Notifications] Make sure all custom defines are set at compile time + [Travis] Fix deploy multiple ZIP files + split ESP82xx and ESP32 files + [Build] Fix Python 3.8 build when no .git dir or pygit2 not installed + [GPS] Add GPS#travelled=... event (#3099) + [Build] Add ina219 and mpu6050 to custom build (#3100) + [Build] Disable diagnostics code for test_ESP8266_4M1M_VCC to fit size + [Build] Disabling timing stats results in build errors for ESP32 + [Commands] Split commands.ino to .h/.cpp to overcome build/link issues + [Build] Limit build size (no diagnostics) for test_beta_ESP8266_4M1M + [Notifications] Show notification tab when notifiers set via Custom.h + [Notifiers] switch from NOTIFIER_SET_NONE to USES_NOTIFIER in code + [ESP32] Fix Disabling ARDUINO_OTA fails the build (#3083) + [ESP32 build] Fix capitalization error in #include + [ESP32] Update to platform-espressif32@1.12.2 + [PIO] Add exception_decoder as serial monitor filter + [WiFi] Reduce excessive logs WIFI : Disconnected: WiFi.status() + [GPS] Add sanity check for reporting distance travelled event + Transform defines in EventValueSource into enum + [Build] Disable diagnostics in test/dev build to reduce build size + +Michał Obrembski (2): + Added /raw endpoint which gives an easy access to raw value of sensor + Changed format of RAW to CSV, added ability to filter values + +Michał Obrembski (3): + Fixed invalid check of valnr validity in CSV output mode + Renamed RAW to CSV, added printing of header + Removed usage of String.clear() + +Saverio Cisternino (1): + Fix parse_uint ref https://github.com/staticlibs/ccronexpr/pull/30 + +TD-er (1): + [Bug] ControllerIndex not set when calling CPLUGIN calls + +denisfrench (1): + [MQTT] Connect message honors LWT settings (#3006) + +jimmys01 (1): + [IR] Update Library + +sakinit (18): + Show for ESP32 also the first rule on the webserver rules page + Fix ESP32 undefined pin initialisation + Don't repeat the last rule on the next webserver page + Revert P1WifiGateway to 30cbb4c to bugfix this more generic code + Cherry-pick relevant P1WifiGateway updates since 30cbb4c + Fix the datagram check to be able to send valid messages again + Fix the serial reading algorithm + Fix P1WifiGateway webserver start + Remove temporary comments + Use ESPeasySerial + Restart P1WifiGateway if webserver start failed + Optimize serial reading algorithm and move client from plugin into task + Fix ESP32 reboot cause at boot/setup + Optimize serial in duration + Update due to review comments + Add sanity checks based on review comments + Discard data received from WiFi client due to review comment + Update based on review comments + +tonhuisman (6): + [Rules page] Add RTD help button and fix page layout issue ('Old Engine') + [Transformation] Add R/r transformations (LEFT/RIGHT and L/R) + [Transformations] Adjusted R/r to L/l and added c + [Justifications] Add 'C' (Capitalize, OPEN -> Open) option + [Justifications] Added u/l for upper/lowercasing the value, removed dash-check from C justificaion + [Docs] Describe 'elseif' with some examples + + ------------------------------------------------- Changes in release mega-20200515 (since mega-20200426) ------------------------------------------------- diff --git a/docs/requirements.txt b/docs/requirements.txt index d25555bac..d04a885ce 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ recommonmark==0.6.0 -Sphinx==3.0.3 +Sphinx==3.1.1 sphinx-autobuild==0.7.1 sphinx-bootstrap-theme==0.7.1 sphinxcontrib-applehelp==1.0.2 @@ -8,4 +8,4 @@ sphinxcontrib-htmlhelp==1.0.3 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.4 -sphinxcontrib-websupport==1.2.2 +sphinxcontrib-websupport==1.2.2 \ No newline at end of file diff --git a/docs/source/Controller/C013.rst b/docs/source/Controller/C013.rst index 5d1461f24..ed3a7bb23 100644 --- a/docs/source/Controller/C013.rst +++ b/docs/source/Controller/C013.rst @@ -175,7 +175,7 @@ The entire message processed as a command like this: .. code-block:: C++ packetBuffer[len] = 0; - ExecuteCommand_all(VALUE_SOURCE_SYSTEM, &packetBuffer[0]); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0]); As can be seen, no checks for size, and it is just expected to be a valid ESPeasy command. Also no check to see if the command is supported by the receiving end and no feedback to the sender. diff --git a/docs/source/Plugin/P064.rst b/docs/source/Plugin/P064.rst index 0e6c6b9d9..9100cbe81 100644 --- a/docs/source/Plugin/P064.rst +++ b/docs/source/Plugin/P064.rst @@ -1,4 +1,4 @@ -.. include:: ../Plugin/_plugin_substitutions_p06x.repl +.. include:: ../Plugin/_plugin_substitutions_p06x.repl .. _P064_page: |P064_typename| @@ -21,6 +21,44 @@ Maintainer: |P064_maintainer| Used libraries: |P064_usedlibraries| +Description +----------- + +The APDS9960 sensor provides Gesture, Proximity and Ambient Light data or R/G/B color values from the light sensor, depending on the Plugin Mode. After changing the Plugin Mode, the Values arguments may need to be adjusted according to their function (Gesture, Proximity, Light or R, G, B). If the initial Values names are used, they will be replaced when switching the Plugin Mode, and the settings are actually saved. + +There is only 1 I2C address available for this sensor, so that default value is shown. + +The Gain, LED Drive and LED Boost parameters may need adjustment from the defaults as some of the low-cost clone sensors aren't as carefully calibrated as the original SparkFun or AdaFruit sensors. The suggested defaults are taken from the original SparkFun driver software settings. When first configuring this plugin it is advised to start with these default settings, and adjust when the sensor isn't responding as required. + +For the R/G/B Colors mode, only Light Sensor Gain and Light Sensor LED Drive parameters are available. They correspond with the Ambient Light Sensor Gain and Proximity/ALS LED Drive parameters (and use the same settings storage), but with different labels. + +NB: Defaults are *not* automatically set after adding the plugin! + +Gesture parameters +------------------ + +Gesture Gain: Selection of the gain factor, select from 1x, 2x, 4x (default) or 8x. + +Gesture LED Drive: Selection of the current to drive the Gesture IR LED, select from 100 mA (default), 50 mA, 25 mA or 12.5 mA. + +Gesture LED Boost: Selection of the LED Boost factor, select from 100%, 150%, 200% or 300% (default). + +Proximity & Ambient Light Sensor parameters +------------------------------------------- + +Proximity Gain: Selection of the gain factor, select from 1x, 2x, 4x (default) or 8x. + +Ambient Light Sensor Gain: Selection of the gain factor, select from 1x, 2x, 4x (default) or 8x. + +Proximity/ALS LED Drive: Selection of the current to drive the Proximity/Ambient Light Sensor IR LED, select from 100 mA (default), 50 mA, 25 mA or 12.5 mA. + +R/G/B Colors parameters +----------------------- + +Light Sensor Gain: Selection of the gain factor, select from 1x, 2x, 4x (default) or 8x. + +Light Sensor LED Drive: Selection of the current to drive the Light Sensor IR LED, select from 100 mA (default), 50 mA, 25 mA or 12.5 mA. + Supported hardware ------------------ diff --git a/docs/source/Plugin/P082_events.repl b/docs/source/Plugin/P082_events.repl index eb915ee79..cf3a256be 100644 --- a/docs/source/Plugin/P082_events.repl +++ b/docs/source/Plugin/P082_events.repl @@ -26,3 +26,21 @@ endon " + " + ``GPS#travelled`` + When configured to update every N meters travelled, this event will be triggered if the GPS moved more than N meters away from the last position this trigger was given. + This means the total travel distance can be more if the GPS does not move in a straight line. + "," + + .. code-block:: html + + on GPS#travelled do + LogEntry,'Travelled %eventvalue% meter' + endon + + " + + + + + \ No newline at end of file diff --git a/docs/source/Plugin/_plugin_substitutions_p06x.repl b/docs/source/Plugin/_plugin_substitutions_p06x.repl index 1253c0137..05dfba88c 100644 --- a/docs/source/Plugin/_plugin_substitutions_p06x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p06x.repl @@ -52,7 +52,7 @@ .. |P064_name| replace:: :cyan:`APDS9960` .. |P064_type| replace:: :cyan:`Gesture` -.. |P064_typename| replace:: :cyan:`Gestrure - APDS9960` +.. |P064_typename| replace:: :cyan:`Gesture - APDS9960` .. |P064_porttype| replace:: `.` .. |P064_status| replace:: :red:`DEVELOPMENT` .. |P064_github| replace:: P064_APDS9960.ino @@ -61,7 +61,7 @@ .. |P064_shortinfo| replace:: `.` .. |P064_maintainer| replace:: `.` .. |P064_compileinfo| replace:: `.` -.. |P064_usedlibraries| replace:: `.` +.. |P064_usedlibraries| replace:: https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor (extended and improved) .. |P065_name| replace:: :cyan:`DFPlayer-Mini MP3` .. |P065_type| replace:: :cyan:`Notify` diff --git a/docs/source/Rules/Rules.rst b/docs/source/Rules/Rules.rst index af7bae12b..47eb9663a 100644 --- a/docs/source/Rules/Rules.rst +++ b/docs/source/Rules/Rules.rst @@ -388,6 +388,7 @@ Transformation * A "binary" transformation can be "inverted" by adding a leading ``!``. * A "binary" value is considered 0 when its string value is "0" or empty, otherwise it is an 1. (float values are rounded) * A "binary" value can also be used to detect presence of a string, as it is 0 on an empty string or 1 otherwise. +* If the transformation contains ``R``, under certain circumstances, the value will be right-aligned. Binary transformations: @@ -417,9 +418,16 @@ Floating point transformations: * ``F``: Floor (round down) * ``E``: cEiling (round up) +Other transformations: + +* ``p``: Password display, replacing all value characters by asterisks ``*``. If the value is "0", nothing will be displayed. +* ``pc``: Password display with custom character ``c``. For example p- will display value "123" as "---". If the value is "0", nothing will be displayed. + Justification ^^^^^^^^^^^^^ +To apply a justification, a transformation must also be used. If no transformation is needed, use the ``V`` (value) transformation. + * ``Pn``: Prefix Fill with n spaces. * ``Sn``: Suffix Fill with n spaces. * ``Ln``: Left part of the string, n characters. diff --git a/docs/source/Tools/Tools.rst b/docs/source/Tools/Tools.rst index 9fdb59c7c..5f9797b84 100644 --- a/docs/source/Tools/Tools.rst +++ b/docs/source/Tools/Tools.rst @@ -4,6 +4,88 @@ Tools Log === +ESPEasy can output a lot of diagnostics via logs. + +There are several output directions where you can send the logs and per direction the log level can be set. + +Log Directions +-------------- + +Logs can be sent to: + +* Syslog - A log collecting service running on another computer +* Serial port +* Web Log - Visible via the web interface +* SD card (only when included in the build) + +Syslog +^^^^^^ + +A Syslog service (often called ``rsyslog``) is often standard included in many Linux distributions. + +Some How-to: + +* `How to setup rsyslog on Ubuntu 18.04 `_ + +ESPEasy sends the syslog via UDP to the configured IP-address. + +It is also possible to set the Syslog Facility, which allows to set a level to help sort the log messages on the syslog server. + +Serial +^^^^^^ + +When configuring to send the logs to serial, all logs will be sent to `Serial0`. +This means you should not use that port for sensors. + +The logs will only be sent to the serial port, if under "Serial Settings" the serial port is set to enabled. + +N.B. Serial-0 and Serial-0 Swapped are the same port, only configured to use different pins. + + +Web Log +^^^^^^^ + +The Web log is accessible via the web interface via Tools => Log. + +To save resources, the buffer for logs sent to the web log is only used as long as the web log page is active. +This means that it may initially take some time to see the first log entries and also that it is not possible +to see log entries from before the web log page was opened. + + +SD Card +^^^^^^^ + +It is possible to send logs to an SD card. +However this is not included in the standard builds by default. +The needed libraries for this add a few tens of kByte to the bin size of the firmware, which is why it has been made optional. + +Next to the logs, it is also possible to send the task values to the SD card. +Please be aware frequent writing to an SD card may wear out an SD card and thus shortens its life span. + + + +Log Levels +---------- + +There are several log levels. +A more verbose level also includes all previous levels. + +All log levels sorted by increased verbosity: + +* None - No logs are generated for the log output direction. +* Error - Typical error messages like failed connection attempts or read/write errors +* Info - Quite a lot of operational information like new values, time set, etc. +* Debug - Typically used to determine a cause for issues. +* Debug More - Only used when a bit more detailed information is needed to find the cause of an issue. +* Debug Dev - Only used while developing a piece of code. The amount of logs generated at this level is quite overwhelming for a typical setup. + +These log levels can be set per output direction. + +Please note the most verbose active log level is used to determine whether a log entry should be generated. +For the best performance the log level on all output directions should be set as low as possible, since these log entries do take resources like RAM and CPU cycles. + + + Info ==== diff --git a/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.cpp b/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.cpp index f11ec50ec..16526af66 100644 --- a/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.cpp +++ b/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.cpp @@ -9,6 +9,12 @@ * This library interfaces the Avago APDS-9960 to Arduino over I2C. The library * relies on the Arduino Wire (I2C) library. to use the library, instantiate an * APDS9960 object, call init(), and call the appropriate functions. + * + * Original library can be found here: https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor + * + * 2020-04-27 tonhuisman + * - Added fixes suggested in original library (PR25) + * - Applied suggested improvement, but not yet fixed issue #23 * * APDS-9960 current draw tests (default parameters): * Off: 1mA @@ -37,6 +43,11 @@ SparkFun_APDS9960::SparkFun_APDS9960() gesture_state_ = 0; gesture_motion_ = DIR_NONE; + + gesture_gain_ = 0; + proximity_gain_ = 0; + proximity_ldrive_ = 0; + ambient_gain_ = 0; } /** @@ -53,6 +64,21 @@ SparkFun_APDS9960::~SparkFun_APDS9960() * @return True if initialized successfully. False otherwise. */ bool SparkFun_APDS9960::init() +{ + return init(DEFAULT_GGAIN, DEFAULT_GLDRIVE, DEFAULT_PGAIN, DEFAULT_AGAIN, DEFAULT_LDRIVE); +} + +/** + * @brief Configures I2C communications and initializes registers to defaults + * + * @param[in] ggain Gesture gain constant (0..3) + * @param[in] gldrive Gesture Led Drive constant (0..3) + * @param[in] pgain Proximity gain constant (0..3) + * @param[in] again Ambient Light Sensor gain constant (0..3) + * @param[in] ldrive Proximity and Ambient Light Sensor Led Drive constant (0..3) + * @return True if initialized successfully. False otherwise. + */ +bool SparkFun_APDS9960::init(uint8_t ggain, uint8_t gldrive, uint8_t pgain, uint8_t again, uint8_t led_drive) { uint8_t id; @@ -63,7 +89,7 @@ bool SparkFun_APDS9960::init() if( !wireReadDataByte(APDS9960_ID, id) ) { return false; } - if( !(id == APDS9960_ID_1 || id == APDS9960_ID_2) ) { + if( !(id == APDS9960_ID_1 || id == APDS9960_ID_2 || id == APDS9960_ID_3) ) { // Add support for GY-9960LLC as requested in original library github return false; } @@ -91,15 +117,18 @@ bool SparkFun_APDS9960::init() if( !wireWriteDataByte(APDS9960_CONFIG1, DEFAULT_CONFIG1) ) { return false; } - if( !setLEDDrive(DEFAULT_LDRIVE) ) { + if( !setLEDDrive(led_drive) ) { return false; } - if( !setProximityGain(DEFAULT_PGAIN) ) { + proximity_ldrive_ = led_drive; + if( !setProximityGain(pgain) ) { return false; } - if( !setAmbientLightGain(DEFAULT_AGAIN) ) { + proximity_gain_ = pgain; + if( !setAmbientLightGain(again) ) { return false; } + ambient_gain_ = again; if( !setProxIntLowThresh(DEFAULT_PILT) ) { return false; } @@ -132,10 +161,11 @@ bool SparkFun_APDS9960::init() if( !wireWriteDataByte(APDS9960_GCONF1, DEFAULT_GCONF1) ) { return false; } - if( !setGestureGain(DEFAULT_GGAIN) ) { + if( !setGestureGain(ggain) ) { return false; } - if( !setGestureLEDDrive(DEFAULT_GLDRIVE) ) { + gesture_gain_ = ggain; + if( !setGestureLEDDrive(gldrive) ) { return false; } if( !setGestureWaitTime(DEFAULT_GWTIME) ) { @@ -266,7 +296,7 @@ bool SparkFun_APDS9960::enableLightSensor(bool interrupts) { /* Set default gain, interrupts, enable power, and enable sensor */ - if( !setAmbientLightGain(DEFAULT_AGAIN) ) { + if( !setAmbientLightGain(ambient_gain_) ) { return false; } if( interrupts ) { @@ -315,10 +345,10 @@ bool SparkFun_APDS9960::disableLightSensor() bool SparkFun_APDS9960::enableProximitySensor(bool interrupts) { /* Set default gain, LED, interrupts, enable power, and enable sensor */ - if( !setProximityGain(DEFAULT_PGAIN) ) { + if( !setProximityGain(proximity_gain_) ) { return false; } - if( !setLEDDrive(DEFAULT_LDRIVE) ) { + if( !setLEDDrive(proximity_ldrive_) ) { return false; } if( interrupts ) { @@ -363,7 +393,17 @@ bool SparkFun_APDS9960::disableProximitySensor() * @param[in] interrupts true to enable hardware external interrupt on gesture * @return True if engine enabled correctly. False on error. */ -bool SparkFun_APDS9960::enableGestureSensor(bool interrupts) +bool SparkFun_APDS9960::enableGestureSensor(bool interrupts) { + return enableGestureSensor(interrupts, LED_BOOST_300); +} +/** + * @brief Starts the gesture recognition engine on the APDS-9960 + * + * @param[in] interrupts true to enable hardware external interrupt on gesture + * @param[in] Led-boost value (0..3 = 100, 150, 200, 300%; 3 = default) + * @return True if engine enabled correctly. False on error. + */ +bool SparkFun_APDS9960::enableGestureSensor(bool interrupts, uint8_t led_boost) { /* Enable gesture mode @@ -379,7 +419,7 @@ bool SparkFun_APDS9960::enableGestureSensor(bool interrupts) if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ) { return false; } - if( !setLEDBoost(LED_BOOST_300) ) { + if( !setLEDBoost(led_boost) ) { return false; } if( interrupts ) { @@ -464,9 +504,9 @@ bool SparkFun_APDS9960::isGestureAvailable() int SparkFun_APDS9960::readGesture() { uint8_t fifo_level = 0; - uint8_t bytes_read = 0; uint8_t fifo_data[128]; uint8_t gstatus; + int bytes_read = 0; // Fixed Issue #23 reported in original library source int motion; int i; @@ -2267,7 +2307,7 @@ bool SparkFun_APDS9960::wireWriteDataBlock( uint8_t reg, Wire.beginTransmission(APDS9960_I2C_ADDR); Wire.write(reg); for(i = 0; i < len; i++) { - Wire.beginTransmission(val[i]); + Wire.write(val[i]); // Improvement suggested by Koepel in issue #24 in original library } if( Wire.endTransmission() != 0 ) { return false; diff --git a/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.h b/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.h index 81a8cfc6a..d24885721 100644 --- a/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.h +++ b/lib/SparkFun_APDS-9960_Sensor_Arduino_Library/src/SparkFun_APDS9960.h @@ -33,6 +33,7 @@ /* Acceptable device IDs */ #define APDS9960_ID_1 0xAB #define APDS9960_ID_2 0x9C +#define APDS9960_ID_3 0xA8 // Add support for GY-9960LLC as requested in original library github /* Misc parameters */ #define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads @@ -223,6 +224,7 @@ public: SparkFun_APDS9960(); ~SparkFun_APDS9960(); bool init(); + bool init(uint8_t ggain, uint8_t gldrive, uint8_t pgain, uint8_t again, uint8_t led_drive); uint8_t getMode(); bool setMode(uint8_t mode, uint8_t enable); @@ -236,6 +238,7 @@ public: bool enableProximitySensor(bool interrupts = false); bool disableProximitySensor(); bool enableGestureSensor(bool interrupts = true); + bool enableGestureSensor(bool interrupts, uint8_t led_boost); bool disableGestureSensor(); /* LED drive strength control */ @@ -344,6 +347,11 @@ private: int gesture_far_count_; int gesture_state_; int gesture_motion_; + + uint8_t gesture_gain_; + uint8_t proximity_gain_; + uint8_t proximity_ldrive_; + uint8_t ambient_gain_; }; #endif diff --git a/lib/ccronexpr/ccronexpr.c b/lib/ccronexpr/ccronexpr.c index 826d95536..1933eb144 100644 --- a/lib/ccronexpr/ccronexpr.c +++ b/lib/ccronexpr/ccronexpr.c @@ -595,7 +595,7 @@ static char* str_replace(char *orig, const char *rep, const char *with) { static unsigned int parse_uint(const char* str, int* errcode) { char* endptr; errno = 0; - long int l = strtol(str, &endptr, 0); + long int l = strtol(str, &endptr, 10); if (errno == ERANGE || *endptr != '\0' || l < 0 || l > INT_MAX) { *errcode = 1; return 0; diff --git a/platformio.ini b/platformio.ini index 37b2b5886..197e0c0b1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,7 +58,8 @@ upload_port = 192.168.1.152 [debug_flags] -build_flags = +;build_flags = -Wstack-usage=300 +build_flags = [mqtt_flags] build_flags = -DMQTT_MAX_PACKET_SIZE=1024 diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index b735b1686..ef03ad73b 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -100,16 +100,17 @@ lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, Hea [core_2_7_1] extends = esp82xx_2_6_x -platform = espressif8266@2.5.1 +platform = espressif8266@2.5.2 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.1 build_flags = ${esp82xx_2_6_x.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 + -Wno-deprecated-declarations [core_2_7_1_sdk3] extends = esp82xx_2_6_x -platform = espressif8266@2.5.1 +platform = espressif8266@2.5.2 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.1 build_flags = ${esp82xx_2_6_x.build_flags} @@ -120,12 +121,17 @@ extends = esp82xx_2_6_x platform = https://github.com/platformio/platform-espressif8266.git build_flags = ${esp82xx_2_6_x.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191122 + -Wno-deprecated-declarations platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git -[core_esp32_1_11_2] -platform = espressif32@1.11.2 + +; Updated ESP-IDF to the latest stable 4.0.1 +; See: https://github.com/platformio/platform-espressif32/releases +[core_esp32_1_12_2] +platform = espressif32@1.12.2 + [core_esp32_stage] platform = https://github.com/platformio/platform-espressif32.git#feature/stage diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 48f91c6b9..f14bccc17 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -8,7 +8,7 @@ [esp32_common] extends = common -platform = ${core_esp32_1_11_2.platform} +platform = ${core_esp32_1_12_2.platform} lib_ignore = AS_BH1750, ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, ESP32_ping, HeatpumpIR lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.3, Adafruit ILI9341, Adafruit GFX Library board_build.f_flash = 80000000L @@ -23,6 +23,7 @@ build_flags = ${mqtt_flags.build_flags} -DCONFIG_FREERTOS_ASSERT_DISABLE -DCONFIG_LWIP_ESP_GRATUITOUS_ARP -DCONFIG_LWIP_GARP_TMR_INTERVAL=30 +monitor_filters = esp32_exception_decoder @@ -38,7 +39,9 @@ extra_scripts = ${esp32_common.extra_scripts} [env:test_ESP32_4M316k] extends = esp32_common platform = ${esp32_common.platform} -build_flags = ${esp32_common.build_flags} -DPLUGIN_SET_TEST_ESP32 +build_flags = ${esp32_common.build_flags} + -DFEATURE_ARDUINO_OTA + -DPLUGIN_SET_TEST_ESP32 board = esp32dev extra_scripts = ${esp32_common.extra_scripts} @@ -46,11 +49,30 @@ extra_scripts = ${esp32_common.extra_scripts} [env:test_ESP32-wrover-kit_4M316k] extends = esp32_common platform = ${esp32_common.platform} -build_flags = ${esp32_common.build_flags} -DPLUGIN_SET_TEST_ESP32 +build_flags = ${esp32_common.build_flags} + -DFEATURE_ARDUINO_OTA + -DPLUGIN_SET_TEST_ESP32 board = esp-wrover-kit upload_protocol = ftdi debug_tool = ftdi debug_extra_cmds = break Misc.ino:3011 extra_scripts = ${esp32_common.extra_scripts} +; Custom: 4096k version -------------------------- +[env:custom_ESP32_4M316k_ETH] +extends = env:custom_ESP32_4M316k +platform = ${env:custom_ESP32_4M316k.platform} +build_flags = ${env:custom_ESP32_4M316k.build_flags} -DHAS_ETHERNET + +[env:test_ESP32_4M316k_ETH] +extends = env:test_ESP32_4M316k +platform = ${env:test_ESP32_4M316k.platform} +build_flags = ${env:test_ESP32_4M316k.build_flags} -DHAS_ETHERNET + + +[env:test_ESP32-wrover-kit_4M316k_ETH] +extends = env:test_ESP32-wrover-kit_4M316k +platform = ${env:test_ESP32-wrover-kit_4M316k.platform} +build_flags = ${env:test_ESP32-wrover-kit_4M316k.build_flags} -DHAS_ETHERNET + diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 4cb149678..5927def6b 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -12,6 +12,7 @@ platform_packages = ${core_2_7_1.platform_packages} lib_ignore = ${core_2_7_1.lib_ignore} + [core262_sdk3_platform] build_unflags = build_flags = ${core_2_7_1_sdk3.build_flags} @@ -28,14 +29,28 @@ platform_packages = ${core_stage.platform_packages} lib_ignore = ${core_stage.lib_ignore} +[no_ir] +lib_ignore = IRremoteESP8266, HeatpumpIR + +[no_sd] +lib_ignore = SD(esp8266), SDFS + +[no_littlefs] +lib_ignore = LittleFS(esp8266) + +[generic_build] +lib_ignore = ${no_ir.lib_ignore}, ${no_sd.lib_ignore}, ${no_littlefs.lib_ignore} + [esp82xx_common] extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.3, Adafruit ILI9341, Adafruit GFX Library -lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS +lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS, LittleFS(esp8266) board = esp12e +monitor_filters = esp8266_exception_decoder + @@ -97,7 +112,7 @@ lib_ignore = ${regular_platform.lib_ignore} platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} -lib_ignore = ${esp82xx_defaults.lib_ignore}, SD(esp8266), SDFS +lib_ignore = ${esp82xx_defaults.lib_ignore}, SD(esp8266), SDFS, LittleFS(esp8266) [minimal_ir] extends = ir @@ -153,6 +168,7 @@ extends = esp82xx_1M board_build.flash_mode = dout board_upload.maximum_size = 616448 build_flags = ${esp82xx_1M.build_flags} -DPLUGIN_BUILD_MINIMAL_OTA +lib_deps = [esp8266_1M_OTA] diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 38f14e53b..3bbca0315 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -49,7 +49,7 @@ lib_ignore = ${beta_platform.lib_ignore} extra_scripts = ${esp8266_scripts_custom.extra_scripts} -; Custom: 4M2M version -------------------------- +; Custom: 4M2M version -- SPIFFS -------------- [env:custom_ESP8266_4M2M] extends = esp8266_4M2M platform = ${regular_platform.platform} @@ -60,6 +60,19 @@ build_flags = ${regular_platform.build_flags} lib_ignore = ${regular_platform.lib_ignore} extra_scripts = ${esp8266_scripts_custom.extra_scripts} +; Custom: 4M2M version -- LittleFS -------------- +; LittleFS is determined by using "LittleFS" in the pio env name +[env:custom_ESP8266_4M2M_LittleFS] +extends = esp8266_4M2M +platform = ${regular_platform.platform} +platform_packages = ${regular_platform.platform_packages} +build_flags = ${regular_platform.build_flags} + ${esp8266_4M1M.build_flags} + -DPLUGIN_BUILD_CUSTOM +lib_ignore = ${regular_platform.lib_ignore} +extra_scripts = ${esp8266_scripts_custom.extra_scripts} + + ; Custom: 1M version -------------------------- [env:custom_ESP8266_1M] extends = esp8266_1M @@ -149,8 +162,9 @@ platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8266_4M1M.build_flags} -; NORMAL: 16M version -------------------------- -[env:normal_ESP8266_16M] +; NORMAL: 16M version --- LittleFS -------------- +; LittleFS is determined by using "LittleFS" in the pio env name +[env:normal_ESP8266_16M_LittleFS] extends = esp8266_16M platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} @@ -328,7 +342,8 @@ build_flags = ${testing.build_flags} -DFEATURE_ADC_VCC=true -DFEATURE_MDNS -DFEATURE_SD -lib_ignore = ESP32_ping, ESP32WebServer, ESP32HTTPUpdateServer, , IRremoteESP8266, HeatpumpIR + -DLIMIT_BUILD_SIZE +lib_ignore = ESP32_ping, ESP32WebServer, ESP32HTTPUpdateServer, IRremoteESP8266, HeatpumpIR, LittleFS(esp8266) [env:test_beta_ESP8266_4M1M] @@ -337,15 +352,18 @@ platform = ${testing_beta.platform} platform_packages = ${testing_beta.platform_packages} build_flags = ${testing_beta.build_flags} ${esp8266_4M1M.build_flags} + -DLIMIT_BUILD_SIZE - -[env:test_beta_ESP8266_16M] +; Test: 16M version -- LittleFS -------------- +; LittleFS is determined by using "LittleFS" in the pio env name +[env:test_beta_ESP8266_16M_LittleFS] extends = esp8266_16M platform = ${testing_beta.platform} platform_packages = ${testing_beta.platform_packages} build_flags = ${testing_beta.build_flags} ${esp8266_16M.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22y +lib_ignore = ESP32_ping, ESP32WebServer, ESP32HTTPUpdateServer, IRremoteESP8266, HeatpumpIR diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index 230961327..8a6e44a1e 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -20,7 +20,7 @@ build_flags = ${regular_platform.build_flags} ${debug_pio.build_flags} ${esp8266_4M1M.build_flags} -DPLUGIN_BUILD_CUSTOM -lib_ignore = ${regular_platform.lib_ignore} +lib_ignore = ${regular_platform.lib_ignore}, IRremoteESP8266, HeatpumpIR, LittleFS(esp8266) extra_scripts = ${esp8266_scripts_custom.extra_scripts} @@ -32,7 +32,7 @@ build_flags = ${beta_platform.build_flags} ${debug_pio.build_flags} ${esp8266_4M1M.build_flags} -DPLUGIN_BUILD_CUSTOM -lib_ignore = ${beta_platform.lib_ignore} +lib_ignore = ${regular_platform.lib_ignore}, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS, LittleFS(esp8266) extra_scripts = ${esp8266_scripts_custom.extra_scripts} diff --git a/requirements.txt b/requirements.txt index 4d31c39c5..b7fbab683 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ argh==0.26.2 Babel==2.8.0 bottle==0.12.18 cached-property==1.5.1 -certifi==2020.4.5.1 +certifi==2020.6.20 cffi==1.14.0 chardet==3.0.4 click==7.1.2 @@ -13,12 +13,12 @@ docutils==0.16 idna==2.9 imagesize==1.2.0 Jinja2==2.11.2 -livereload==2.6.1 +livereload==2.6.2 MarkupSafe==1.1.1 -marshmallow==3.5.2 +marshmallow==3.6.1 packaging==20.3 pathtools==0.1.2 -platformio>=4.3.3 +platformio>=4.3.4 port-for==0.3.1 pycparser==2.20 pyelftools==0.26 @@ -29,9 +29,9 @@ pyserial==3.4 pytz==2020.1 PyYAML==5.3.1 recommonmark==0.6.0 -requests==2.23.0 +requests==2.24.0 semantic-version==2.8.5 -six==1.14.0 +six==1.15.0 snowballstemmer==2.0.0 tabulate==0.8.7 tornado==6.0.4 diff --git a/src/Controller.ino b/src/Controller.ino index 8cb10b646..9f0a7e7f8 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -1,6 +1,7 @@ #include "ESPEasy_common.h" #include "ESPEasy_fdwdecl.h" #include "ESPEasy_plugindefs.h" +#include "src/ControllerQueue/MQTT_queue_element.h" #include "src/DataStructs/ControllerSettingsStruct.h" #include "src/DataStructs/ESPEasy_EventStruct.h" #include "src/Globals/CPlugins.h" @@ -28,6 +29,12 @@ void sendData(struct EventStruct *event) } LoadTaskSettings(event->TaskIndex); // could have changed during background tasks. + if (event->sensorType == SENSOR_TYPE_NONE) { + const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); + if (validDeviceIndex(DeviceIndex)) { + event->sensorType = Device[DeviceIndex].VType; + } + } for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { @@ -66,10 +73,7 @@ void sendData(struct EventStruct *event) } bool validUserVar(struct EventStruct *event) { - const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); - if (!validDeviceIndex(DeviceIndex)) return false; - - switch (Device[DeviceIndex].VType) { + switch (event->sensorType) { case SENSOR_TYPE_LONG: return true; case SENSOR_TYPE_STRING: return true; // FIXME TD-er: Must look at length of event->String2 ? default: @@ -106,32 +110,12 @@ void callback(char *c_topic, byte *b_payload, unsigned int length) { return; } - struct EventStruct TempEvent; - // TD-er: This one cannot set the TaskIndex, but that may seem to work out.... hopefully. - TempEvent.String1 = c_topic; - TempEvent.String2.reserve(length); - - for (unsigned int i = 0; i < length; ++i) { - char c = static_cast(*(b_payload + i)); - TempEvent.String2 += c; - } - - /* - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - String log; - log=F("MQTT : Topic: "); - log+=c_topic; - addLog(LOG_LEVEL_DEBUG_MORE, log); - - log=F("MQTT : Payload: "); - log+=TempEvent.String2; - addLog(LOG_LEVEL_DEBUG_MORE, log); - } - */ - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(enabledMqttController); - schedule_controller_event_timer(ProtocolIndex, CPlugin::Function::CPLUGIN_PROTOCOL_RECV, &TempEvent); + schedule_mqtt_controller_event_timer( + ProtocolIndex, + CPlugin::Function::CPLUGIN_PROTOCOL_RECV, + c_topic, b_payload, length); } /*********************************************************************************************\ @@ -153,6 +137,10 @@ bool MQTTConnect(controllerIndex_t controller_idx) { ++mqtt_reconnect_count; MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot connect, out of RAM")); + return false; + } LoadControllerSettings(controller_idx, ControllerSettings); if (!ControllerSettings.checkHostReachable(true)) { @@ -177,34 +165,13 @@ bool MQTTConnect(controllerIndex_t controller_idx) // MQTT needs a unique clientname to subscribe to broker String clientid = getMQTTclientID(ControllerSettings); - String LWTTopic = ControllerSettings.MQTTLwtTopic; - - if (LWTTopic.length() == 0) - { - LWTTopic = ControllerSettings.Subscribe; - LWTTopic += F("/LWT"); - } - LWTTopic.replace(F("/#"), F("/status")); - parseSystemVariables(LWTTopic, false); - - String LWTMessageConnect = ControllerSettings.LWTMessageConnect; - - if (LWTMessageConnect.length() == 0) { - LWTMessageConnect = F(DEFAULT_MQTT_LWT_CONNECT_MESSAGE); - } - parseSystemVariables(LWTMessageConnect, false); - - String LWTMessageDisconnect = ControllerSettings.LWTMessageDisconnect; - - if (LWTMessageDisconnect.length() == 0) { - LWTMessageDisconnect = F(DEFAULT_MQTT_LWT_DISCONNECT_MESSAGE); - } - parseSystemVariables(LWTMessageDisconnect, false); - - bool MQTTresult = false; - uint8_t willQos = 0; - bool willRetain = ControllerSettings.mqtt_willRetain() && ControllerSettings.mqtt_sendLWT(); - bool cleanSession = ControllerSettings.mqtt_cleanSession(); // As suggested here: https://github.com/knolleary/pubsubclient/issues/458#issuecomment-493875150 + String LWTTopic = getLWT_topic(ControllerSettings); + String LWTMessageDisconnect = getLWT_messageDisconnect(ControllerSettings); + bool MQTTresult = false; + uint8_t willQos = 0; + bool willRetain = ControllerSettings.mqtt_willRetain() && ControllerSettings.mqtt_sendLWT(); + bool cleanSession = ControllerSettings.mqtt_cleanSession(); // As suggested here: + // https://github.com/knolleary/pubsubclient/issues/458#issuecomment-493875150 if (hasControllerCredentialsSet(controller_idx, ControllerSettings)) { MQTTresult = @@ -229,8 +196,9 @@ bool MQTTConnect(controllerIndex_t controller_idx) delay(0); - byte controller_number = Settings.Protocol[controller_idx]; + byte controller_number = Settings.Protocol[controller_idx]; count_connection_results(MQTTresult, F("MQTT : Broker "), controller_number, ControllerSettings); + if (!MQTTresult) { MQTTclient.disconnect(); updateMQTTclient_connected(); @@ -246,21 +214,28 @@ bool MQTTConnect(controllerIndex_t controller_idx) log += subscribeTo; addLog(LOG_LEVEL_INFO, log); - if (MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), 1)) { - updateMQTTclient_connected(); - statusLED(true); - mqtt_reconnect_count = 0; + updateMQTTclient_connected(); + statusLED(true); + mqtt_reconnect_count = 0; - // call all installed controller to publish autodiscover data - if (MQTTclient_should_reconnect) { CPluginCall(CPlugin::Function::CPLUGIN_GOT_CONNECTED, 0); } - MQTTclient_should_reconnect = false; - return true; // end loop if succesfull + // call all installed controller to publish autodiscover data + if (MQTTclient_should_reconnect) { CPluginCall(CPlugin::Function::CPLUGIN_GOT_CONNECTED, 0); } + MQTTclient_should_reconnect = false; + + if (ControllerSettings.mqtt_sendLWT()) { + String LWTMessageConnect = getLWT_messageConnect(ControllerSettings); + + if (!MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), willRetain)) { + MQTTclient_must_send_LWT_connected = true; + } } - return false; + + return true; } String getMQTTclientID(const ControllerSettingsStruct& ControllerSettings) { String clientid = ControllerSettings.ClientID; + if (clientid.length() == 0) { // Try to generate some default clientid = F(CONTROLLER_DEFAULT_CLIENTID); @@ -285,120 +260,184 @@ String getMQTTclientID(const ControllerSettingsStruct& ControllerSettings) { \*********************************************************************************************/ bool MQTTCheck(controllerIndex_t controller_idx) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return false; } protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controller_idx); + if (!validProtocolIndex(ProtocolIndex)) { return false; } if (Protocol[ProtocolIndex].usesMQTT) { - if (MQTTclient_should_reconnect || !MQTTclient.connected()) - { - if (MQTTclient_should_reconnect) { - addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect")); - } - return MQTTConnect(controller_idx); + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot check, out of RAM")); + return false; + } + + LoadControllerSettings(controller_idx, ControllerSettings); + + // FIXME TD-er: Is this still needed? + /* + #ifdef USES_ESPEASY_NOW + if (!MQTTclient.connected()) { + if (ControllerSettings.enableESPEasyNowFallback()) { + return true; + } + } + #endif + */ + + if (ControllerSettings.isSet()) { + if (MQTTclient_should_reconnect || !MQTTclient.connected()) + { + if (MQTTclient_should_reconnect) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect")); + } + return MQTTConnect(controller_idx); + } + + if (MQTTclient_must_send_LWT_connected) { + if (ControllerSettings.mqtt_sendLWT()) { + String LWTTopic = getLWT_topic(ControllerSettings); + String LWTMessageConnect = getLWT_messageConnect(ControllerSettings); + bool willRetain = ControllerSettings.mqtt_willRetain(); + + if (MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), willRetain)) { + MQTTclient_must_send_LWT_connected = false; + } + } else { + MQTTclient_must_send_LWT_connected = false; + } + } } } // When no MQTT protocol is enabled, all is fine. return true; } -#endif //USES_MQTT + + +String getLWT_topic(const ControllerSettingsStruct& ControllerSettings) { + String LWTTopic; + + if (ControllerSettings.mqtt_sendLWT()) { + LWTTopic = ControllerSettings.MQTTLwtTopic; + + if (LWTTopic.length() == 0) + { + LWTTopic = ControllerSettings.Subscribe; + LWTTopic += F("/LWT"); + } + LWTTopic.replace(F("/#"), F("/status")); + parseSystemVariables(LWTTopic, false); + } + return LWTTopic; +} + +String getLWT_messageConnect(const ControllerSettingsStruct& ControllerSettings) { + String LWTMessageConnect; + + if (ControllerSettings.mqtt_sendLWT()) { + LWTMessageConnect = ControllerSettings.LWTMessageConnect; + + if (LWTMessageConnect.length() == 0) { + LWTMessageConnect = F(DEFAULT_MQTT_LWT_CONNECT_MESSAGE); + } + parseSystemVariables(LWTMessageConnect, false); + } + return LWTMessageConnect; +} + +String getLWT_messageDisconnect(const ControllerSettingsStruct& ControllerSettings) { + String LWTMessageDisconnect; + + if (ControllerSettings.mqtt_sendLWT()) { + LWTMessageDisconnect = ControllerSettings.LWTMessageDisconnect; + + if (LWTMessageDisconnect.length() == 0) { + LWTMessageDisconnect = F(DEFAULT_MQTT_LWT_DISCONNECT_MESSAGE); + } + parseSystemVariables(LWTMessageDisconnect, false); + } + return LWTMessageDisconnect; +} + +#endif // USES_MQTT /*********************************************************************************************\ * Send status info to request source \*********************************************************************************************/ -void SendStatusOnlyIfNeeded(byte eventSource, bool param1, uint32_t key, const String& param2, int16_t param3) { +void SendStatusOnlyIfNeeded(EventValueSource::Enum eventSource, bool param1, uint32_t key, const String& param2, int16_t param3) { if (SourceNeedsStatusUpdate(eventSource)) { SendStatus(eventSource, getPinStateJSON(param1, key, param2, param3)); } } -bool SourceNeedsStatusUpdate(byte eventSource) +bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource) { switch (eventSource) { - case VALUE_SOURCE_HTTP: - case VALUE_SOURCE_SERIAL: - case VALUE_SOURCE_MQTT: - case VALUE_SOURCE_WEB_FRONTEND: + case EventValueSource::Enum::VALUE_SOURCE_HTTP: + case EventValueSource::Enum::VALUE_SOURCE_SERIAL: + case EventValueSource::Enum::VALUE_SOURCE_MQTT: + case EventValueSource::Enum::VALUE_SOURCE_WEB_FRONTEND: return true; + + default: + break; } return false; } -void SendStatus(byte source, const String& status) +void SendStatus(EventValueSource::Enum source, const String& status) { switch (source) { - case VALUE_SOURCE_HTTP: - case VALUE_SOURCE_WEB_FRONTEND: + case EventValueSource::Enum::VALUE_SOURCE_HTTP: + case EventValueSource::Enum::VALUE_SOURCE_WEB_FRONTEND: if (printToWeb) { printWebString += status; } break; #ifdef USES_MQTT - case VALUE_SOURCE_MQTT: + case EventValueSource::Enum::VALUE_SOURCE_MQTT: MQTTStatus(status); break; #endif //USES_MQTT - case VALUE_SOURCE_SERIAL: + case EventValueSource::Enum::VALUE_SOURCE_SERIAL: serialPrintln(status); break; + + default: + break; } } #ifdef USES_MQTT +bool MQTT_queueFull(controllerIndex_t controller_idx) { + MQTT_queue_element dummy_element; + dummy_element.controller_idx = controller_idx; + if (MQTTDelayHandler.queueFull(dummy_element)) { + // The queue is full, try to make some room first. + processMQTTdelayQueue(); + return MQTTDelayHandler.queueFull(dummy_element); + } + return false; +} + bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained) { - { - MQTT_queue_element dummy_element(MQTT_queue_element(controller_idx, "", "", retained)); - if (MQTTDelayHandler.queueFull(dummy_element)) { - // The queue is full, try to make some room first. - addLog(LOG_LEVEL_DEBUG, F("MQTT : Extra processMQTTdelayQueue()")); - processMQTTdelayQueue(); - } + if (MQTT_queueFull(controller_idx)) { + return false; } const bool success = MQTTDelayHandler.addToQueue(MQTT_queue_element(controller_idx, topic, payload, retained)); scheduleNextMQTTdelayQueue(); return success; } -void scheduleNextMQTTdelayQueue() { - scheduleNextDelayQueue(TIMER_MQTT_DELAY_QUEUE, MQTTDelayHandler.getNextScheduleTime()); -} - -void processMQTTdelayQueue() { - START_TIMER; - MQTT_queue_element *element(MQTTDelayHandler.getNext()); - - if (element == NULL) { return; } - - if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) { - if (connectionFailures > 0) { - --connectionFailures; - } - MQTTDelayHandler.markProcessed(true); - } else { - MQTTDelayHandler.markProcessed(false); -#ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("MQTT : process MQTT queue not published, "); - log += MQTTDelayHandler.sendQueue.size(); - log += F(" items left in queue"); - addLog(LOG_LEVEL_DEBUG, log); - } -#endif // ifndef BUILD_NO_DEBUG - } - setIntervalTimerOverride(TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible. - scheduleNextMQTTdelayQueue(); - STOP_TIMER(MQTT_DELAY_QUEUE); -} /*********************************************************************************************\ * Send status info back to channel where request came from @@ -408,12 +447,24 @@ void MQTTStatus(const String& status) controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(enabledMqttController)) { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(enabledMqttController, ControllerSettings); - String pubname = ControllerSettings.Subscribe; + String pubname; + bool mqtt_retainFlag; + { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot send status, out of RAM")); + return; + } + + LoadControllerSettings(enabledMqttController, ControllerSettings); + pubname = ControllerSettings.Publish; + mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); + } + pubname.replace(F("/#"), F("/status")); parseSystemVariables(pubname, false); - MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(), ControllerSettings.mqtt_retainFlag()); + MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(), mqtt_retainFlag); } } #endif //USES_MQTT diff --git a/src/ESPEasy-Globals.cpp b/src/ESPEasy-Globals.cpp index e255ccfed..6b6949e5e 100644 --- a/src/ESPEasy-Globals.cpp +++ b/src/ESPEasy-Globals.cpp @@ -2,6 +2,7 @@ #include "ESPEasy-Globals.h" #include "ESPEasy_plugindefs.h" +#include "ESPEasyEthWifi.h" #if defined(ESP32) @@ -23,6 +24,14 @@ bool dnsServerActive = false; //NTP status bool statusNTPInitialized = false; +// Ethernet Connectiopn status +#ifdef HAS_ETHERNET +uint8_t eth_wifi_mode = ETHERNET; + // WIFI = 0 + // ETHERNET = 1 +bool eth_connected = false; +#endif + // udp protocol stuff (syslog, global sync, node info list, ntp time) WiFiUDP portUDP; @@ -65,7 +74,6 @@ bool webserverRunning(false); bool webserver_init(false); -EventQueueStruct eventQueue; diff --git a/src/ESPEasy-Globals.h b/src/ESPEasy-Globals.h index de2936e4e..3e05680ed 100644 --- a/src/ESPEasy-Globals.h +++ b/src/ESPEasy-Globals.h @@ -28,7 +28,6 @@ #include "ESPEasy_fdwdecl.h" #include "src/DataStructs/ESPEasyLimits.h" -#include "src/DataStructs/EventQueue.h" #include "src/Helpers/msecTimerHandlerStruct.h" #include "ESPEasy_plugindefs.h" #include "src/Globals/Device.h" @@ -96,7 +95,7 @@ #include "src/DataStructs/NotificationSettingsStruct.h" #include "src/DataStructs/NotificationStruct.h" -#ifndef NOTIFIER_SET_NONE +#ifdef USES_NOTIFIER extern NotificationStruct Notification[NPLUGIN_MAX]; #endif @@ -184,7 +183,11 @@ extern NotificationStruct Notification[NPLUGIN_MAX]; #define FILE_RULES "/rules1.txt" #include // #include "esp32_ping.h" - #include "SPIFFS.h" + #ifdef USE_LITTLEFS + #include "LittleFS.h" + #else + #include "SPIFFS.h" + #endif #include #include "esp_wifi.h" // Needed to call ESP-IDF functions like esp_wifi_.... #ifdef FEATURE_MDNS @@ -226,6 +229,11 @@ extern bool statusNTPInitialized; // udp protocol stuff (syslog, global sync, node info list, ntp time) extern WiFiUDP portUDP; +// Ethernet Connectiopn status +#ifdef HAS_ETHERNET +extern uint8_t eth_wifi_mode; +extern bool eth_connected; +#endif @@ -343,7 +351,6 @@ extern bool webserverRunning; extern bool webserver_init; -extern EventQueueStruct eventQueue; extern bool shouldReboot; @@ -434,6 +441,16 @@ struct GpioFactorySettingsStruct { i2c_sda = -1; // GPIO4 conflicts with relay control. i2c_scl = -1; // GPIO5 conflicts with SW input break; + case DeviceMode_Olimex_ESP32_PoE: + button[0] = 34; // DUT1 Button + relais[0] = -1; // No LED's or relays on board + status_led = -1; + i2c_sda = 4; + i2c_scl = 5; + eth_power = 12; + eth_clock_mode = 3; + eth_wifi_mode = 1; + break; // case DeviceModel_default: break; default: break; @@ -445,6 +462,13 @@ struct GpioFactorySettingsStruct { int8_t status_led = DEFAULT_PIN_STATUS_LED; int8_t i2c_sda = DEFAULT_PIN_I2C_SDA; int8_t i2c_scl = DEFAULT_PIN_I2C_SCL; + int8_t eth_phyaddr = DEFAULT_ETH_PHY_ADDR; + int8_t eth_phytype = DEFAULT_ETH_PHY_TYPE; + int8_t eth_mdc = DEFAULT_ETH_PIN_MDC; + int8_t eth_mdio = DEFAULT_ETH_PIN_MDIO; + int8_t eth_power = DEFAULT_ETH_PIN_POWER; + int8_t eth_clock_mode = DEFAULT_ETH_CLOCK_MODE; + int8_t eth_wifi_mode = DEFAULT_ETH_WIFI_MODE; }; void addPredefinedPlugins(const GpioFactorySettingsStruct& gpio_settings); diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index a0c73525a..fd26ee748 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -108,6 +108,7 @@ #include "src/Globals/Device.h" #include "src/Globals/ESPEasyWiFiEvent.h" #include "src/Globals/ExtraTaskSettings.h" +#include "src/Globals/EventQueue.h" #include "src/Globals/GlobalMapPortStatus.h" #include "src/Globals/MQTT.h" #include "src/Globals/Plugins.h" @@ -119,24 +120,21 @@ #include "src/Globals/Settings.h" #include "src/Globals/Statistics.h" +#include "src/Helpers/ESPEasy_checks.h" +#include "src/Helpers/Hardware.h" +#include "src/Helpers/Scheduler.h" +#include "src/Helpers/ESPEasy_Storage.h" +#include "src/Helpers/DeepSleep.h" +#include "src/Helpers/PeriodicalActions.h" + +#include "ESPEasyWiFi_credentials.h" +#include "ESPEasyWifi_ProcessEvent.h" +#include "ESPEasyWifi.h" + #if FEATURE_ADC_VCC ADC_MODE(ADC_VCC); #endif -// Get functions to give access to global defined variables. -// These are needed to get direct access to global defined variables, since they cannot be defined in .h files and included more than once. - -float& getUserVar(unsigned int varIndex) {return UserVar[varIndex]; } - - -#ifdef USES_BLYNK -// Blynk_get prototype -boolean Blynk_get(const String& command, controllerIndex_t controllerIndex,float *data = NULL ); - -controllerIndex_t firstEnabledBlynk_ControllerIndex(); -#endif - -//void checkRAM( const __FlashStringHelper* flashString); #ifdef CORE_POST_2_5_0 void preinit(); @@ -226,7 +224,7 @@ void setup() if (SpiffsSectors() < 32) { - serialPrintln(F("\nNo (or too small) SPIFFS area..\nSystem Halted\nPlease reflash with 128k SPIFFS minimum!")); + serialPrintln(F("\nNo (or too small) FS area..\nSystem Halted\nPlease reflash with 128k FS minimum!")); while (true) delay(1); } @@ -243,7 +241,6 @@ void setup() log += FreeMem(); addLog(LOG_LEVEL_INFO, log); - //warm boot if (readFromRTC()) { @@ -290,6 +287,18 @@ void setup() progMemMD5check(); LoadSettings(); + #ifdef HAS_ETHERNET + // This ensures, that changing WIFI OR ETHERNET MODE happens properly only after reboot. Changing without reboot would not be a good idea. + // This only works after LoadSettings(); + eth_wifi_mode = Settings.ETH_Wifi_Mode; + log = F("INIT : ETH_WIFI_MODE:"); + log += String(eth_wifi_mode); + log += F(" ("); + log += (eth_wifi_mode == WIFI ? F("WIFI") : F("ETHERNET")); + log += F(")"); + addLog(LOG_LEVEL_INFO, log); + #endif + Settings.UseRTOSMultitasking = false; // For now, disable it, we experience heap corruption. if (RTC.bootFailedCount > 10 && RTC.bootCounter > 10) { byte toDisable = RTC.bootFailedCount - 10; @@ -306,7 +315,7 @@ void setup() RTC.lastWiFiChannel = 0; // Must scan all channels // Wait until scan has finished to make sure as many as possible are found // We're still in the setup phase, so nothing else is taking resources of the ESP. - WifiScan(false); + WifiScan(false, false); } // setWifiMode(WIFI_STA); @@ -351,7 +360,7 @@ void setup() timermqtt_interval = 250; // Interval for checking MQTT timerAwakeFromDeepSleep = millis(); CPluginInit(); - #ifndef NOTIFIER_SET_NONE + #ifdef USES_NOTIFIER NPluginInit(); #endif PluginInit(); @@ -381,7 +390,7 @@ void setup() rulesProcessing(event); // TD-er: Process events in the setup() now. } - WiFiConnectRelaxed(); + NetworkConnectRelaxed(); setWebserverRunning(true); @@ -501,32 +510,6 @@ void updateLoopStats() { longestLoop = usecSince; } -void updateLoopStats_30sec(byte loglevel) { - loopCounterLast = loopCounter; - loopCounter = 0; - if (loopCounterLast > loopCounterMax) - loopCounterMax = loopCounterLast; - - msecTimerHandler.updateIdleTimeStats(); - -#ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(loglevel)) { - String log = F("LoopStats: shortestLoop: "); - log += shortestLoop; - log += F(" longestLoop: "); - log += longestLoop; - log += F(" avgLoopDuration: "); - log += loop_usec_duration_total / loopCounter_full; - log += F(" loopCounterMax: "); - log += loopCounterMax; - log += F(" loopCounterLast: "); - log += loopCounterLast; - addLog(loglevel, log); - } -#endif - loop_usec_duration_total = 0; - loopCounter_full = 1; -} float getCPUload() { return 100.0 - msecTimerHandler.getIdleTimePct(); @@ -553,9 +536,16 @@ void loop() updateLoopStats(); + #ifdef HAS_ETHERNET + // Handle WiFiEvents when compiled with HAS_ETHERNET but in WiFi Mode eth_wifi_mode (WIFI = 0, ETHERNET = 1) + if(eth_wifi_mode == WIFI) { + handle_unprocessedWiFiEvents(); + } + #else handle_unprocessedWiFiEvents(); + #endif - bool firstLoopConnectionsEstablished = WiFiConnected() && firstLoop; + bool firstLoopConnectionsEstablished = NetworkConnected() && firstLoop; if (firstLoopConnectionsEstablished) { addLog(LOG_LEVEL_INFO, F("firstLoopConnectionsEstablished")); firstLoop = false; @@ -637,297 +627,9 @@ void flushAndDisconnectAllClients() { } -#ifdef USES_MQTT - -void updateMQTTclient_connected() { - if (MQTTclient_connected != MQTTclient.connected()) { - MQTTclient_connected = !MQTTclient_connected; - if (!MQTTclient_connected) { - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String connectionError = F("MQTT : Connection lost, state: "); - connectionError += getMQTT_state(); - addLog(LOG_LEVEL_ERROR, connectionError); - } - } else { - schedule_all_tasks_using_MQTT_controller(); - } - if (Settings.UseRules) { - if (MQTTclient_connected) { - eventQueue.add(F("MQTT#Connected")); - } else { - eventQueue.add(F("MQTT#Disconnected")); - } - } - } - if (!MQTTclient_connected) { - // As suggested here: https://github.com/letscontrolit/ESPEasy/issues/1356 - if (timermqtt_interval < 30000) { - timermqtt_interval += 5000; - } - } else { - timermqtt_interval = 250; - } - setIntervalTimer(TIMER_MQTT); -} - -void runPeriodicalMQTT() { - // MQTT_KEEPALIVE = 15 seconds. - if (!WiFiConnected(10)) { - updateMQTTclient_connected(); - return; - } - //dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683) - controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); - if (validControllerIndex(enabledMqttController)) { - if (!MQTTclient.loop()) { - updateMQTTclient_connected(); - if (MQTTCheck(enabledMqttController)) { - updateMQTTclient_connected(); - } - } - } else { - if (MQTTclient.connected()) { - MQTTclient.disconnect(); - updateMQTTclient_connected(); - } - } -} - -controllerIndex_t firstEnabledMQTT_ControllerIndex() { - for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i); - if (validProtocolIndex(ProtocolIndex)) { - if (Protocol[ProtocolIndex].usesMQTT && Settings.ControllerEnabled[i]) { - return i; - } - } - } - return INVALID_CONTROLLER_INDEX; -} - -#endif //USES_MQTT - -#ifdef USES_BLYNK -// Blynk_get prototype -//boolean Blynk_get(const String& command, controllerIndex_t controllerIndex,float *data = NULL ); - -controllerIndex_t firstEnabledBlynk_ControllerIndex() { - for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i); - if (validProtocolIndex(ProtocolIndex)) { - if (Protocol[ProtocolIndex].Number == 12 && Settings.ControllerEnabled[i]) { - return i; - } - } - } - return INVALID_CONTROLLER_INDEX; -} -#endif -/*********************************************************************************************\ - * Tasks that run 50 times per second -\*********************************************************************************************/ -void run50TimesPerSecond() { - String dummy; - { - START_TIMER; - PluginCall(PLUGIN_FIFTY_PER_SECOND, 0, dummy); - STOP_TIMER(PLUGIN_CALL_50PS); - } - { - START_TIMER; - CPluginCall(CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND, 0, dummy); - STOP_TIMER(CPLUGIN_CALL_50PS); - } -} - -/*********************************************************************************************\ - * Tasks that run 10 times per second -\*********************************************************************************************/ -void run10TimesPerSecond() { - String dummy; - { - START_TIMER; - PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummy); - STOP_TIMER(PLUGIN_CALL_10PS); - } - { - START_TIMER; -// PluginCall(PLUGIN_UNCONDITIONAL_POLL, 0, dummyString); - PluginCall(PLUGIN_MONITOR, 0, dummy); - STOP_TIMER(PLUGIN_CALL_10PSU); - } - { - START_TIMER; - CPluginCall(CPlugin::Function::CPLUGIN_TEN_PER_SECOND, 0, dummy); - STOP_TIMER(CPLUGIN_CALL_10PS); - } - processNextEvent(); - - #ifdef USES_C015 - if (WiFiConnected()) - Blynk_Run_c015(); - #endif - #ifndef USE_RTOS_MULTITASKING - web_server.handleClient(); - #endif -} - - -/*********************************************************************************************\ - * Tasks each second -\*********************************************************************************************/ -void runOncePerSecond() -{ - START_TIMER; - updateLogLevelCache(); - dailyResetCounter++; - if (dailyResetCounter > 86400) // 1 day elapsed... //86400 - { - RTC.flashDayCounter=0; - saveToRTC(); - dailyResetCounter=0; - addLog(LOG_LEVEL_INFO, F("SYS : Reset 24h counters")); - } - - if (Settings.ConnectionFailuresThreshold) - if (connectionFailures > Settings.ConnectionFailuresThreshold) - delayedReboot(60); - - if (cmd_within_mainloop != 0) - { - switch (cmd_within_mainloop) - { - case CMD_WIFI_DISCONNECT: - { - WifiDisconnect(); - break; - } - case CMD_REBOOT: - { - reboot(); - break; - } - } - cmd_within_mainloop = 0; - } - // clock events - if (node_time.reportNewMinute()) { - String dummy; - PluginCall(PLUGIN_CLOCK_IN, 0, dummy); - if (Settings.UseRules) - { - String event; - event.reserve(21); - event = F("Clock#Time="); - event += node_time.weekday_str(); - event += ","; - - if (node_time.hour() < 10) { - event += '0'; - } - event += node_time.hour(); - event += ":"; - - if (node_time.minute() < 10) { - event += '0'; - } - event += node_time.minute(); - // TD-er: Do not add to the eventQueue, but execute right now. - rulesProcessing(event); - } - } - -// unsigned long start = micros(); - String dummy; - PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummy); -// unsigned long elapsed = micros() - start; - - if (Settings.UseRules) - rulesTimers(); - - - if (SecuritySettings.Password[0] != 0) - { - if (WebLoggedIn) - WebLoggedInTimer++; - if (WebLoggedInTimer > 300) - WebLoggedIn = false; - } - - // I2C Watchdog feed - if (Settings.WDI2CAddress != 0) - { - Wire.beginTransmission(Settings.WDI2CAddress); - Wire.write(0xA5); - Wire.endTransmission(); - } - - checkResetFactoryPin(); - STOP_TIMER(PLUGIN_CALL_1PS); -} - -void logTimerStatistics() { - byte loglevel = LOG_LEVEL_DEBUG; - updateLoopStats_30sec(loglevel); -#ifndef BUILD_NO_DEBUG -// logStatistics(loglevel, true); - if (loglevelActiveFor(loglevel)) { - String queueLog = F("Scheduler stats: (called/tasks/max_length/idle%) "); - queueLog += msecTimerHandler.getQueueStats(); - addLog(loglevel, queueLog); - } -#endif -} - -/*********************************************************************************************\ - * Tasks each 30 seconds -\*********************************************************************************************/ -void runEach30Seconds() -{ - checkRAMtoLog(); - wdcounter++; - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - log.reserve(80); - log = F("WD : Uptime "); - log += wdcounter / 2; - log += F(" ConnectFailures "); - log += connectionFailures; - log += F(" FreeMem "); - log += FreeMem(); - log += F(" WiFiStatus "); - log += WiFi.status(); -// log += F(" ListenInterval "); -// log += WiFi.getListenInterval(); - addLog(LOG_LEVEL_INFO, log); - } - sendSysInfoUDP(1); - refreshNodeList(); - - // sending $stats to homie controller - CPluginCall(CPlugin::Function::CPLUGIN_INTERVAL, 0); - - #if defined(ESP8266) - #ifdef USES_SSDP - if (Settings.UseSSDP) - SSDP_update(); - - #endif // USES_SSDP - #endif -#if FEATURE_ADC_VCC - if (!wifiConnectInProgress) { - vcc = ESP.getVcc() / 1000.0; - } -#endif - - #ifdef FEATURE_REPORTING - ReportStatus(); - #endif - -} @@ -958,14 +660,14 @@ void backgroundtasks() return; } START_TIMER - const bool wifiConnected = WiFiConnected(); + const bool networkConnected = NetworkConnected(); runningBackgroundTasks=true; - #if defined(ESP8266) - if (wifiConnected) { - tcpCleanup(); + if (networkConnected) { + #if defined(ESP8266) + tcpCleanup(); + #endif } - #endif process_serialWriteBuffer(); if(!UseRTOSMultitasking){ if (Settings.UseSerial && Serial.available()) { @@ -977,7 +679,12 @@ void backgroundtasks() if (webserverRunning) { web_server.handleClient(); } - if (WiFi.getMode() != WIFI_OFF) { + if (WiFi.getMode() != WIFI_OFF + // This makes UDP working for ETHERNET + #ifdef HAS_ETHERNET + || eth_connected + #endif + ) { checkUDP(); } } @@ -987,14 +694,14 @@ void backgroundtasks() dnsServer.processNextRequest(); #ifdef FEATURE_ARDUINO_OTA - if(Settings.ArduinoOTAEnable && wifiConnected) + if(Settings.ArduinoOTAEnable && networkConnected) ArduinoOTA.handle(); //once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails) while (ArduinoOTAtriggered) { delay(0); - if (WiFiConnected()) { + if (NetworkConnected()) { ArduinoOTA.handle(); } } @@ -1003,7 +710,7 @@ void backgroundtasks() #ifdef FEATURE_MDNS // Allow MDNS processing - if (wifiConnected) { + if (networkConnected) { MDNS.update(); } #endif @@ -1014,4 +721,4 @@ void backgroundtasks() runningBackgroundTasks=false; STOP_TIMER(BACKGROUND_TASKS); -} +} \ No newline at end of file diff --git a/src/ESPEasyEth.cpp b/src/ESPEasyEth.cpp new file mode 100644 index 000000000..603e57cff --- /dev/null +++ b/src/ESPEasyEth.cpp @@ -0,0 +1,131 @@ +#ifdef HAS_ETHERNET + +#include "ESPEasyEth.h" +#include "ESPEasyNetwork.h" +#include "ETH.h" +#include "ESPEasy-Globals.h" +#include "eth_phy/phy.h" +#include "src/Helpers/StringConverter.h" + +bool ethUseStaticIP() { + return Settings.ETH_IP[0] != 0 && Settings.ETH_IP[0] != 255; +} + +void ethSetupStaticIPconfig() { + if (!ethUseStaticIP()) { return; } + const IPAddress ip = Settings.ETH_IP; + const IPAddress gw = Settings.ETH_Gateway; + const IPAddress subnet = Settings.ETH_Subnet; + const IPAddress dns = Settings.ETH_DNS; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ETH IP : Static IP : "); + log += formatIP(ip); + log += F(" GW: "); + log += formatIP(gw); + log += F(" SN: "); + log += formatIP(subnet); + log += F(" DNS: "); + log += formatIP(dns); + addLog(LOG_LEVEL_INFO, log); + } + ETH.config(ip, gw, subnet, dns); +} + +bool ethCheckSettings() { + bool result = true; + if (Settings.ETH_Phy_Type != 0 && Settings.ETH_Phy_Type != 1) + result = false; + if (Settings.ETH_Clock_Mode > 3) + result = false; + if (Settings.ETH_Wifi_Mode > 1) + result = false; + if (Settings.ETH_Pin_mdc > MAX_GPIO) + result = false; + if (Settings.ETH_Pin_mdio > MAX_GPIO) + result = false; + if (Settings.ETH_Pin_power > MAX_GPIO) + result = false; + return result; +} + +bool ethPrepare() { + if (!ethCheckSettings()) + { + addLog(LOG_LEVEL_ERROR, F("ETH: Settings not correct!!!")); + return false; + } + char hostname[40]; + safe_strncpy(hostname, NetworkCreateRFCCompliantHostname().c_str(), sizeof(hostname)); + ETH.setHostname(hostname); + ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + ethSetupStaticIPconfig(); + return true; +} + +String ethGetDebugClockModeStr() { + switch (Settings.ETH_Clock_Mode) + { + case 0: return F("ETH_CLOCK_GPIO0_IN"); + case 1: return F("ETH_CLOCK_GPIO0_OUT"); + case 2: return F("ETH_CLOCK_GPIO16_OUT"); + case 3: return F("ETH_CLOCK_GPIO17_OUT"); + default: return F("ETH_CLOCK_ERR"); + } +} + +String ethGetDebugEthWifiModeStr() { + switch (eth_wifi_mode) + { + case 0: return F("WIFI"); + case 1: return F("ETHERNET"); + default: return F("ETH_WIFI_ERR"); + } +} + +void ethPrintSettings() { + String settingsDebugLog; + settingsDebugLog.reserve(115); + settingsDebugLog += F("Eth Wifi mode: "); + settingsDebugLog += ethGetDebugEthWifiModeStr(); + settingsDebugLog += F(" ETH: PHY Type: "); + settingsDebugLog += Settings.ETH_Phy_Type == 0 ? F("ETH_PHY_LAN8720") : F("ETH_PHY_TLK110"); + settingsDebugLog += F(" PHY Addr: "); + settingsDebugLog += Settings.ETH_Phy_Addr; + settingsDebugLog += F(" Eth Clock mode: "); + settingsDebugLog += ethGetDebugClockModeStr(); + settingsDebugLog += F(" MDC Pin: "); + settingsDebugLog += String(Settings.ETH_Pin_mdc); + settingsDebugLog += F(" MIO Pin: "); + settingsDebugLog += String(Settings.ETH_Pin_mdio); + settingsDebugLog += F(" Power Pin: "); + settingsDebugLog += String(Settings.ETH_Pin_power); + addLog(LOG_LEVEL_INFO, settingsDebugLog); +} + +uint8_t * ETHMacAddress(uint8_t* mac) { + esp_eth_get_mac(mac); + return mac; +} + +void ETHConnectRelaxed() { + ethPrintSettings(); + ETH.begin(Settings.ETH_Phy_Addr, + Settings.ETH_Pin_power, + Settings.ETH_Pin_mdc, + Settings.ETH_Pin_mdio, + (eth_phy_type_t)Settings.ETH_Phy_Type, + (eth_clock_mode_t)Settings.ETH_Clock_Mode); + addLog(LOG_LEVEL_INFO, F("After ETH.begin")); + if (!ethPrepare()) { + // Dead code for now... + addLog(LOG_LEVEL_ERROR, F("ETH : Could not prepare ETH!")); + return; + } +} + +bool ETHConnected() { + return eth_connected; +} + +#endif \ No newline at end of file diff --git a/src/ESPEasyEth.h b/src/ESPEasyEth.h new file mode 100644 index 000000000..b130144e9 --- /dev/null +++ b/src/ESPEasyEth.h @@ -0,0 +1,19 @@ +#ifdef HAS_ETHERNET +#ifndef ESPEASY_ETH_H +#define ESPEASY_ETH_H + +#include "ESPEasy_common.h" + +bool ethUseStaticIP(); +void ethSetupStaticIPconfig(); +bool ethCheckSettings(); +bool ethPrepare(); +String ethGetDebugClockModeStr(); +String ethGetDebugEthWifiModeStr(); +void ethPrintSettings(); +void ETHConnectRelaxed(); +bool ETHConnected(); +uint8_t * ETHMacAddress(uint8_t* mac); + +#endif // ESPEASY_ETH_H +#endif \ No newline at end of file diff --git a/src/ESPEasyEthWifi.h b/src/ESPEasyEthWifi.h new file mode 100644 index 000000000..a7fec2e5d --- /dev/null +++ b/src/ESPEasyEthWifi.h @@ -0,0 +1,14 @@ +#ifdef HAS_ETHERNET +#ifndef ESPEASY_WTH_WIFI_H_ +#define ESPEASY_WTH_WIFI_H_ + +#ifndef WIFI +#define WIFI 0 +#endif + +#ifndef ETHERNET +#define ETHERNET 1 +#endif + +#endif // ESPEASY_WTH_WIFI_H_ +#endif // HAS_ETHERNET \ No newline at end of file diff --git a/src/ESPEasyNetwork.cpp b/src/ESPEasyNetwork.cpp new file mode 100644 index 000000000..0dc168f51 --- /dev/null +++ b/src/ESPEasyNetwork.cpp @@ -0,0 +1,183 @@ +#include "ESPEasyNetwork.h" +#include "ESPEasy_fdwdecl.h" +#include "ESPEasy-Globals.h" +#include "ESPEasy_Log.h" +#include "ESPEasyEth.h" +#include "src/Helpers/StringConverter.h" +#include "ESPEasyWifi.h" + +#ifdef HAS_ETHERNET +#include "ETH.h" +#endif + +/*********************************************************************************************\ + Ethernet or Wifi Support for ESP32 Build flag HAS_ETHERNET +\*********************************************************************************************/ +void NetworkConnectRelaxed() { +#ifdef HAS_ETHERNET + addLog(LOG_LEVEL_INFO, F("Connect to: ")); + addLog(LOG_LEVEL_INFO, ethGetDebugEthWifiModeStr()); + if(eth_wifi_mode == ETHERNET) { + ETHConnectRelaxed(); + } else { + WiFiConnectRelaxed(); + } +#else + WiFiConnectRelaxed(); +#endif +} + +bool NetworkConnected() { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + return ETHConnected(); + } else { + return WiFiConnected(); + } + #else + return WiFiConnected(); + #endif +} + +IPAddress NetworkLocalIP() { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + if(eth_connected) { + return ETH.localIP(); + } else { + addLog(LOG_LEVEL_ERROR, F("Call NetworkLocalIP() only on connected Ethernet!")); + return IPAddress(); + } + } else { + return WiFi.localIP(); + } + #else + return WiFi.localIP(); + #endif +} + +IPAddress NetworkSubnetMask() { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + if(eth_connected) { + return ETH.subnetMask(); + } else { + addLog(LOG_LEVEL_ERROR, F("Call NetworkSubnetMask() only on connected Ethernet!")); + return IPAddress(); + } + } else { + return WiFi.subnetMask(); + } + #else + return WiFi.subnetMask(); + #endif +} + +IPAddress NetworkGatewayIP() { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + if(eth_connected) { + return ETH.gatewayIP(); + } else { + addLog(LOG_LEVEL_ERROR, F("Call NetworkGatewayIP() only on connected Ethernet!")); + return IPAddress(); + } + } else { + return WiFi.gatewayIP(); + } + #else + return WiFi.gatewayIP(); + #endif +} + +IPAddress NetworkDnsIP (uint8_t dns_no) { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + if(eth_connected) { + return ETH.dnsIP(); + } else { + addLog(LOG_LEVEL_ERROR, F("Call NetworkDnsIP(uint8_t dns_no) only on connected Ethernet!")); + return IPAddress(); + } + } else { + return WiFi.dnsIP(dns_no); + } + #else + return WiFi.dnsIP(dns_no); + #endif +} + +String NetworkMacAddress() { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + if(!eth_connected) { + addLog(LOG_LEVEL_ERROR, F("Call NetworkMacAddress() only on connected Ethernet!")); + } else { + return ETH.macAddress(); + } + } + #endif + + uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; + uint8_t *macread = NetworkMacAddressAsBytes(mac); + char macaddress[20]; + formatMAC(macread, macaddress); + + return String(macaddress); +} + +uint8_t * NetworkMacAddressAsBytes(uint8_t* mac) { + #ifdef HAS_ETHERNET + if(eth_wifi_mode == ETHERNET) { + return ETHMacAddress(mac); + } else { + return WiFi.macAddress(mac); + } + #else + return WiFi.macAddress(mac); + #endif +} + +String NetworkGetHostname() { + #ifdef ESP32 + #ifdef HAS_ETHERNET + if(Settings.ETH_Wifi_Mode == ETHERNET) { + return String(ETH.getHostname()); + } + return String(WiFi.getHostname()); + #else + return String(WiFi.getHostname()); + #endif + #else + return String(WiFi.hostname()); + #endif +} + +// ******************************************************************************** +// Determine Wifi AP name to set. (also used for mDNS) +// ******************************************************************************** +String NetworkGetHostNameFromSettings() +{ + return Settings.getHostname(); +} + +String NetworkCreateRFCCompliantHostname() { + return createRFCCompliantHostname(NetworkGetHostNameFromSettings()); +} + +// Create hostname with - instead of spaces +String createRFCCompliantHostname(String oldString) { + String result(oldString); + + result.replace(" ", "-"); + result.replace("_", "-"); // See RFC952 + return result; +} + +String WifiSoftAPmacAddress() { + uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; + uint8_t *macread = WiFi.softAPmacAddress(mac); + char macaddress[20]; + formatMAC(macread, macaddress); + return String(macaddress); +} \ No newline at end of file diff --git a/src/ESPEasyNetwork.h b/src/ESPEasyNetwork.h new file mode 100644 index 000000000..cdb774e85 --- /dev/null +++ b/src/ESPEasyNetwork.h @@ -0,0 +1,21 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include "ESPEasy-Globals.h" + +void NetworkConnectRelaxed(); +bool NetworkConnected(); +IPAddress NetworkLocalIP(); +IPAddress NetworkSubnetMask(); +IPAddress NetworkGatewayIP(); +IPAddress NetworkDnsIP (uint8_t dns_no); +uint8_t * NetworkMacAddressAsBytes(uint8_t* mac); +String NetworkMacAddress(); +String NetworkGetHostNameFromSettings(); +String NetworkGetHostname(); +String NetworkCreateRFCCompliantHostname(); +String createRFCCompliantHostname(String oldString); +String WifiSoftAPmacAddress(); + + +#endif // NETWORK_H \ No newline at end of file diff --git a/src/ESPEasyRTC.ino b/src/ESPEasyRTC.ino index 9326a3a21..66df031e7 100644 --- a/src/ESPEasyRTC.ino +++ b/src/ESPEasyRTC.ino @@ -45,16 +45,16 @@ // Locations where to store the cached data -// As a file on the SPIFFS filesystem +// As a file on the filesystem #define CACHE_STORAGE_SPIFFS 0 -// Between the sketch and SPIFFS, including OTA area (will overwrite this area when performing OTA) +// Between the sketch and FS, including OTA area (will overwrite this area when performing OTA) #define CACHE_STORAGE_OTA_FREE 1 -// Only use the free space between sketch and SPIFFS, thus avoid OTA area +// Only use the free space between sketch and FS, thus avoid OTA area #define CACHE_STORAGE_NO_OTA_FREE 2 -// Use space after SPIFFS. (e.g. on 16M flash partitioned as 4M, or 4M flash partitioned as 2M) +// Use space after FS. (e.g. on 16M flash partitioned as 4M, or 4M flash partitioned as 2M) #define CACHE_STORAGE_BEHIND_SPIFFS 3 @@ -114,7 +114,7 @@ boolean readFromRTC() /********************************************************************************************\ Save values to RTC memory \*********************************************************************************************/ -boolean saveUserVarToRTC() +bool saveUserVarToRTC() { #if defined(ESP32) return false; @@ -124,7 +124,7 @@ boolean saveUserVarToRTC() byte *buffer = (byte *)&UserVar; size_t size = sizeof(UserVar); uint32_t sum = calc_CRC32(buffer, size); - boolean ret = system_rtc_mem_write(RTC_BASE_USERVAR, buffer, size); + bool ret = system_rtc_mem_write(RTC_BASE_USERVAR, buffer, size); ret &= system_rtc_mem_write(RTC_BASE_USERVAR + (size >> 2), (byte *)&sum, 4); return ret; #endif // if defined(ESP32) @@ -313,7 +313,7 @@ struct RTC_cache_handler_struct for (int i = 0; i < 2; ++i) { String fname = createCacheFilename(RTC_cache.readFileNr); - if (SPIFFS.exists(fname)) { + if (ESPEASY_FS.exists(fname)) { if (i != 0) { // First attempt failed, so stored read position is not valid RTC_cache.readPos = 0; @@ -346,7 +346,7 @@ struct RTC_cache_handler_struct } islast = peekfilenr > RTC_cache.writeFileNr; - if (SPIFFS.exists(fname)) { + if (ESPEASY_FS.exists(fname)) { return fname; } return ""; @@ -360,7 +360,7 @@ struct RTC_cache_handler_struct if (tryDeleteFile(fname)) { #ifdef RTC_STRUCT_DEBUG - String log = F("RTC : Removed file from SPIFFS: "); + String log = F("RTC : Removed file from FS: "); log += fname; addLog(LOG_LEVEL_INFO, String(log)); #endif // ifdef RTC_STRUCT_DEBUG @@ -503,7 +503,7 @@ private: // } if (SpiffsFull()) { #ifdef RTC_STRUCT_DEBUG - addLog(LOG_LEVEL_ERROR, String(F("RTC : SPIFFS full"))); + addLog(LOG_LEVEL_ERROR, String(F("RTC : FS full"))); #endif // ifdef RTC_STRUCT_DEBUG return false; } diff --git a/src/ESPEasyRules.ino b/src/ESPEasyRules.ino index 9f60893f1..49baecf02 100644 --- a/src/ESPEasyRules.ino +++ b/src/ESPEasyRules.ino @@ -1,11 +1,13 @@ #define RULE_FILE_SEPARAROR '/' #define RULE_MAX_FILENAME_LENGTH 24 +#include "src/Commands/InternalCommands.h" #include "src/DataStructs/EventValueSource.h" #include "src/Globals/Device.h" #include "src/Globals/Plugins.h" #include "src/Globals/Plugins_other.h" #include "src/Helpers/ESPEasy_time_calc.h" +#include "src/Helpers/Numerical.h" String EventToFileName(const String& eventName) { int size = eventName.length(); @@ -48,7 +50,7 @@ void checkRuleSets() { fileName += x + 1; fileName += F(".txt"); - if (SPIFFS.exists(fileName)) { + if (ESPEASY_FS.exists(fileName)) { activeRuleSets[x] = true; } else { @@ -122,7 +124,7 @@ void rulesProcessing(String& event) { String fileName = EventToFileName(event); // if exists processed the rule file - if (SPIFFS.exists(fileName)) { + if (ESPEASY_FS.exists(fileName)) { rulesProcessingFile(fileName, event); } #ifndef BUILD_NO_DEBUG @@ -756,7 +758,7 @@ void processMatchedRule(String& action, String& event, addLog(LOG_LEVEL_INFO, log); } - ExecuteCommand_all(VALUE_SOURCE_RULES, action.c_str()); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_RULES, action.c_str()); delay(0); } } diff --git a/src/ESPEasyStatistics.ino b/src/ESPEasyStatistics.ino index 1105ca6a0..d02bb94a6 100644 --- a/src/ESPEasyStatistics.ino +++ b/src/ESPEasyStatistics.ino @@ -1,4 +1,4 @@ -#include "define_plugin_sets.h" +#include "ESPEasy_common.h" #ifdef USES_TIMING_STATS diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index e8ac039e3..939b1e884 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -1,12 +1,22 @@ +#ifdef HAS_ETHERNET +#include "ETH.h" +#endif #include "ESPEasyWiFiEvent.h" +#include "ESPEasyWifi_ProcessEvent.h" #include "src/Globals/ESPEasyWiFiEvent.h" #include "src/Globals/RTC.h" #include "ESPEasyTimeTypes.h" +#include "ESPEasy_Log.h" +#include "ESPEasy_fdwdecl.h" #include "src/DataStructs/RTCStruct.h" #include "src/Helpers/ESPEasy_time_calc.h" +#ifdef HAS_ETHERNET +extern bool eth_connected; +#endif + #ifdef ESP32 void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { _useStaticIp = enabled; @@ -99,6 +109,50 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { case SYSTEM_EVENT_SCAN_DONE: processedScanDone = false; break; +#ifdef HAS_ETHERNET + case SYSTEM_EVENT_ETH_START: + addLog(LOG_LEVEL_INFO, F("ETH Started")); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + addLog(LOG_LEVEL_INFO, F("ETH Connected")); + eth_connected = true; + processEthernetConnected(); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + { + String log = F("ETH MAC: "); + log += NetworkMacAddress(); + log += F(" IPv4: "); + log += NetworkLocalIP().toString(); + log += " ("; + log += NetworkGetHostname(); + log += F(") GW: "); + log += NetworkGatewayIP().toString(); + log += F(" SN: "); + log += NetworkSubnetMask().toString(); + if (ETH.fullDuplex()) { + log += F(" FULL_DUPLEX"); + } + log += F(" "); + log += ETH.linkSpeed(); + log += F("Mbps"); + addLog(LOG_LEVEL_INFO, log); + } + eth_connected = true; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + addLog(LOG_LEVEL_ERROR, F("ETH Disconnected")); + eth_connected = false; + processEthernetDisconnected(); + break; + case SYSTEM_EVENT_ETH_STOP: + addLog(LOG_LEVEL_INFO, F("ETH Stopped")); + eth_connected = false; + break; + case SYSTEM_EVENT_GOT_IP6: + addLog(LOG_LEVEL_INFO, F("ETH Got IP6")); + break; +#endif //HAS_ETHERNET default: break; } diff --git a/src/ESPEasyWiFi_credentials.ino b/src/ESPEasyWiFi_credentials.cpp similarity index 92% rename from src/ESPEasyWiFi_credentials.ino rename to src/ESPEasyWiFi_credentials.cpp index 3289fa2fb..aea8a2c5a 100644 --- a/src/ESPEasyWiFi_credentials.ino +++ b/src/ESPEasyWiFi_credentials.cpp @@ -1,3 +1,7 @@ +#include "ESPEasyWiFi_credentials.h" +#include "src/Globals/RTC.h" +#include "src/Globals/SecuritySettings.h" + // ******************************************************************************** // Manage WiFi credentials // ******************************************************************************** diff --git a/src/ESPEasyWiFi_credentials.h b/src/ESPEasyWiFi_credentials.h new file mode 100644 index 000000000..f608100d9 --- /dev/null +++ b/src/ESPEasyWiFi_credentials.h @@ -0,0 +1,11 @@ +#ifndef ESPEASYWIFI_CREDENTIALS_H +#define ESPEASYWIFI_CREDENTIALS_H + +const char* getLastWiFiSettingsSSID(); +const char* getLastWiFiSettingsPassphrase(); +bool selectNextWiFiSettings(); +bool selectValidWiFiSettings(); +bool wifiSettingsValid(const char *ssid, const char *pass); + + +#endif // ESPEASYWIFI_CREDENTIALS_H \ No newline at end of file diff --git a/src/ESPEasyWifi.ino b/src/ESPEasyWifi.cpp similarity index 95% rename from src/ESPEasyWifi.ino rename to src/ESPEasyWifi.cpp index 9eec41d8d..4ab6b0c8f 100644 --- a/src/ESPEasyWifi.ino +++ b/src/ESPEasyWifi.cpp @@ -1,10 +1,15 @@ -#define WIFI_RECONNECT_WAIT 20000 // in milliSeconds -#define WIFI_AP_OFF_TIMER_DURATION 60000 // in milliSeconds -#define WIFI_CONNECTION_CONSIDERED_STABLE 300000 // in milliSeconds -#define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes - +#include "ESPEasyWifi.h" +#include "ESPEasyNetwork.h" +#include "ESPEasyWifi_ProcessEvent.h" #include "src/Globals/ESPEasyWiFiEvent.h" #include "ESPEasy-Globals.h" +#include "ESPEasyWiFi_credentials.h" +#include "src/DataStructs/TimingStats.h" +#include "src/Globals/EventQueue.h" +#include "src/Globals/RTC.h" +#include "src/Globals/SecuritySettings.h" +#include "src/Helpers/ESPEasy_time_calc.h" +#include "src/Helpers/StringConverter.h" // ******************************************************************************** // WiFi state @@ -203,7 +208,7 @@ bool prepareWiFi() { } setSTA(true); char hostname[40]; - safe_strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname)); + safe_strncpy(hostname, NetworkCreateRFCCompliantHostname().c_str(), sizeof(hostname)); #if defined(ESP8266) wifi_station_set_hostname(hostname); @@ -220,7 +225,7 @@ bool prepareWiFi() { #endif // if defined(ESP32) if (RTC.lastWiFiChannel == 0 && wifi_connect_attempt <= 1) { - WifiScan(true); + WifiScan(false, true); } setConnectionSpeed(); setupStaticIPconfig(); @@ -300,7 +305,7 @@ void WifiScan() { // Direct Serial is allowed here, since this function will only be called from serial input. serialPrintln(F("WIFI : SSID Scan start")); - WifiScan(false); + WifiScan(false, false); const int8_t scanCompleteStatus = WiFi.scanComplete(); if (scanCompleteStatus <= 0) { serialPrintln(F("WIFI : No networks found")); @@ -381,7 +386,7 @@ void setAPinternal(bool enable) if (enable) { // 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 - String softAPSSID = WifiGetAPssid(); + String softAPSSID = NetworkCreateRFCCompliantHostname(); String pwd = SecuritySettings.WifiAPKey; IPAddress subnet(DEFAULT_AP_SUBNET); @@ -506,26 +511,6 @@ bool WifiIsSTA(WiFiMode_t wifimode) #endif // if defined(ESP32) } -// ******************************************************************************** -// Determine Wifi AP name to set. (also used for mDNS) -// ******************************************************************************** -String WifiGetAPssid() -{ - return Settings.getHostname(); -} - -// ******************************************************************************** -// Determine hostname: basically WifiGetAPssid with spaces changed to - -// ******************************************************************************** -String WifiGetHostname() -{ - String hostname(WifiGetAPssid()); - - hostname.replace(" ", "-"); - hostname.replace("_", "-"); // See RFC952 - return hostname; -} - bool useStaticIP() { return Settings.IP[0] != 0 && Settings.IP[0] != 255; } diff --git a/src/ESPEasyWifi.h b/src/ESPEasyWifi.h new file mode 100644 index 000000000..3a11606ed --- /dev/null +++ b/src/ESPEasyWifi.h @@ -0,0 +1,43 @@ +#ifndef ESPEASY_WIFI_H +#define ESPEASY_WIFI_H + +#include "ESPEasy_common.h" + +#if defined(ESP8266) + # include + # include +#endif // if defined(ESP8266) +#if defined(ESP32) + # include + # include +#endif // if defined(ESP32) + + +#define WIFI_RECONNECT_WAIT 20000 // in milliSeconds +#define WIFI_AP_OFF_TIMER_DURATION 60000 // in milliSeconds +#define WIFI_CONNECTION_CONSIDERED_STABLE 300000 // in milliSeconds +#define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes + +bool WiFiConnected(); +void WiFiConnectRelaxed(); +bool prepareWiFi(); +void resetWiFi(); +void WifiDisconnect(); +void WifiScan(bool async, bool quick); +void WifiScan(); +void setSTA(bool enable); +void setAP(bool enable); +String getWifiModeString(WiFiMode_t wifimode); +void setWifiMode(WiFiMode_t wifimode); +bool WifiIsAP(WiFiMode_t wifimode); +bool useStaticIP(); +bool wifiConnectTimeoutReached(); +bool wifiAPmodeActivelyUsed(); +void setConnectionSpeed(); +void setupStaticIPconfig(); +String formatScanResult(int i, const String& separator); +String formatScanResult(int i, const String& separator, int32_t& rssi); +void logConnectionStatus(); +String getLastDisconnectReason(); + +#endif // ESPEASY_WIFI_H \ No newline at end of file diff --git a/src/ESPEasyWifi_ProcessEvent.ino b/src/ESPEasyWifi_ProcessEvent.cpp similarity index 89% rename from src/ESPEasyWifi_ProcessEvent.ino rename to src/ESPEasyWifi_ProcessEvent.cpp index 3f8e563d5..f5b485513 100644 --- a/src/ESPEasyWifi_ProcessEvent.ino +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -1,4 +1,19 @@ +#include "ESPEasyWifi_ProcessEvent.h" +#include "ESPEasy-Globals.h" +#include "ESPEasyNetwork.h" +#include "ESPEasyWifi.h" +#include "ESPEasyWiFi_credentials.h" +#include "ESPEasy_fdwdecl.h" +#include "src/DataStructs/SchedulerTimers.h" #include "src/Globals/ESPEasyWiFiEvent.h" +#include "src/Globals/EventQueue.h" +#include "src/Globals/RTC.h" +#include "src/Globals/MQTT.h" +#include "src/Helpers/ESPEasy_Storage.h" +#include "src/Helpers/ESPEasy_time_calc.h" +#include "src/Helpers/StringConverter.h" +#include "src/Helpers/Scheduler.h" + bool unprocessedWifiEvents() { if (processedConnect && processedDisconnect && processedGotIP && processedDHCPTimeout) @@ -24,7 +39,7 @@ void handle_unprocessedWiFiEvents() delay(1); if (wifiConnectAttemptNeeded) { - WiFiConnectRelaxed(); + NetworkConnectRelaxed(); } // Process disconnect events before connect events. @@ -82,7 +97,7 @@ void handle_unprocessedWiFiEvents() markWiFi_services_initialized(); } } - } else if (!WiFiConnected()) { + } else if (!NetworkConnected()) { // Somehow the WiFi has entered a limbo state. // FIXME TD-er: This may happen on WiFi config with AP_STA mode active. // addLog(LOG_LEVEL_ERROR, F("Wifi status out sync")); @@ -99,10 +114,18 @@ void handle_unprocessedWiFiEvents() #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String wifilog = F("WIFI : Disconnected: WiFi.status() = "); - wifilog += String(WiFi.status()); + static unsigned long lastDisconnectMoment_log = 0; + static uint8_t lastWiFiStatus_log = 0; + uint8_t cur_wifi_status = WiFi.status(); + if (lastDisconnectMoment != lastDisconnectMoment_log || + lastWiFiStatus_log != cur_wifi_status) { + lastDisconnectMoment_log = lastDisconnectMoment; + lastWiFiStatus_log = cur_wifi_status; + String wifilog = F("WIFI : Disconnected: WiFi.status() = "); + wifilog += String(cur_wifi_status); - addLog(LOG_LEVEL_DEBUG, wifilog); + addLog(LOG_LEVEL_DEBUG, wifilog); + } } #endif // ifndef BUILD_NO_DEBUG @@ -223,7 +246,7 @@ void processGotIP() { // Only process GotIP events if we are connected. return; } - IPAddress ip = WiFi.localIP(); + IPAddress ip = NetworkLocalIP(); if (!useStaticIP()) { if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) { @@ -232,8 +255,8 @@ void processGotIP() { } processedGotIP = true; wifiStatus |= ESPEASY_WIFI_GOT_IP; - const IPAddress gw = WiFi.gatewayIP(); - const IPAddress subnet = WiFi.subnetMask(); + const IPAddress gw = NetworkGatewayIP(); + const IPAddress subnet = NetworkSubnetMask(); const long dhcp_duration = timeDiff(lastConnectMoment, lastGetIPmoment); if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -246,7 +269,7 @@ void processGotIP() { } log += formatIP(ip); log += " ("; - log += WifiGetHostname(); + log += NetworkGetHostname(); log += F(") GW: "); log += formatIP(gw); log += F(" SN: "); @@ -442,4 +465,23 @@ void markWiFi_services_initialized() { wifiConnectInProgress = false; processedDHCPTimeout = true; // FIXME TD-er: Is this ever happening? -} \ No newline at end of file +} + +#ifdef HAS_ETHERNET + +void processEthernetConnected() { + if (Settings.UseRules) + { + eventQueue.add(F("ETHERNET#Connected")); + } + statusLED(true); +} + +void processEthernetDisconnected() { + if (Settings.UseRules) + { + eventQueue.add(F("ETHERNET#Disconnected")); + } +} + +#endif \ No newline at end of file diff --git a/src/ESPEasyWifi_ProcessEvent.h b/src/ESPEasyWifi_ProcessEvent.h new file mode 100644 index 000000000..78c4a1161 --- /dev/null +++ b/src/ESPEasyWifi_ProcessEvent.h @@ -0,0 +1,20 @@ +#ifndef ESPEASYWIFI_PROCESSEVENT_H +#define ESPEASYWIFI_PROCESSEVENT_H + +bool unprocessedWifiEvents(); +void handle_unprocessedWiFiEvents(); +void processDisconnect(); +void processConnect(); +void processGotIP(); +void processDisconnectAPmode(); +void processConnectAPmode(); +void processDisableAPmode(); +void processScanDone(); +void markWiFi_services_initialized(); + +#ifdef HAS_ETHERNET +void processEthernetConnected(); +void processEthernetDisconnected(); +#endif + +#endif //ESPEASYWIFI_PROCESSEVENT_H \ No newline at end of file diff --git a/src/ESPEasy_buildinfo.h b/src/ESPEasy_buildinfo.h index b6647320a..ccdc2b084 100644 --- a/src/ESPEasy_buildinfo.h +++ b/src/ESPEasy_buildinfo.h @@ -20,7 +20,7 @@ #endif // if defined(ESP32) -#define BUILD 20107 // git version e.g. "20103" can be read as "2.1.03" (stored in int16_t) +#define BUILD 20108 // git version e.g. "20103" can be read as "2.1.03" (stored in int16_t) #if defined(ESP8266) # define BUILD_NOTES " - Mega" #endif // if defined(ESP8266) diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index b69eebbc5..d1845bf12 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -22,6 +22,12 @@ namespace std #include "src/DataStructs/ESPEasyDefaults.h" +#ifdef USE_LITTLEFS + #include + #define ESPEASY_FS LittleFS +#else + #define ESPEASY_FS SPIFFS +#endif // Include custom first, then build info. (one may want to set BUILD_GIT for example) #include "ESPEasy_buildinfo.h" @@ -106,7 +112,7 @@ String getUnknownString(); // #define FEATURE_MDNS #endif #if defined(ESP32) - #define FEATURE_ARDUINO_OTA + //#define FEATURE_ARDUINO_OTA //#define FEATURE_MDNS #endif diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index 3174b43da..de93e409c 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -32,48 +32,47 @@ #include -// Forward declaration to give access to global member variables -float & getUserVar(unsigned int varIndex); - - -struct ControllerSettingsStruct; -String getUnknownString(); -void scheduleNextDelayQueue(unsigned long id, - unsigned long nextTime); -String LoadControllerSettings(controllerIndex_t ControllerIndex, - ControllerSettingsStruct& controller_settings); void statusLED(bool traffic); void backgroundtasks(); uint32_t getCurrentFreeStack(); uint32_t getFreeStackWatermark(); + + +/* +struct ControllerSettingsStruct; +String getUnknownString(); +void scheduleNextDelayQueue(unsigned long id, + unsigned long nextTime); bool canYield(); +*/ + void serialHelper_getGpioNames(struct EventStruct *event, bool rxOptional = false, bool txOptional = false); - +/* fs::File tryOpenFile(const String& fname, const String& mode); +*/ + bool resolveHostByName(const char *aHostname, IPAddress & aResult); + bool connectClient(WiFiClient& client, const char *hostname, uint16_t port); + bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port); - -String getWifiModeString(WiFiMode_t wifimode); -bool WiFiConnected(uint32_t timeout_ms); -bool WiFiConnected(); bool useStaticIP(); +String getWifiModeString(WiFiMode_t wifimode); +bool NetworkConnected(uint32_t timeout_ms); +bool NetworkConnected(); bool hostReachable(const IPAddress& ip); bool hostReachable(const String& hostname); -void formatMAC(const uint8_t * mac, char (& strMAC)[20]); -String to_json_object_value(const String& object, - const String& value); bool I2C_read_bytes(uint8_t i2caddr, @@ -104,44 +103,35 @@ bool safe_strncpy(char *dest, size_t max_size); -void rulesProcessing(String& event); void setIntervalTimer(unsigned long id); +void rulesProcessing(String& event); void schedule_notification_event_timer(byte NotificationProtocolIndex, byte Function, struct EventStruct *event); #ifdef USES_MQTT // void runPeriodicalMQTT(); // void updateMQTTclient_connected(); -controllerIndex_t firstEnabledMQTT_ControllerIndex(); -// String getMQTT_state(); +//controllerIndex_t firstEnabledMQTT_ControllerIndex(); +String getMQTT_state(); void callback(char *c_topic, byte *b_payload, unsigned int length); -void MQTTDisconnect(); -bool MQTTConnect(controllerIndex_t controller_idx); +//void MQTTDisconnect(); +//bool MQTTConnect(controllerIndex_t controller_idx); bool MQTTCheck(controllerIndex_t controller_idx); -void schedule_all_tasks_using_MQTT_controller(); +//bool MQTT_queueFull(controllerIndex_t controller_idx); bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained); #endif // ifdef USES_MQTT +void flushAndDisconnectAllClients(); +bool saveUserVarToRTC(); // Used in src/Commands/* +void process_serialWriteBuffer(); void serialPrintln(const String& text); void serialPrintln(); -bool GetArgv(const char *string, String& argvString, unsigned int argc); -bool HasArgv(const char *string, unsigned int argc); -boolean str2ip(const String& string, byte *IP); -String formatIP(const IPAddress& ip); -String toString(float value, byte decimals); -String boolToString(bool value); -bool isInt(const String& tBuf); -unsigned long hexToUL(const String& input_c); -unsigned long hexToUL(const String& input_c, size_t nrHexDecimals); -unsigned long hexToUL(const String& input_c, size_t startpos, size_t nrHexDecimals); -String formatToHex(unsigned long value, const String& prefix); -String formatToHex(unsigned long value); -String formatToHex_decimal(unsigned long value); -String getNumerical(const String& tBuf, bool mustBeInteger); + + float getCPUload(); int getLoopCountPerSec(); @@ -150,7 +140,8 @@ void setLogLevelFor(byte destination, byte logLevel); uint16_t getPortFromKey(uint32_t key); void initRTC(); -void deepSleepStart(int dsdelay); +boolean saveToRTC(); + bool setControllerEnableStatus(controllerIndex_t controllerIndex, bool enabled); bool setTaskEnableStatus(taskIndex_t taskIndex, bool enabled); void taskClear(taskIndex_t taskIndex, bool save); @@ -161,20 +152,31 @@ String getControllerParameterInternalName(protocolIndex_t ProtocolIndex, Control void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettings, controllerIndex_t controllerindex, ControllerSettingsStruct::VarType varType); void saveControllerParameterForm(ControllerSettingsStruct& ControllerSettings, controllerIndex_t controllerindex, ControllerSettingsStruct::VarType varType); -String SaveToFile(SettingsType::Enum settingsType, int index, byte *memAddress, int datasize); -String SaveToFile(SettingsType::Enum settingsType, int index, byte *memAddress, int datasize, int posInBlock); -String LoadFromFile(SettingsType::Enum settingsType, int index, byte *memAddress, int datasize, int offset_in_block); -String LoadFromFile(SettingsType::Enum settingsType, int index, byte *memAddress, int datasize); -String ClearInFile(SettingsType::Enum settingsType, int index); -String LoadStringArray(SettingsType::Enum settingsType, int index, String strings[], uint16_t nrStrings, uint16_t maxStringLength); -String SaveStringArray(SettingsType::Enum settingsType, int index, const String strings[], uint16_t nrStrings, uint16_t maxStringLength); +void set_mDNS(); +bool allocatedOnStack(const void* address); + +uint32_t createKey(uint16_t pluginNumber, uint16_t portNumber); + +void sendGratuitousARP(); +bool processNextEvent(); +void rulesTimers(); +void delayedReboot(int rebootDelay); +void sendSysInfoUDP(byte repeats); +void refreshNodeList(); +void SSDP_update(); +String parseTemplate(String& tmpString); +String parseTemplate(String& tmpString, bool useURLencode); +void parseCommandString(struct EventStruct *event, const String& string); + +/* String parseString(const String& string, byte indexFind); String parseStringKeepCase(const String& string, byte indexFind); String parseStringToEnd(const String& string, byte indexFind); String parseStringToEndKeepCase(const String& string, byte indexFind); String tolerantParseStringKeepCase(const String& string, byte indexFind); +*/ int parseCommandArgumentInt(const String& string, unsigned int argc); taskIndex_t parseCommandArgumentTaskIndex(const String& string, unsigned int argc); @@ -183,37 +185,43 @@ String describeAllowedIPrange(); void clearAccessBlock(); String rulesProcessingFile(const String& fileName, String& event); int Calculate(const char *input, float* result); -bool SourceNeedsStatusUpdate(byte eventSource); +bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource); +void SendStatus(EventValueSource::Enum source, const String& status); +//bool ExecuteCommand(taskIndex_t taskIndex, EventValueSource::Enum source, const char *Line, bool tryPlugin, bool tryInternal, bool tryRemoteConfig); -void WifiScan(bool async, bool quick = false); -void WifiScan(); -void WiFiConnectRelaxed(); -void WifiDisconnect(); -void setAP(bool enable); -void setSTA(bool enable); +//void WifiScan(bool async, bool quick = false); +//void WifiScan(); +//void WifiDisconnect(); +//void setAP(bool enable); +//void setSTA(bool enable); + +// Used for Networking with Wifi or Ethernet +#include "ESPEasyEthWifi.h" +#include "ESPEasyNetwork.h" +//void WiFiConnectRelaxed(); +//bool WiFiConnected(); #include "src/Globals/ESPEasyWiFiEvent.h" -void setWifiMode(WiFiMode_t wifimode); +//void setWifiMode(WiFiMode_t wifimode); - -String SaveSettings(void); -String LoadSettings(); unsigned long FreeMem(void); void ResetFactory(); void reboot(); void SendUDPCommand(byte destUnit, const char *data, byte dataLength); +bool hasIPaddr(); -#include -void printDirectory(File dir, int numTabs); +//#include +//void printDirectory(File dir, int numTabs); void delayBackground(unsigned long dsdelay); -void setIntervalTimerOverride(unsigned long id, unsigned long msecFromNow); //implemented in Scheduler.ino +//implemented in Scheduler.ino +//void setIntervalTimerOverride(unsigned long id, unsigned long msecFromNow); +//void sendGratuitousARP_now(); byte PluginCall(byte Function, struct EventStruct *event, String& str); bool beginWiFiUDP_randomPort(WiFiUDP& udp); -String toString(float value, byte decimals); #endif // ESPEASY_FWD_DECL_H diff --git a/src/Misc.ino b/src/Misc.ino index 367a6c500..e80961819 100644 --- a/src/Misc.ino +++ b/src/Misc.ino @@ -1,7 +1,10 @@ +#include "ESPEasy_common.h" + #include "src/DataStructs/Caches.h" #include "src/DataStructs/NodeStruct.h" #include "src/DataStructs/PinMode.h" #include "src/DataStructs/RTCStruct.h" +#include "src/DataStructs/StorageLayout.h" #include "src/Globals/CRCValues.h" #include "src/Globals/Cache.h" @@ -12,6 +15,12 @@ #include "src/Globals/RTC.h" #include "src/Globals/ResetFactoryDefaultPref.h" #include "src/Globals/Services.h" +#include "src/Globals/Settings.h" + +#include "src/Helpers/Hardware.h" +#include "src/Helpers/Convert.h" + +#include "ESPEasyWifi.h" #include "Misc.h" @@ -143,14 +152,6 @@ String getResetReasonString() { #endif } -uint32_t getFlashRealSizeInBytes() { - #if defined(ESP32) - return ESP.getFlashChipSize(); - #else - return ESP.getFlashChipRealSize(); //ESP.getFlashChipSize(); - #endif -} - String getSystemBuildString() { String result; result += BUILD; @@ -338,127 +339,6 @@ bool allocatedOnStack(const void* address) { -/********************************************************** -* * -* Deep Sleep related functions * -* * -**********************************************************/ -int getDeepSleepMax() -{ - int dsmax = 4294; // About 71 minutes, limited by hardware - -#if defined(CORE_POST_2_5_0) - dsmax = INT_MAX; - - if ((ESP.deepSleepMax() / 1000000ULL) <= (uint64_t)INT_MAX) { - dsmax = (int)(ESP.deepSleepMax() / 1000000ULL); - } -#endif // if defined(CORE_POST_2_5_0) - return dsmax; -} - -bool isDeepSleepEnabled() -{ - if (!Settings.deepSleep_wakeTime) { - return false; - } - - // cancel deep sleep loop by pulling the pin GPIO16(D0) to GND - // recommended wiring: 3-pin-header with 1=RST, 2=D0, 3=GND - // short 1-2 for normal deep sleep / wakeup loop - // short 2-3 to cancel sleep loop for modifying settings - pinMode(16, INPUT_PULLUP); - - if (!digitalRead(16)) - { - return false; - } - return true; -} - -bool readyForSleep() -{ - if (!isDeepSleepEnabled()) { - return false; - } - - if (!WiFiConnected()) { - // Allow 12 seconds to establish connections - return timeOutReached(timerAwakeFromDeepSleep + 12000); - } - return timeOutReached(timerAwakeFromDeepSleep + 1000 * Settings.deepSleep_wakeTime); -} - -void prepare_deepSleep(int dsdelay) -{ - checkRAM(F("prepare_deepSleep")); - - if (!isDeepSleepEnabled()) - { - // Deep sleep canceled by GPIO16(D0)=LOW - return; - } - - // first time deep sleep? offer a way to escape - if (lastBootCause != BOOT_CAUSE_DEEP_SLEEP) - { - addLog(LOG_LEVEL_INFO, F("SLEEP: Entering deep sleep in 30 seconds.")); - - if (Settings.UseRules && isDeepSleepEnabled()) - { - eventQueue.add(F("System#NoSleep=30")); - while (processNextEvent()) { - delay(1); - } - } - delayBackground(30000); - - // disabled? - if (!isDeepSleepEnabled()) - { - addLog(LOG_LEVEL_INFO, F("SLEEP: Deep sleep cancelled (GPIO16 connected to GND)")); - return; - } - } - deepSleepStart(dsdelay); // Call deepSleepStart function after these checks -} - -void deepSleepStart(int dsdelay) -{ - // separate function that is called from above function or directly from rules, usign deepSleep_wakeTime as a one-shot - if (Settings.UseRules) - { - eventQueue.add(F("System#Sleep")); - while (processNextEvent()) { - delay(1); - } - } - - addLog(LOG_LEVEL_INFO, F("SLEEP: Powering down to deepsleep...")); - RTC.deepSleepState = 1; - prepareShutdown(); - - #if defined(ESP8266) - # if defined(CORE_POST_2_5_0) - uint64_t deepSleep_usec = dsdelay * 1000000ULL; - - if ((deepSleep_usec > ESP.deepSleepMax()) || (dsdelay < 0)) { - deepSleep_usec = ESP.deepSleepMax(); - } - ESP.deepSleepInstant(deepSleep_usec, WAKE_RF_DEFAULT); - # else // if defined(CORE_POST_2_5_0) - - if ((dsdelay > 4294) || (dsdelay < 0)) { - dsdelay = 4294; // max sleep time ~71 minutes - } - ESP.deepSleep((uint32_t)dsdelay * 1000000, WAKE_RF_DEFAULT); - # endif // if defined(CORE_POST_2_5_0) - #endif // if defined(ESP8266) - #if defined(ESP32) - esp_sleep_enable_timer_wakeup((uint32_t)dsdelay * 1000000); - esp_deep_sleep_start(); - #endif // if defined(ESP32) -} bool remoteConfig(struct EventStruct *event, const String& string) { @@ -793,7 +673,7 @@ void statusLED(bool traffic) else { - if (WiFiConnected()) + if (NetworkConnected()) { long int delta = timePassedSince(gnLastUpdate); if (delta>0 || delta<0 ) @@ -943,125 +823,6 @@ void taskClear(taskIndex_t taskIndex, bool save) } } -String checkTaskSettings(taskIndex_t taskIndex) { - String err = LoadTaskSettings(taskIndex); - if (err.length() > 0) return err; - if (!ExtraTaskSettings.checkUniqueValueNames()) { - return F("Use unique value names"); - } - if (!ExtraTaskSettings.checkInvalidCharInNames()) { - return F("Invalid character in names. Do not use ',#[]' or space."); - } - String deviceName = ExtraTaskSettings.TaskDeviceName; - if (deviceName.length() == 0) { - if (Settings.TaskDeviceEnabled[taskIndex]) { - // Decide what to do here, for now give a warning when task is enabled. - return F("Warning: Task Device Name is empty. It is adviced to give tasks an unique name"); - } - } - // Do not use the cached function findTaskIndexByName since that one does rely on the fact names should be unique. - for (taskIndex_t i = 0; i < TASKS_MAX; ++i) { - if (i != taskIndex && Settings.TaskDeviceEnabled[i]) { - LoadTaskSettings(i); - if (ExtraTaskSettings.TaskDeviceName[0] != 0) { - if (strcasecmp(ExtraTaskSettings.TaskDeviceName, deviceName.c_str()) == 0) { - err = F("Task Device Name is not unique, conflicts with task ID #"); - err += (i+1); -// return err; - } - } - } - } - - err += LoadTaskSettings(taskIndex); - return err; -} - - -/********************************************************************************************\ - Find positional parameter in a char string - \*********************************************************************************************/ - -bool HasArgv(const char *string, unsigned int argc) { - String argvString; - return GetArgv(string, argvString, argc); -} - -bool GetArgv(const char *string, String& argvString, unsigned int argc) { - int pos_begin, pos_end; - bool hasArgument = GetArgvBeginEnd(string, argc, pos_begin, pos_end); - argvString = ""; - if (!hasArgument) return false; - if (pos_begin >= 0 && pos_end >= 0 && pos_end > pos_begin) { - argvString.reserve(pos_end - pos_begin); - for (int i = pos_begin; i < pos_end; ++i) { - argvString += string[i]; - } - } - argvString.trim(); - argvString = stripQuotes(argvString); - return argvString.length() > 0; -} - -bool GetArgvBeginEnd(const char *string, const unsigned int argc, int& pos_begin, int& pos_end) { - pos_begin = -1; - pos_end = -1; - size_t string_len = strlen(string); - unsigned int string_pos = 0, argc_pos = 0; - bool parenthesis = false; - char matching_parenthesis = '"'; - - while (string_pos < string_len) - { - char c, d; // c = current char, d = next char (if available) - c = string[string_pos]; - d = 0; - - if ((string_pos + 1) < string_len) { - d = string[string_pos + 1]; - } - - if (!parenthesis && (c == ' ') && (d == ' ')) {} - else if (!parenthesis && (c == ' ') && (d == ',')) {} - else if (!parenthesis && (c == ',') && (d == ' ')) {} - else if (!parenthesis && (c == ' ') && (d >= 33) && (d <= 126)) {} - else if (!parenthesis && (c == ',') && (d >= 33) && (d <= 126)) {} - else - { - if (!parenthesis && (isQuoteChar(c) || (c == '['))) { - parenthesis = true; - matching_parenthesis = c; - - if (c == '[') { - matching_parenthesis = ']'; - } - } else if (parenthesis && (c == matching_parenthesis)) { - parenthesis = false; - } - - if (pos_begin == -1) { - pos_begin = string_pos; - pos_end = string_pos; - } - ++pos_end; - - if (!parenthesis && (isParameterSeparatorChar(d) || (d == 0))) // end of word - { - argc_pos++; - - if (argc_pos == argc) - { - return true; - } - pos_begin = -1; - pos_end = -1; - string_pos++; - } - } - string_pos++; - } - return false; -} @@ -1170,14 +931,14 @@ void ResetFactory() RTC.factoryResetCounter++; saveToRTC(); - //always format on factory reset, in case of corrupt SPIFFS - SPIFFS.end(); + //always format on factory reset, in case of corrupt FS + ESPEASY_FS.end(); serialPrintln(F("RESET: formatting...")); - SPIFFS.format(); + ESPEASY_FS.format(); serialPrintln(F("RESET: formatting done...")); - if (!SPIFFS.begin()) + if (!ESPEASY_FS.begin()) { - serialPrintln(F("RESET: FORMAT SPIFFS FAILED!")); + serialPrintln(F("RESET: FORMAT FS FAILED!")); return; } @@ -1191,7 +952,7 @@ void ResetFactory() fname=FILE_SECURITY; InitFile(fname.c_str(), 4096); - #ifndef NOTIFIER_SET_NONE + #ifdef USES_NOTIFIER fname=FILE_NOTIFICATION; InitFile(fname.c_str(), 4096); #endif @@ -1301,6 +1062,14 @@ void ResetFactory() Settings.UseSerial = DEFAULT_USE_SERIAL; Settings.BaudRate = DEFAULT_SERIAL_BAUD; + Settings.ETH_Phy_Addr = gpio_settings.eth_phyaddr; + Settings.ETH_Pin_mdc = gpio_settings.eth_mdc; + Settings.ETH_Pin_mdio = gpio_settings.eth_mdio; + Settings.ETH_Pin_power = gpio_settings.eth_power; + Settings.ETH_Phy_Type = gpio_settings.eth_phytype; + Settings.ETH_Clock_Mode = gpio_settings.eth_clock_mode; + Settings.ETH_Wifi_Mode = gpio_settings.eth_wifi_mode; + /* Settings.GlobalSync = DEFAULT_USE_GLOBAL_SYNC; @@ -1320,21 +1089,24 @@ void ResetFactory() addPredefinedRules(gpio_settings); #if DEFAULT_CONTROLLER - MakeControllerSettings(ControllerSettings); - safe_strncpy(ControllerSettings.Subscribe, F(DEFAULT_SUB), sizeof(ControllerSettings.Subscribe)); - safe_strncpy(ControllerSettings.Publish, F(DEFAULT_PUB), sizeof(ControllerSettings.Publish)); - safe_strncpy(ControllerSettings.MQTTLwtTopic, F(DEFAULT_MQTT_LWT_TOPIC), sizeof(ControllerSettings.MQTTLwtTopic)); - safe_strncpy(ControllerSettings.LWTMessageConnect, F(DEFAULT_MQTT_LWT_CONNECT_MESSAGE), sizeof(ControllerSettings.LWTMessageConnect)); - safe_strncpy(ControllerSettings.LWTMessageDisconnect, F(DEFAULT_MQTT_LWT_DISCONNECT_MESSAGE), sizeof(ControllerSettings.LWTMessageDisconnect)); - str2ip((char*)DEFAULT_SERVER, ControllerSettings.IP); - ControllerSettings.setHostname(F(DEFAULT_SERVER_HOST)); - ControllerSettings.UseDNS = DEFAULT_SERVER_USEDNS; - ControllerSettings.useExtendedCredentials(DEFAULT_USE_EXTD_CONTROLLER_CREDENTIALS); - ControllerSettings.Port = DEFAULT_PORT; - setControllerUser(0, ControllerSettings, F(DEFAULT_CONTROLLER_USER)); - setControllerPass(0, ControllerSettings, F(DEFAULT_CONTROLLER_PASS)); + { + // Place in a scope to have its memory freed ASAP + MakeControllerSettings(ControllerSettings); + safe_strncpy(ControllerSettings.Subscribe, F(DEFAULT_SUB), sizeof(ControllerSettings.Subscribe)); + safe_strncpy(ControllerSettings.Publish, F(DEFAULT_PUB), sizeof(ControllerSettings.Publish)); + safe_strncpy(ControllerSettings.MQTTLwtTopic, F(DEFAULT_MQTT_LWT_TOPIC), sizeof(ControllerSettings.MQTTLwtTopic)); + safe_strncpy(ControllerSettings.LWTMessageConnect, F(DEFAULT_MQTT_LWT_CONNECT_MESSAGE), sizeof(ControllerSettings.LWTMessageConnect)); + safe_strncpy(ControllerSettings.LWTMessageDisconnect, F(DEFAULT_MQTT_LWT_DISCONNECT_MESSAGE), sizeof(ControllerSettings.LWTMessageDisconnect)); + str2ip((char*)DEFAULT_SERVER, ControllerSettings.IP); + ControllerSettings.setHostname(F(DEFAULT_SERVER_HOST)); + ControllerSettings.UseDNS = DEFAULT_SERVER_USEDNS; + ControllerSettings.useExtendedCredentials(DEFAULT_USE_EXTD_CONTROLLER_CREDENTIALS); + ControllerSettings.Port = DEFAULT_PORT; + setControllerUser(0, ControllerSettings, F(DEFAULT_CONTROLLER_USER)); + setControllerPass(0, ControllerSettings, F(DEFAULT_CONTROLLER_PASS)); - SaveControllerSettings(0, ControllerSettings); + SaveControllerSettings(0, ControllerSettings); + } #endif SaveSettings(); @@ -1400,127 +1172,6 @@ unsigned long getMaxFreeBlock() -/********************************************************************************************\ - Check if string is valid float - \*********************************************************************************************/ -bool isFloat(const String& tBuf) { - return isNumerical(tBuf, false); -} - -bool isValidFloat(float f) { - if (f == NAN) return false; //("NaN"); - if (f == INFINITY) return false; //("INFINITY"); - if (-f == INFINITY)return false; //("-INFINITY"); - if (isnan(f)) return false; //("isnan"); - if (isinf(f)) return false; //("isinf"); - return true; -} - -bool isInt(const String& tBuf) { - return isNumerical(tBuf, true); -} - -bool validIntFromString(const String& tBuf, int& result) { - const String numerical = getNumerical(tBuf, true); - const bool isvalid = numerical.length() > 0; - if (isvalid) { - result = numerical.toInt(); - } - return isvalid; -} - -bool validUIntFromString(const String& tBuf, unsigned int& result) { - int tmp; - if (!validIntFromString(tBuf, tmp)) return false; - if (tmp < 0) return false; - result = static_cast(tmp); - return true; -} - - -bool validFloatFromString(const String& tBuf, float& result) { - // DO not call validDoubleFromString and then cast to float. - // Working with double values is quite CPU intensive as it must be done in software - // since the ESP does not have large enough registers for handling double values in hardware. - const String numerical = getNumerical(tBuf, false); - const bool isvalid = numerical.length() > 0; - if (isvalid) { - result = numerical.toFloat(); - } - return isvalid; -} - -bool validDoubleFromString(const String& tBuf, double& result) { - #ifdef CORE_POST_2_5_0 - // String.toDouble() is introduced in core 2.5.0 - const String numerical = getNumerical(tBuf, false); - const bool isvalid = numerical.length() > 0; - if (isvalid) { - result = numerical.toDouble(); - } - return isvalid; - #else - float tmp = static_cast(result); - bool res = validFloatFromString(tBuf, tmp); - result = static_cast(tmp); - return res; - #endif -} - - -String getNumerical(const String& tBuf, bool mustBeInteger) { - String result = ""; - const unsigned int bufLength = tBuf.length(); - unsigned int firstDec = 0; - while (firstDec < bufLength && tBuf.charAt(firstDec) == ' ') { - ++firstDec; - } - if (firstDec >= bufLength) return result; - - bool decPt = false; - - char c = tBuf.charAt(firstDec); - if(c == '+' || c == '-') { - result += c; - ++firstDec; - } - for(unsigned int x=firstDec; x < bufLength; ++x) { - c = tBuf.charAt(x); - if(c == '.') { - if (mustBeInteger) return result; - // Only one decimal point allowed - if(decPt) return result; - else decPt = true; - } - else if(c < '0' || c > '9') return result; - result += c; - } - return result; -} - -bool isNumerical(const String& tBuf, bool mustBeInteger) { - const unsigned int bufLength = tBuf.length(); - unsigned int firstDec = 0; - while (firstDec < bufLength && tBuf.charAt(firstDec) == ' ') { - ++firstDec; - } - if (firstDec >= bufLength) return false; - bool decPt = false; - char c = tBuf.charAt(firstDec); - if(c == '+' || c == '-') - ++firstDec; - for(unsigned int x=firstDec; x < bufLength; ++x) { - c = tBuf.charAt(x); - if(c == '.') { - if (mustBeInteger) return false; - // Only one decimal point allowed - if(decPt) return false; - else decPt = true; - } - else if(c < '0' || c > '9') return false; - } - return true; -} void logtimeStringToSeconds(const String& tBuf, int hours, int minutes, int seconds) { @@ -1594,22 +1245,6 @@ bool timeStringToSeconds(const String& tBuf, int& time_seconds) { return true; } -/********************************************************************************************\ - Clean up all before going to sleep or reboot. - \*********************************************************************************************/ -void prepareShutdown() -{ -#ifdef USES_MQTT - runPeriodicalMQTT(); // Flush outstanding MQTT messages -#endif // USES_MQTT - process_serialWriteBuffer(); - flushAndDisconnectAllClients(); - saveUserVarToRTC(); - SPIFFS.end(); - delay(100); // give the node time to flush all before reboot or sleep - node_time.now(); - saveToRTC(); -} /********************************************************************************************\ Delayed reboot, in case of issues, do not reboot with high frequency as it might not help... @@ -1978,6 +1613,23 @@ void transformValue( { case 'V': //value = value without transformations break; + case 'p': // Password hide using asterisks or custom character: pc + { + char maskChar = '*'; + if (tempValueFormatLength > 1) + { + maskChar = tempValueFormat[1]; + } + if (value == F("0")) { + value = ""; + } else { + const int valueLength = value.length(); + for (int i = 0; i < valueLength; i++) { + value[i] = maskChar; + } + } + } + break; case 'O': value = logicVal == 0 ? F("OFF") : F(" ON"); //(equivalent to XOR operator) break; @@ -2830,7 +2482,7 @@ void ArduinoOTAInit() ArduinoOTA.onStart([]() { serialPrintln(F("OTA : Start upload")); ArduinoOTAtriggered = true; - SPIFFS.end(); //important, otherwise it fails + ESPEASY_FS.end(); //important, otherwise it fails }); ArduinoOTA.onEnd([]() { @@ -2910,21 +2562,6 @@ uint32_t calc_CRC32(const uint8_t *data, size_t length) { } -// Compute the dew point temperature, given temperature and humidity (temp in Celcius) -// Formula: http://www.ajdesigner.com/phphumidity/dewpoint_equation_dewpoint_temperature.php -// Td = (f/100)^(1/8) * (112 + 0.9*T) + 0.1*T - 112 -float compute_dew_point_temp(float temperature, float humidity_percentage) { - return pow(humidity_percentage / 100.0, 0.125) * - (112.0 + 0.9*temperature) + 0.1*temperature - 112.0; -} - -// Compute the humidity given temperature and dew point temperature (temp in Celcius) -// Formula: http://www.ajdesigner.com/phphumidity/dewpoint_equation_relative_humidity.php -// f = 100 * ((112 - 0.1*T + Td) / (112 + 0.9 * T))^8 -float compute_humidity_from_dewpoint(float temperature, float dew_temperature) { - return 100.0 * pow((112.0 - 0.1 * temperature + dew_temperature) / - (112.0 + 0.9 * temperature), 8); -} /********************************************************** * * diff --git a/src/Modbus_RTU.ino b/src/Modbus_RTU.ino deleted file mode 100644 index b56aca5d1..000000000 --- a/src/Modbus_RTU.ino +++ /dev/null @@ -1,834 +0,0 @@ -// FIXME TD-er: No idea why, but in this file you cannot use the F() macro. (core 2.4.1) - -#ifdef USES_MODBUS -#include -#include -#include -#include -#include "ESPEasy_fdwdecl.h" -#include "ESPEasy_common.h" - -#define MODBUS_RECEIVE_BUFFER 256 -#define MODBUS_BROADCAST_ADDRESS 0xFE - -#define MODBUS_READ_HOLDING_REGISTERS 0x03 -#define MODBUS_READ_INPUT_REGISTERS 0x04 -#define MODBUS_WRITE_SINGLE_REGISTER 0x06 -#define MODBUS_WRITE_MULTIPLE_REGISTERS 0x10 - -#define MODBUS_CMD_READ_RAM 0x44 -#define MODBUS_CMD_READ_EEPROM 0x46 -#define MODBUS_CMD_WRITE_RAM 0x41 -#define MODBUS_CMD_WRITE_EEPROM 0x43 - - -#define MODBUS_EXCEPTION_ILLEGAL_FUNCTION 1 -#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS 2 -#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE 3 -#define MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE 4 -#define MODBUS_EXCEPTION_ACKNOWLEDGE 5 -#define MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY 6 -#define MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE 7 -#define MODBUS_EXCEPTION_MEMORY_PARITY 8 -#define MODBUS_EXCEPTION_NOT_DEFINED 9 -#define MODBUS_EXCEPTION_GATEWAY_PATH 10 -#define MODBUS_EXCEPTION_GATEWAY_TARGET 11 - -/* Additional error codes for the processCommand return values */ -#define MODBUS_BADCRC (MODBUS_EXCEPTION_GATEWAY_TARGET + 1) -#define MODBUS_BADDATA (MODBUS_EXCEPTION_GATEWAY_TARGET + 2) -#define MODBUS_BADEXC (MODBUS_EXCEPTION_GATEWAY_TARGET + 3) -#define MODBUS_UNKEXC (MODBUS_EXCEPTION_GATEWAY_TARGET + 4) -#define MODBUS_MDATA (MODBUS_EXCEPTION_GATEWAY_TARGET + 5) -#define MODBUS_BADSLAVE (MODBUS_EXCEPTION_GATEWAY_TARGET + 6) -#define MODBUS_TIMEOUT (MODBUS_EXCEPTION_GATEWAY_TARGET + 7) -#define MODBUS_NODATA (MODBUS_EXCEPTION_GATEWAY_TARGET + 8) - - -struct ModbusRTU_struct { - ModbusRTU_struct() : easySerial(nullptr) {} - - ~ModbusRTU_struct() { - reset(); - } - - void reset() { - if (easySerial != nullptr) { - delete easySerial; - easySerial = nullptr; - } - detected_device_description = ""; - - for (int i = 0; i < 8; ++i) { - _sendframe[i] = 0; - } - _sendframe_used = 0; - - for (int i = 0; i < MODBUS_RECEIVE_BUFFER; ++i) { - _recv_buf[i] = 0xff; - } - _recv_buf_used = 0; - _modbus_address = MODBUS_BROADCAST_ADDRESS; - _reads_pass = 0; - _reads_crc_failed = 0; - _reads_nodata = 0; - } - - bool init(const int16_t serial_rx, const int16_t serial_tx, int16_t baudrate, byte address) { - return init(serial_rx, serial_tx, baudrate, address, -1); - } - - bool init(const int16_t serial_rx, const int16_t serial_tx, int16_t baudrate, byte address, int8_t dere_pin) { - if ((serial_rx < 0) || (serial_tx < 0)) { - return false; - } - reset(); - easySerial = new ESPeasySerial(serial_rx, serial_tx); - easySerial->begin(baudrate); - - if (!isInitialized()) { return false; } - _modbus_address = address; - _dere_pin = dere_pin; - - if (_dere_pin != -1) { // set output pin mode for DE/RE pin when used (for control MAX485) - pinMode(_dere_pin, OUTPUT); - } - - detected_device_description = getDevice_description(_modbus_address); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; // = F("Modbus detected: "); - log += detected_device_description; - addLog(LOG_LEVEL_INFO, log); - modbus_log_MEI(_modbus_address); - } - return true; - } - - bool isInitialized() const { - return easySerial != nullptr; - } - - void getStatistics(uint32_t& pass, uint32_t& fail, uint32_t& nodata) { - pass = _reads_pass; - fail = _reads_crc_failed; - nodata = _reads_nodata; - } - - void setModbusTimeout(uint16_t timeout) { - _modbus_timeout = timeout; - } - - uint16_t getModbusTimeout() const { - return _modbus_timeout; - } - - String getDevice_description(byte slaveAddress) { - bool more_follows = true; - byte next_object_id = 0; - byte conformity_level = 0; - unsigned int object_value_int; - String description; - String obj_text; - - for (byte object_id = 0; object_id < 0x84; ++object_id) { - if (object_id == 6) { - object_id = 0x82; // Skip to the serialnr/sensor type - } - int result = modbus_get_MEI(slaveAddress, object_id, obj_text, - object_value_int, next_object_id, - more_follows, conformity_level); - String label; - - switch (object_id) { - case 0x01: - - if (result == 0) { label = "Pcode"; } - break; - case 0x02: - - if (result == 0) { label = "Rev"; } - break; - case 0x82: - { - if (result != 0) { - uint32_t sensorId = readSensorId(); - obj_text = String(sensorId, HEX); - result = 0; - } - - if (result == 0) { label = "S/N"; } - break; - } - case 0x83: - { - if (result != 0) { - uint32_t sensorId = readTypeId(); - obj_text = String(sensorId, HEX); - result = 0; - } - - if (result == 0) { label = "Type"; } - break; - } - default: - break; - } - - if (result == 0) { - if (label.length() > 0) { - // description += MEI_objectid_to_name(object_id); - description += label; - description += ": "; - } - - if (obj_text.length() > 0) { - description += obj_text; - description += " - "; - } - } - } - return description; - } - - // Read from RAM or EEPROM - void buildRead_RAM_EEPROM(byte slaveAddress, byte functionCode, - short startAddress, byte number_bytes) { - _sendframe[0] = slaveAddress; - _sendframe[1] = functionCode; - _sendframe[2] = (byte)(startAddress >> 8); - _sendframe[3] = (byte)(startAddress & 0xFF); - _sendframe[4] = number_bytes; - _sendframe_used = 5; - } - - // Write to the Special Control Register (SCR) - void buildWriteCommandRegister(byte slaveAddress, byte value) { - _sendframe[0] = slaveAddress; - _sendframe[1] = MODBUS_CMD_WRITE_RAM; - _sendframe[2] = 0; // Address-Hi SCR (0x0060) - _sendframe[3] = 0x60; // Address-Lo SCR - _sendframe[4] = 1; // Count - _sendframe[5] = value; - _sendframe_used = 6; - } - - void buildWriteMult16bRegister(byte slaveAddress, uint16_t startAddress, uint16_t value) { - _sendframe[0] = slaveAddress; - _sendframe[1] = MODBUS_WRITE_MULTIPLE_REGISTERS; - _sendframe[2] = (byte)(startAddress >> 8); - _sendframe[3] = (byte)(startAddress & 0xFF); - _sendframe[4] = 0; // nr reg hi - _sendframe[5] = 1; // nr reg lo - _sendframe[6] = 2; // nr bytes to follow (2 bytes per register) - _sendframe[7] = (byte)(value >> 8); - _sendframe[8] = (byte)(value & 0xFF); - _sendframe_used = 9; - } - - void buildFrame(byte slaveAddress, byte functionCode, - short startAddress, short parameter) { - _sendframe[0] = slaveAddress; - _sendframe[1] = functionCode; - _sendframe[2] = (byte)(startAddress >> 8); - _sendframe[3] = (byte)(startAddress & 0xFF); - _sendframe[4] = (byte)(parameter >> 8); - _sendframe[5] = (byte)(parameter & 0xFF); - _sendframe_used = 6; - } - - void build_modbus_MEI_frame(byte slaveAddress, byte device_id, - byte object_id) { - _sendframe[0] = slaveAddress; - _sendframe[1] = 0x2B; - _sendframe[2] = 0x0E; - - // The parameter "Read Device ID code" allows to define four access types : - // 01: request to get the basic device identification (stream access) - // 02: request to get the regular device identification (stream access) - // 03: request to get the extended device identification (stream access) - // 04: request to get one specific identification object (individual access) - _sendframe[3] = device_id; - _sendframe[4] = object_id; - _sendframe_used = 5; - } - - String MEI_objectid_to_name(byte object_id) { - String result; - - switch (object_id) { - case 0: result = "VendorName"; break; - case 1: result = "ProductCode"; break; - case 2: result = "MajorMinorRevision"; break; - case 3: result = "VendorUrl"; break; - case 4: result = "ProductName"; break; - case 5: result = "ModelName"; break; - case 6: result = "UserApplicationName"; break; - case 0x80: result = "MemoryMapVersion"; break; - case 0x81: result = "Firmware Rev."; break; - case 0x82: result = "Sensor S/N"; break; - case 0x83: result = "Sensor type"; break; - default: - result = formatToHex(object_id); - break; - } - return result; - } - - String parse_modbus_MEI_response(unsigned int& object_value_int, - byte & next_object_id, - bool & more_follows, - byte & conformity_level) { - String result; - - if (_recv_buf_used < 8) { - // Too small. - addLog(LOG_LEVEL_INFO, - String("MEI response too small: ") + _recv_buf_used); - next_object_id = 0xFF; - more_follows = false; - return result; - } - int pos = 4; // Data skipped: slave_address, FunctionCode, MEI type, ReadDevId - // See http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf - // Page 45 - conformity_level = _recv_buf[pos++]; - more_follows = _recv_buf[pos++] != 0; - next_object_id = _recv_buf[pos++]; - const byte number_objects = _recv_buf[pos++]; - byte object_id = 0; - - for (int i = 0; i < number_objects; ++i) { - if ((pos + 3) < _recv_buf_used) { - object_id = _recv_buf[pos++]; - const byte object_length = _recv_buf[pos++]; - - if ((pos + object_length) < _recv_buf_used) { - String object_value; - - if (object_id < 0x80) { - // Parse as type String - object_value.reserve(object_length); - object_value_int = static_cast(-1); - - for (int c = 0; c < object_length; ++c) { - object_value += char(_recv_buf[pos++]); - } - } else { - object_value.reserve(2 * object_length + 2); - object_value_int = 0; - - for (int c = 0; c < object_length; ++c) { - object_value_int = - object_value_int << 8 | _recv_buf[pos++]; - } - object_value += formatToHex(object_value_int); - } - - if (i != 0) { - // Append to existing description - result += ", "; - } - result += object_value; - } - } - } - return result; - } - - void logModbusException(byte value) { - if (value == 0) { - return; - } - - /* - // Exception Response, see: - // http://digital.ni.com/public.nsf/allkb/E40CA0CFA0029B2286256A9900758E06?OpenDocument - String log = F("Modbus Exception - "); - switch (value) { - case MODBUS_EXCEPTION_ILLEGAL_FUNCTION: { - // The function code received in the query is not an allowable action for - // the slave. - // If a Poll Program Complete command was issued, this code indicates that - // no program function preceded it. - log += F("Illegal Function (not allowed by client)"); - break; - } - case MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS: { - // The data address received in the query is not an allowable address for - // the slave. - log += F("Illegal Data Address"); - break; - } - case MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE: { - // A value contained in the query data field is not an allowable value for - // the slave - log += F("Illegal Data Value"); - break; - } - case MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE: { - // An unrecoverable error occurred while the slave was attempting to perform - // the requested action - log += F("Slave Device Failure"); - break; - } - case MODBUS_EXCEPTION_ACKNOWLEDGE: { - // The slave has accepted the request and is processing it, but a long - // duration of time will be - // required to do so. This response is returned to prevent a timeout error - // from occurring in the master. - // The master can next issue a Poll Program Complete message to determine if - // processing is completed. - log += F("Acknowledge"); - break; // Is this an error? - } - case MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY: { - // The slave is engaged in processing a long-duration program command. - // The master should retransmit the message later when the slave is free. - log += F("Slave Device Busy"); - break; - } - case MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE: - log += F("Negative acknowledge"); - break; - case MODBUS_EXCEPTION_MEMORY_PARITY: - log += F("Memory parity error"); - break; - case MODBUS_EXCEPTION_GATEWAY_PATH: - log += F("Gateway path unavailable"); - break; - case MODBUS_EXCEPTION_GATEWAY_TARGET: - log += F("Target device failed to respond"); - break; - case MODBUS_BADCRC: - log += F("Invalid CRC"); - break; - case MODBUS_BADDATA: - log += F("Invalid data"); - break; - case MODBUS_BADEXC: - log += F("Invalid exception code"); - break; - case MODBUS_MDATA: - log += F("Too many data"); - break; - case MODBUS_BADSLAVE: - log += F("Response not from requested slave"); - break; - case MODBUS_TIMEOUT: - log += F("Modbus Timeout"); - break; - case MODBUS_NODATA: - log += F("Modbus No Data"); - break; - default: - log += String(F("Unknown Exception code: ")) + value; - break; - } - log += F(" - sent: "); - log += log_buffer(_sendframe, _sendframe_used); - log += F(" - received: "); - log += log_buffer(_recv_buf, _recv_buf_used); - addLog(LOG_LEVEL_DEBUG_MORE, log); - */ - } - - /* - String log_buffer(byte *buffer, int length) { - String log; - log.reserve(3 * length + 5); - for (int i = 0; i < length; ++i) { - String hexvalue(buffer[i], HEX); - hexvalue.toUpperCase(); - log += hexvalue; - log += F(" "); - } - log += F("("); - log += length; - log += F(")"); - return log; - } - */ - byte processCommand() { - // CRC-calculation - unsigned int crc = - ModRTU_CRC(_sendframe, _sendframe_used); - - // Note, this number has low and high bytes swapped, so use it accordingly (or - // swap bytes) - byte checksumHi = (byte)((crc >> 8) & 0xFF); - byte checksumLo = (byte)(crc & 0xFF); - - _sendframe[_sendframe_used++] = checksumLo; - _sendframe[_sendframe_used++] = checksumHi; - - int nrRetriesLeft = 2; - byte return_value = 0; - - while (nrRetriesLeft > 0) { - return_value = 0; - - // Send the byte array - startWrite(); - easySerial->write(_sendframe, _sendframe_used); - - // sent all data from buffer - easySerial->flush(); - startRead(); - - // Read answer from sensor - _recv_buf_used = 0; - unsigned long timeout = millis() + _modbus_timeout; - bool validPacket = false; - bool invalidDueToTimeout = false; - - // idx: 0, 1, 2, 3, 4, 5, 6, 7 - // send: 0x02,0x03,0x00,0x00,0x00,0x01,0x39,0x84 - // recv: 0x02,0x03,0x02,0x01,0x57,0xBC,0x2A - - while (!validPacket && !invalidDueToTimeout && _recv_buf_used < MODBUS_RECEIVE_BUFFER) { - if (timeOutReached(timeout)) { - invalidDueToTimeout = true; - } - - while (!invalidDueToTimeout && easySerial->available() && _recv_buf_used < MODBUS_RECEIVE_BUFFER) { - if (timeOutReached(timeout)) { - invalidDueToTimeout = true; - } - _recv_buf[_recv_buf_used++] = easySerial->read(); - } - - if (_recv_buf_used > 2) { // got length - if (_recv_buf_used >= (3 + _recv_buf[2] + 2)) { // got whole pkt - crc = ModRTU_CRC(_recv_buf, _recv_buf_used); // crc16 is 0 for whole valid pkt - validPacket = (crc == 0) && (_recv_buf[0] == _sendframe[0]); // check crc and address - return_value = 0; // reset return value - } - } - delay(0); - } - - // Check for MODBUS exception - if (invalidDueToTimeout) { - ++_reads_nodata; - - if (_recv_buf_used == 0) { - return_value = MODBUS_NODATA; - } else { - return_value = MODBUS_TIMEOUT; - } - } else if (!validPacket) { - ++_reads_crc_failed; - return_value = MODBUS_BADCRC; - } else { - const byte received_functionCode = _recv_buf[1]; - - if ((received_functionCode & 0x80) != 0) { - return_value = _recv_buf[2]; - } - ++_reads_pass; - _reads_nodata = 0; - } - - switch (return_value) { - case MODBUS_EXCEPTION_ACKNOWLEDGE: - case MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY: - case MODBUS_BADCRC: - case MODBUS_TIMEOUT: - - // Bad communication, makes sense to retry. - break; - default: - nrRetriesLeft = 0; // When not supported, does not make sense to retry. - break; - } - --nrRetriesLeft; - } - _last_error = return_value; - return return_value; - } - - uint32_t read_32b_InputRegister(short address) { - uint32_t result = 0; - byte errorcode; - int idHigh = readInputRegister(address, errorcode); - - if (errorcode != 0) { return result; } - int idLow = readInputRegister(address + 1, errorcode); - - if (errorcode == 0) { - result = idHigh; - result = result << 16; - result += idLow; - } - return result; - } - - uint32_t read_32b_HoldingRegister(short address) { - uint32_t result = 0; - - process_32b_register(_modbus_address, MODBUS_READ_HOLDING_REGISTERS, address, result); - return result; - } - - float read_float_HoldingRegister(short address) { - union { - uint32_t ival; - float fval; - } conversion; - - conversion.ival = read_32b_HoldingRegister(address); - return conversion.fval; - - // uint32_t ival = read_32b_HoldingRegister(address); - // float fval = *reinterpret_cast(&ival); - // return fval; - } - - int readInputRegister(short address, byte& errorcode) { - // Only read 1 register - return process_16b_register(_modbus_address, MODBUS_READ_INPUT_REGISTERS, address, 1, errorcode); - } - - int readHoldingRegister(short address, byte& errorcode) { - // Only read 1 register - return process_16b_register( - _modbus_address, MODBUS_READ_HOLDING_REGISTERS, address, 1, errorcode); - } - - // Write to holding register. - int writeSingleRegister(short address, short value) { - // No check for the specific error code. - byte errorcode = 0; - - return writeSingleRegister(address, value, errorcode); - } - - int writeSingleRegister(short address, short value, byte& errorcode) { - // GN: Untested, will probably not work - return process_16b_register( - _modbus_address, MODBUS_WRITE_SINGLE_REGISTER, address, value, errorcode); - } - - // Function 16 (0x10) "Write Multiple Registers" to write to a single holding register - int writeMultipleRegisters(short address, short value) { - return preset_mult16b_register( - _modbus_address, address, value); - } - - byte modbus_get_MEI(byte slaveAddress, byte object_id, - String& result, unsigned int& object_value_int, - byte& next_object_id, bool& more_follows, - byte& conformity_level) { - // Force device_id to 4 = individual access (reading one ID object per call) - build_modbus_MEI_frame(slaveAddress, 4, object_id); - const byte process_result = processCommand(); - - if (process_result == 0) { - result = parse_modbus_MEI_response(object_value_int, - next_object_id, more_follows, - conformity_level); - } else { - more_follows = false; - } - return process_result; - } - - void modbus_log_MEI(byte slaveAddress) { - // Iterate over all Device identification items, using - // Modbus command (0x2B / 0x0E) Read Device Identification - // And add to log. - bool more_follows = true; - byte conformity_level = 0; - byte object_id = 0; - byte next_object_id = 0; - - while (more_follows) { - String result; - unsigned int object_value_int; - const byte process_result = modbus_get_MEI( - slaveAddress, object_id, result, object_value_int, next_object_id, - more_follows, conformity_level); - - if (process_result == 0) { - if (result.length() > 0) { - String log = MEI_objectid_to_name(object_id); - log += ": "; - log += result; - addLog(LOG_LEVEL_INFO, log); - } - } else { - switch (process_result) { - case MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS: - - // No need to log this exception when scanning. - break; - default: - logModbusException(process_result); - break; - } - } - - // If more parts are needed, collect them or iterate over the known list. - // For example with "individual access" a new request has to be sent for each single item - if (more_follows) { - object_id = next_object_id; - } else if (object_id < 0x84) { - // Allow for scanning only the usual object ID's - // This range is vendor specific - more_follows = true; - object_id++; - - if (object_id == 7) { - // Skip range 0x07...0x7F - object_id = 0x80; - } - } - } - } - - int process_16b_register(byte slaveAddress, byte functionCode, - short startAddress, short parameter, - byte& errorcode) { - buildFrame(slaveAddress, functionCode, startAddress, parameter); - errorcode = processCommand(); - - if (errorcode == 0) { - return (_recv_buf[3] << 8) | (_recv_buf[4]); - } - logModbusException(errorcode); - return -1; - } - - // Still writing single register, but calling it using "Preset Multiple Registers" function (FC=16) - int preset_mult16b_register(byte slaveAddress, uint16_t startAddress, uint16_t value) { - buildWriteMult16bRegister(slaveAddress, startAddress, value); - const byte process_result = processCommand(); - - if (process_result == 0) { - return (_recv_buf[4] << 8) | (_recv_buf[5]); - } - logModbusException(process_result); - return -1 * process_result; - } - - bool process_32b_register(byte slaveAddress, byte functionCode, - short startAddress, uint32_t& result) { - buildFrame(slaveAddress, functionCode, startAddress, 2); - const byte process_result = processCommand(); - - if (process_result == 0) { - result = 0; - - for (byte i = 0; i < 4; ++i) { - result = result << 8; - result += _recv_buf[i + 3]; - } - return true; - } - logModbusException(process_result); - return false; - } - - int writeSpecialCommandRegister(byte command) { - buildWriteCommandRegister(_modbus_address, command); - const byte process_result = processCommand(); - - if (process_result == 0) { - return 0; - } - logModbusException(process_result); - return -1 * process_result; - } - - unsigned int read_RAM_EEPROM(byte command, byte startAddress, - byte nrBytes, - byte& errorcode) { - buildRead_RAM_EEPROM(_modbus_address, command, - startAddress, nrBytes); - errorcode = processCommand(); - - if (errorcode == 0) { - unsigned int result = 0; - - for (int i = 0; i < _recv_buf[2]; ++i) { - // Most significant byte at lower address - result = (result << 8) | _recv_buf[i + 3]; - } - return result; - } - logModbusException(errorcode); - return 0; - } - - // Compute the MODBUS RTU CRC - unsigned int ModRTU_CRC(byte *buf, int len) { - unsigned int crc = 0xFFFF; - - for (int pos = 0; pos < len; pos++) { - crc ^= (unsigned int)buf[pos]; // XOR byte into least sig. byte of crc - - for (int i = 8; i != 0; i--) { // Loop over each bit - if ((crc & 0x0001) != 0) { // If the LSB is set - crc >>= 1; // Shift right and XOR 0xA001 - crc ^= 0xA001; - } else { // Else LSB is not set - crc >>= 1; // Just shift right - } - } - } - return crc; - } - - uint32_t readTypeId() { - return read_32b_InputRegister(25); - } - - uint32_t readSensorId() { - return read_32b_InputRegister(29); - } - - uint8_t getLastError() { - return _last_error; - } - - uint32_t getFailedReadsSinceLastValid() { - return _reads_nodata; - } - - String detected_device_description; - -private: - - void startWrite() { - // transmit to device -> DE Enable, /RE Disable (for control MAX485) - if ((_dere_pin == -1) || !isInitialized()) { return; } - digitalWrite(_dere_pin, HIGH); - delay(2); // Switching may take some time - } - - void startRead() { - if (!isInitialized()) { return; } - easySerial->flush(); // clear out tx buffer - - // receive from device -> DE Disable, /RE Enable (for control MAX485) - if (_dere_pin != -1) { - digitalWrite(_dere_pin, LOW); - } - } - - byte _sendframe[12] = { 0 }; - byte _sendframe_used = 0; - byte _recv_buf[MODBUS_RECEIVE_BUFFER] = { 0xff }; - byte _recv_buf_used = 0; - byte _modbus_address = MODBUS_BROADCAST_ADDRESS; - int8_t _dere_pin = -1; - uint32_t _reads_pass = 0; - uint32_t _reads_crc_failed = 0; - uint32_t _reads_nodata = 0; // This will be reset as soon as a valid packet has been received. - uint16_t _modbus_timeout = 180; - uint8_t _last_error = 0; - - ESPeasySerial *easySerial; -}; -#endif // USES_MODBUS diff --git a/src/Networking.ino b/src/Networking.ino index 8301f192d..0fe7f0f52 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -1,3 +1,4 @@ +#include "src/Commands/InternalCommands.h" #include "src/Globals/Nodes.h" #include "src/Globals/ESPEasyWiFiEvent.h" @@ -59,12 +60,10 @@ void etharp_gratuitous_r(struct netif *netif) { \*********************************************************************************************/ void syslog(byte logLevel, const char *message) { - if ((Settings.Syslog_IP[0] != 0) && WiFiConnected()) + if ((Settings.Syslog_IP[0] != 0) && NetworkConnected()) { IPAddress broadcastIP(Settings.Syslog_IP[0], Settings.Syslog_IP[1], Settings.Syslog_IP[2], Settings.Syslog_IP[3]); portUDP.beginPacket(broadcastIP, 514); - char str[256]; - str[0] = 0; byte prio = Settings.SyslogFacility * 8; if (logLevel == LOG_LEVEL_ERROR) { @@ -80,16 +79,30 @@ void syslog(byte logLevel, const char *message) // An RFC3164 compliant message must be formated like : "[TimeStamp ]Hostname TaskName: Message" // Using Settings.Name as the Hostname (Hostname must NOT content space) - snprintf_P(str, sizeof(str), PSTR("<%u>%s EspEasy: %s"), prio, Settings.Name, message); - - // Using Setting.Unit to build a Hostname - // snprintf_P(str, sizeof(str), PSTR("<7>EspEasy_%u ESP: %s"), Settings.Unit, message); - #if defined(ESP8266) - portUDP.write(str); - #endif // if defined(ESP8266) - #if defined(ESP32) - portUDP.write((uint8_t *)str, strlen(str)); - #endif // if defined(ESP32) + { + String header; + String hostname = Settings.Name; + hostname.trim(); + hostname.replace(' ', '_'); + header.reserve(16 + hostname.length()); + char str[8] = {0}; + snprintf_P(str, sizeof(str), PSTR("<%u>"), prio); + header = str; + header += hostname; + header += F(" EspEasy: "); + #ifdef ESP8266 + portUDP.write(header.c_str(), header.length()); + #endif + #ifdef ESP32 + portUDP.write((uint8_t *)header.c_str(), header.length()); + #endif + } + #ifdef ESP8266 + portUDP.write(message, strlen(message)); + #endif + #ifdef ESP32 + portUDP.write((uint8_t *)message, strlen(message)); + #endif portUDP.endPacket(); } } @@ -139,7 +152,7 @@ void checkUDP() { packetBuffer[len] = 0; addLog(LOG_LEVEL_DEBUG, &packetBuffer[0]); - ExecuteCommand_all(VALUE_SOURCE_SYSTEM, &packetBuffer[0]); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0]); } else { @@ -229,7 +242,7 @@ void checkUDP() \*********************************************************************************************/ void SendUDPCommand(byte destUnit, const char *data, byte dataLength) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } @@ -253,7 +266,7 @@ void SendUDPCommand(byte destUnit, const char *data, byte dataLength) \*********************************************************************************************/ void sendUDP(byte unit, const byte *data, byte size) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } @@ -328,7 +341,7 @@ void refreshNodeList() \*********************************************************************************************/ void sendSysInfoUDP(byte repeats) { - if ((Settings.UDPPort == 0) || !WiFiConnected(10)) { + if ((Settings.UDPPort == 0) || !NetworkConnected(10)) { return; } @@ -350,7 +363,8 @@ void sendSysInfoUDP(byte repeats) for (byte counter = 0; counter < repeats; counter++) { uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = WiFi.macAddress(mac); + uint8_t *macread = NetworkMacAddressAsBytes(mac); + byte data[80]; data[0] = 255; data[1] = 1; @@ -358,8 +372,9 @@ void sendSysInfoUDP(byte repeats) for (byte x = 0; x < 6; x++) { data[x + 2] = macread[x]; } - IPAddress ip = WiFi.localIP(); - + + IPAddress ip = NetworkLocalIP(); + for (byte x = 0; x < 4; x++) { data[x + 8] = ip[x]; } @@ -388,7 +403,7 @@ void sendSysInfoUDP(byte repeats) if (it != Nodes.end()) { - IPAddress ip = WiFi.localIP(); + IPAddress ip = NetworkLocalIP(); for (byte x = 0; x < 4; x++) { it->second.ip[x] = ip[x]; @@ -407,11 +422,11 @@ void sendSysInfoUDP(byte repeats) Respond to HTTP XML requests for SSDP information \*********************************************************************************************/ void SSDP_schema(WiFiClient& client) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } - const IPAddress ip = WiFi.localIP(); + const IPAddress ip = NetworkLocalIP(); const uint32_t chipId = ESP.getChipId(); char uuid[64]; sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"), @@ -503,7 +518,7 @@ bool SSDP_begin() { _server->ref(); ip_addr_t ifaddr; - ifaddr.addr = WiFi.localIP(); + ifaddr.addr = NetworkLocalIP(); ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t)SSDP_MULTICAST_ADDR; @@ -549,7 +564,7 @@ bool SSDP_begin() { Send SSDP messages (notify & responses) \*********************************************************************************************/ void SSDP_send(byte method) { - uint32_t ip = WiFi.localIP(); + uint32_t ip = NetworkLocalIP(); // FIXME TD-er: Why create String objects of these flashstrings? String _ssdp_response_template = F( @@ -568,7 +583,7 @@ void SSDP_send(byte method) { "CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL "SERVER: Arduino/1.0 UPNP/1.1 ESPEasy/%u\r\n" // _modelNumber "USN: uuid:%s\r\n" // _uuid - "LOCATION: http://%u.%u.%u.%u:80/ssdp.xml\r\n" // WiFi.localIP(), + "LOCATION: http://%u.%u.%u.%u:80/ssdp.xml\r\n" // NetworkLocalIP(), "\r\n"); { char uuid[64] = { 0 }; @@ -758,8 +773,10 @@ bool getSubnetRange(IPAddress& low, IPAddress& high) if (wifiStatus < ESPEASY_WIFI_GOT_IP) { return false; } - const IPAddress ip = WiFi.localIP(); - const IPAddress subnet = WiFi.subnetMask(); + + const IPAddress ip = NetworkLocalIP(); + const IPAddress subnet = NetworkSubnetMask(); + low = ip; high = ip; @@ -803,8 +820,8 @@ bool hasIPaddr() { #endif // ifdef CORE_POST_2_5_0 } -// Check WiFi connection. Maximum timeout 500 msec. -bool WiFiConnected(uint32_t timeout_ms) { +// Check connection. Maximum timeout 500 msec. +bool NetworkConnected(uint32_t timeout_ms) { uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms); uint32_t min_delay = timeout_ms / 20; @@ -814,7 +831,7 @@ bool WiFiConnected(uint32_t timeout_ms) { } // Apparently something needs network, perform check to see if it is ready now. - while (!WiFiConnected()) { + while (!NetworkConnected()) { if (timeOutReached(timer)) { return false; } @@ -824,7 +841,7 @@ bool WiFiConnected(uint32_t timeout_ms) { } bool hostReachable(const IPAddress& ip) { - if (!WiFiConnected()) { return false; } + if (!NetworkConnected()) { return false; } return true; // Disabled ping as requested here: // https://github.com/letscontrolit/ESPEasy/issues/1494#issuecomment-397872538 @@ -870,9 +887,12 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port) { START_TIMER; - if (!WiFiConnected()) { + if (!NetworkConnected()) { return false; } + // In case of domain name resolution error result can be negative. + // https://github.com/esp8266/Arduino/blob/18f643c7e2d6a0da9d26ff2b14c94e6536ab78c1/libraries/Ethernet/src/Dns.cpp#L44 + // Thus must match the result with 1. bool connected = (client.connect(ip, port) == 1); yield(); @@ -893,7 +913,7 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port) bool resolveHostByName(const char *aHostname, IPAddress& aResult) { START_TIMER; - if (!WiFiConnected()) { + if (!NetworkConnected()) { return false; } #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) @@ -925,7 +945,7 @@ bool hostReachable(const String& hostname) { // Create a random port for the UDP connection. // Return true when successful. bool beginWiFiUDP_randomPort(WiFiUDP& udp) { - if (!WiFiConnected()) { + if (!NetworkConnected()) { return false; } unsigned int attempts = 3; @@ -942,7 +962,7 @@ bool beginWiFiUDP_randomPort(WiFiUDP& udp) { } void sendGratuitousARP() { - if (!WiFiConnected()) { + if (!NetworkConnected()) { return; } #ifdef SUPPORT_ARP @@ -1081,7 +1101,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const } long len = http.getSize(); - File f = SPIFFS.open(file_save, "w"); + File f = ESPEASY_FS.open(file_save, "w"); if (f) { uint8_t buff[128]; diff --git a/src/Serial.ino b/src/Serial.ino index 1f1f2c676..ab9219eef 100644 --- a/src/Serial.ino +++ b/src/Serial.ino @@ -1,3 +1,5 @@ +#include "src/Commands/InternalCommands.h" + /********************************************************************************************\ * Get data from Serial Interface \*********************************************************************************************/ @@ -35,7 +37,7 @@ void serial() InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed Serial.write('>'); serialPrintln(InputBuffer_Serial); - ExecuteCommand_all(VALUE_SOURCE_SERIAL, InputBuffer_Serial); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SERIAL, InputBuffer_Serial); SerialInByteCounter = 0; InputBuffer_Serial[0] = 0; // serial data processed, clear buffer } diff --git a/src/StringConverter.ino b/src/StringConverter.ino deleted file mode 100644 index 7718b5b93..000000000 --- a/src/StringConverter.ino +++ /dev/null @@ -1,755 +0,0 @@ -#include "src/Globals/CRCValues.h" -#include "src/Globals/Device.h" -#include "src/Globals/ESPEasy_time.h" -#include "src/Globals/ESPEasyWiFiEvent.h" -#include "src/Globals/MQTT.h" -#include "src/Globals/Plugins.h" - -#include "src/Helpers/StringConverter.h" -#include "src/Helpers/SystemVariables.h" - -//-V::569 - -/********************************************************************************************\ - Convert a char string to integer - \*********************************************************************************************/ - -// FIXME: change original code so it uses String and String.toInt() -unsigned long str2int(const char *string) -{ - unsigned long temp = atof(string); - - return temp; -} - -/********************************************************************************************\ - Check if valid float and convert string to float. - \*********************************************************************************************/ -bool string2float(const String& string, float& floatvalue) { - return validFloatFromString(string, floatvalue); -} - -/********************************************************************************************\ - Convert a char string to IP byte array - \*********************************************************************************************/ -boolean str2ip(const String& string, byte *IP) { - return str2ip(string.c_str(), IP); -} - -boolean str2ip(const char *string, byte *IP) -{ - IPAddress tmpip; // Default constructor => set to 0.0.0.0 - - if ((*string == 0) || tmpip.fromString(string)) { - // Eiher empty string or a valid IP addres, so copy value. - for (byte i = 0; i < 4; ++i) { - IP[i] = tmpip[i]; - } - return true; - } - return false; -} - -String formatIP(const IPAddress& ip) { -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) - IPAddress tmp(ip); - return tmp.toString(); -#else // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) - return ip.toString(); -#endif // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) -} - -void formatMAC(const uint8_t *mac, char (& strMAC)[20]) { - sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - ZERO_TERMINATE(strMAC); -} - -String formatMAC(const uint8_t *mac) { - char str[20] = { 0 }; - - formatMAC(mac, str); - return String(str); -} - - -/********************************************************************************************\ - Handling HEX strings - \*********************************************************************************************/ - -// Convert max. 8 hex decimals to unsigned long -unsigned long hexToUL(const String& input_c, size_t nrHexDecimals) { - size_t nr_decimals = nrHexDecimals; - if (nr_decimals > 8) { - nr_decimals = 8; - } - size_t inputLength = input_c.length(); - if (nr_decimals > inputLength) { - nr_decimals = inputLength; - } - String tmp = input_c.substring(0, nr_decimals); - return strtoul(tmp.c_str(), 0, 16); -} - -unsigned long hexToUL(const String& input_c) { - return hexToUL(input_c, input_c.length()); -} - -unsigned long hexToUL(const String& input_c, size_t startpos, size_t nrHexDecimals) { - return hexToUL(input_c.substring(startpos, startpos + nrHexDecimals), nrHexDecimals); -} - - -String formatToHex(unsigned long value, const String& prefix) { - String result = prefix; - String hex(value, HEX); - - hex.toUpperCase(); - result += hex; - return result; -} - -String formatToHex(unsigned long value) { - return formatToHex(value, F("0x")); -} - -String formatHumanReadable(unsigned long value, unsigned long factor) { - String result = formatHumanReadable(value, factor, 2); - - result.replace(F(".00"), ""); - return result; -} - -String formatHumanReadable(unsigned long value, unsigned long factor, int NrDecimals) { - float floatValue(value); - byte steps = 0; - - while (value >= factor) { - value /= factor; - ++steps; - floatValue /= float(factor); - } - String result = toString(floatValue, NrDecimals); - - switch (steps) { - case 0: return String(value); - case 1: result += 'k'; break; - case 2: result += 'M'; break; - case 3: result += 'G'; break; - case 4: result += 'T'; break; - default: - result += '*'; - result += factor; - result += '^'; - result += steps; - break; - } - return result; -} - -String formatToHex_decimal(unsigned long value) { - return formatToHex_decimal(value, 1); -} - -String formatToHex_decimal(unsigned long value, unsigned long factor) { - String result = formatToHex(value); - - result += " ("; - - if (factor > 1) { - result += formatHumanReadable(value, factor); - } else { - result += value; - } - result += ')'; - return result; -} - -/*********************************************************************************************\ - Workaround for removing trailing white space when String() converts a float with 0 decimals -\*********************************************************************************************/ -String toString(float value, byte decimals) -{ - String sValue = String(value, decimals); - - sValue.trim(); - return sValue; -} - -String toString(WiFiMode_t mode) -{ - String result = F("Undefined"); - - switch (mode) - { - case WIFI_OFF: - result = F("Off"); - break; - case WIFI_STA: - result = F("STA"); - break; - case WIFI_AP: - result = F("AP"); - break; - case WIFI_AP_STA: - result = F("AP+STA"); - break; - default: - break; - } - return result; -} - -String boolToString(bool value) { - return value ? F("true") : F("false"); -} - -/*********************************************************************************************\ - Typical string replace functions. -\*********************************************************************************************/ -void removeExtraNewLine(String& line) { - while (line.endsWith("\r\n\r\n")) { - line.remove(line.length() - 2); - } -} - -void addNewLine(String& line) { - line += "\r\n"; -} - -/*********************************************************************************************\ - Format a value to the set number of decimals -\*********************************************************************************************/ -String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck, bool& isvalid) { - isvalid = true; - - const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); - if (!validDeviceIndex(DeviceIndex)) { - isvalid = false; - return "0"; - } - - if (Device[DeviceIndex].ValueCount <= rel_index) { - isvalid = false; - - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log = F("No sensor value for TaskIndex: "); - log += event->TaskIndex; - log += F(" varnumber: "); - log += rel_index; - addLog(LOG_LEVEL_ERROR, log); - } - return ""; - } - const byte BaseVarIndex = event->TaskIndex * VARS_PER_TASK; - - switch (Device[DeviceIndex].VType) { - case SENSOR_TYPE_LONG: - return String((unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16)); - case SENSOR_TYPE_STRING: - return event->String2; - - default: - break; - } - - float f(UserVar[BaseVarIndex + rel_index]); - - if (mustCheck && !isValidFloat(f)) { - isvalid = false; -#ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("Invalid float value for TaskIndex: "); - log += event->TaskIndex; - log += F(" varnumber: "); - log += rel_index; - addLog(LOG_LEVEL_DEBUG, log); - } -#endif // ifndef BUILD_NO_DEBUG - f = 0; - } - LoadTaskSettings(event->TaskIndex); - String result = toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]); - result.trim(); - return result; -} - -String formatUserVarNoCheck(taskIndex_t TaskIndex, byte rel_index) { - bool isvalid; - - // FIXME TD-er: calls to this function cannot handle SENSOR_TYPE_STRING - struct EventStruct TempEvent; - - TempEvent.TaskIndex = TaskIndex; - return doFormatUserVar(&TempEvent, rel_index, false, isvalid); -} - -String formatUserVar(taskIndex_t TaskIndex, byte rel_index, bool& isvalid) { - // FIXME TD-er: calls to this function cannot handle SENSOR_TYPE_STRING - struct EventStruct TempEvent; - - TempEvent.TaskIndex = TaskIndex; - return doFormatUserVar(&TempEvent, rel_index, true, isvalid); -} - -String formatUserVarNoCheck(struct EventStruct *event, byte rel_index) -{ - bool isvalid; - - return doFormatUserVar(event, rel_index, false, isvalid); -} - -String formatUserVar(struct EventStruct *event, byte rel_index, bool& isvalid) -{ - return doFormatUserVar(event, rel_index, true, isvalid); -} - -/*********************************************************************************************\ - Wrap a string with given pre- and postfix string. -\*********************************************************************************************/ -void wrap_String(const String& string, const String& wrap, String& result) { - result += wrap; - result += string; - result += wrap; -} - -/*********************************************************************************************\ - Format an object value pair for use in JSON. -\*********************************************************************************************/ -String to_json_object_value(const String& object, const String& value) { - String result; - - result.reserve(object.length() + value.length() + 6); - wrap_String(object, "\"", result); - result += F(":"); - - if (value.length() == 0) { - // Empty string - result += F("\"\""); - } else if (!isFloat(value)) { - // Is not a numerical value, thus wrap with quotes - if ((value.indexOf('\n') != -1) || (value.indexOf('\r') != -1) || (value.indexOf('"') != -1)) { - // Must replace characters, so make a deepcopy - String tmpValue(value); - tmpValue.replace('\n', '^'); - tmpValue.replace('\r', '^'); - tmpValue.replace('"', '\''); - wrap_String(tmpValue, "\"", result); - } else { - wrap_String(value, "\"", result); - } - } else { - // It is a numerical - result += value; - } - return result; -} - -/*********************************************************************************************\ - Strip wrapping chars (e.g. quotes) -\*********************************************************************************************/ -String stripWrappingChar(const String& text, char wrappingChar) { - unsigned int length = text.length(); - - if ((length >= 2) && stringWrappedWithChar(text, wrappingChar)) { - return text.substring(1, length - 1); - } - return text; -} - -bool stringWrappedWithChar(const String& text, char wrappingChar) { - unsigned int length = text.length(); - - if (length < 2) { return false; } - - if (text.charAt(0) != wrappingChar) { return false; } - return text.charAt(length - 1) == wrappingChar; -} - -bool isQuoteChar(char c) { - return c == '\'' || c == '"' || c == '`'; -} - -bool isParameterSeparatorChar(char c) { - return c == ',' || c == ' '; -} - -String stripQuotes(const String& text) { - if (text.length() >= 2) { - char c = text.charAt(0); - - if (isQuoteChar(c)) { - return stripWrappingChar(text, c); - } - } - return text; -} - -bool safe_strncpy(char *dest, const String& source, size_t max_size) { - return safe_strncpy(dest, source.c_str(), max_size); -} - -bool safe_strncpy(char *dest, const char *source, size_t max_size) { - if (max_size < 1) { return false; } - - if (dest == NULL) { return false; } - - if (source == NULL) { return false; } - bool result = true; - memset(dest, 0, max_size); - size_t str_length = strlen(source); - - if (str_length >= max_size) { - str_length = max_size; - result = false; - } - strncpy(dest, source, str_length); - dest[max_size - 1] = 0; - return result; -} - -// Convert a string to lower case and replace spaces with underscores. -String to_internal_string(const String& input, char replaceSpace) { - String result = input; - - result.trim(); - result.toLowerCase(); - result.replace(' ', replaceSpace); - return result; -} - -/*********************************************************************************************\ - Parse a string and get the xth command or parameter - IndexFind = 1 => command. - // FIXME TD-er: parseString* should use index starting at 0. -\*********************************************************************************************/ -String parseString(const String& string, byte indexFind) { - String result = parseStringKeepCase(string, indexFind); - result.toLowerCase(); - return result; -} - -String parseStringKeepCase(const String& string, byte indexFind) { - String result; - if (!GetArgv(string.c_str(), result, indexFind)) { - return ""; - } - result.trim(); - return stripQuotes(result); -} - -String parseStringToEnd(const String& string, byte indexFind) { - String result = parseStringToEndKeepCase(string, indexFind); - result.toLowerCase(); - return result; -} - -String parseStringToEndKeepCase(const String& string, byte indexFind) { - // Loop over the arguments to find the first and last pos of the arguments. - int pos_begin = string.length(); - int pos_end = pos_begin; - int tmppos_begin, tmppos_end = -1; - byte nextArgument = indexFind; - bool hasArgument = false; - while (GetArgvBeginEnd(string.c_str(), nextArgument, tmppos_begin, tmppos_end)) - { - hasArgument = true; - if ((tmppos_begin < pos_begin) && (tmppos_begin >= 0)) { - pos_begin = tmppos_begin; - } - if ((tmppos_end >= 0)) { - pos_end = tmppos_end; - } - ++nextArgument; - } - if (!hasArgument || (pos_begin < 0)) { - return ""; - } - String result = string.substring(pos_begin, pos_end); - result.trim(); - return stripQuotes(result); -} - -String tolerantParseStringKeepCase(const String& string, byte indexFind) -{ - if (Settings.TolerantLastArgParse()) { - return parseStringToEndKeepCase(string, indexFind); - } - return parseStringKeepCase(string, indexFind); -} - -// escapes special characters in strings for use in html-forms -bool htmlEscapeChar(char c, String& escaped) -{ - switch (c) - { - case '&': escaped = F("&"); return true; - case '\"': escaped = F("""); return true; - case '\'': escaped = F("'"); return true; - case '<': escaped = F("<"); return true; - case '>': escaped = F(">"); return true; - case '/': escaped = F("/"); return true; - } - return false; -} - -void htmlEscape(String& html, char c) -{ - String repl; - if (htmlEscapeChar(c, repl)) { - html.replace(String(c), repl); - } -} - -void htmlEscape(String& html) -{ - htmlEscape(html, '&'); - htmlEscape(html, '\"'); - htmlEscape(html, '\''); - htmlEscape(html, '<'); - htmlEscape(html, '>'); - htmlEscape(html, '/'); -} - -void htmlStrongEscape(String& html) -{ - String escaped; - - escaped.reserve(html.length()); - - for (unsigned i = 0; i < html.length(); ++i) - { - if (((html[i] >= 'a') && (html[i] <= 'z')) || ((html[i] >= 'A') && (html[i] <= 'Z')) || ((html[i] >= '0') && (html[i] <= '9'))) - { - escaped += html[i]; - } - else - { - char s[4]; - sprintf(s, "%03d", static_cast(html[i])); - escaped += "&#"; - escaped += s; - escaped += ";"; - } - } - html = escaped; -} - - - - - -void parseSpecialCharacters(String& s, boolean useURLencode) -{ - bool no_accolades = s.indexOf('{') == -1 || s.indexOf('}') == -1; - bool no_html_entity = s.indexOf('&') == -1 || s.indexOf(';') == -1; - - if (no_accolades && no_html_entity) { - return; // Nothing to replace - } - { - // Degree - const char degree[3] = { 0xc2, 0xb0, 0 }; // Unicode degree symbol - const char degreeC[4] = { 0xe2, 0x84, 0x83, 0 }; // Unicode degreeC symbol - const char degree_C[4] = { 0xc2, 0xb0, 'C', 0 }; // Unicode degree symbol + captial C - repl(F("{D}"), degree, s, useURLencode); - repl(F("°"), degree, s, useURLencode); - repl(degreeC, degree_C, s, useURLencode); - } - { - // Angle quotes - const char laquo[3] = { 0xc2, 0xab, 0 }; // Unicode left angle quotes symbol - const char raquo[3] = { 0xc2, 0xbb, 0 }; // Unicode right angle quotes symbol - repl(F("{<<}"), laquo, s, useURLencode); - repl(F("«"), laquo, s, useURLencode); - repl(F("{>>}"), raquo, s, useURLencode); - repl(F("»"), raquo, s, useURLencode); - } - { - // Greek letter Mu - const char mu[3] = { 0xc2, 0xb5, 0 }; // Unicode greek letter mu - repl(F("{u}"), mu, s, useURLencode); - repl(F("µ"), mu, s, useURLencode); - } - { - // Currency - const char euro[4] = { 0xe2, 0x82, 0xac, 0 }; // Unicode euro symbol - const char yen[3] = { 0xc2, 0xa5, 0 }; // Unicode yen symbol - const char pound[3] = { 0xc2, 0xa3, 0 }; // Unicode pound symbol - const char cent[3] = { 0xc2, 0xa2, 0 }; // Unicode cent symbol - repl(F("{E}"), euro, s, useURLencode); - repl(F("€"), euro, s, useURLencode); - repl(F("{Y}"), yen, s, useURLencode); - repl(F("¥"), yen, s, useURLencode); - repl(F("{P}"), pound, s, useURLencode); - repl(F("£"), pound, s, useURLencode); - repl(F("{c}"), cent, s, useURLencode); - repl(F("¢"), cent, s, useURLencode); - } - { - // Math symbols - const char sup1[3] = { 0xc2, 0xb9, 0 }; // Unicode sup1 symbol - const char sup2[3] = { 0xc2, 0xb2, 0 }; // Unicode sup2 symbol - const char sup3[3] = { 0xc2, 0xb3, 0 }; // Unicode sup3 symbol - const char frac14[3] = { 0xc2, 0xbc, 0 }; // Unicode frac14 symbol - const char frac12[3] = { 0xc2, 0xbd, 0 }; // Unicode frac12 symbol - const char frac34[3] = { 0xc2, 0xbe, 0 }; // Unicode frac34 symbol - const char plusmn[3] = { 0xc2, 0xb1, 0 }; // Unicode plusmn symbol - const char times[3] = { 0xc3, 0x97, 0 }; // Unicode times symbol - const char divide[3] = { 0xc3, 0xb7, 0 }; // Unicode divide symbol - repl(F("{^1}"), sup1, s, useURLencode); - repl(F("¹"), sup1, s, useURLencode); - repl(F("{^2}"), sup2, s, useURLencode); - repl(F("²"), sup2, s, useURLencode); - repl(F("{^3}"), sup3, s, useURLencode); - repl(F("³"), sup3, s, useURLencode); - repl(F("{1_4}"), frac14, s, useURLencode); - repl(F("¼"), frac14, s, useURLencode); - repl(F("{1_2}"), frac12, s, useURLencode); - repl(F("½"), frac12, s, useURLencode); - repl(F("{3_4}"), frac34, s, useURLencode); - repl(F("¾"), frac34, s, useURLencode); - repl(F("{+-}"), plusmn, s, useURLencode); - repl(F("±"), plusmn, s, useURLencode); - repl(F("{x}"), times, s, useURLencode); - repl(F("×"), times, s, useURLencode); - repl(F("{..}"), divide, s, useURLencode); - repl(F("÷"), divide, s, useURLencode); - } -} - - -/********************************************************************************************\ - replace other system variables like %sysname%, %systime%, %ip% - \*********************************************************************************************/ -void parseControllerVariables(String& s, struct EventStruct *event, boolean useURLencode) { - s = parseTemplate(s, useURLencode); - parseEventVariables(s, event, useURLencode); -} - - -// Simple macro to create the replacement string only when needed. -#define SMART_REPL(T, S) \ - if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode); } -void parseSystemVariables(String& s, boolean useURLencode) -{ - parseSpecialCharacters(s, useURLencode); - - SystemVariables::parseSystemVariables(s, useURLencode); -} - -void parseEventVariables(String& s, struct EventStruct *event, boolean useURLencode) -{ - // These replacements use ExtraTaskSettings, so make sure the correct TaskIndex is set in the event. - LoadTaskSettings(event->TaskIndex); - SMART_REPL(F("%id%"), String(event->idx)) - - if (s.indexOf(F("%val")) != -1) { - if (event->sensorType == SENSOR_TYPE_LONG) { - SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16))) - } else { - SMART_REPL(F("%val1%"), formatUserVarNoCheck(event, 0)) - SMART_REPL(F("%val2%"), formatUserVarNoCheck(event, 1)) - SMART_REPL(F("%val3%"), formatUserVarNoCheck(event, 2)) - SMART_REPL(F("%val4%"), formatUserVarNoCheck(event, 3)) - } - } - LoadTaskSettings(event->TaskIndex); - repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode); - - if (s.indexOf(F("%vname")) != -1) { - repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode); - repl(F("%vname2%"), ExtraTaskSettings.TaskDeviceValueNames[1], s, useURLencode); - repl(F("%vname3%"), ExtraTaskSettings.TaskDeviceValueNames[2], s, useURLencode); - repl(F("%vname4%"), ExtraTaskSettings.TaskDeviceValueNames[3], s, useURLencode); - } -} - -#undef SMART_REPL - -bool getConvertArgument(const String& marker, const String& s, float& argument, int& startIndex, int& endIndex) { - String argumentString; - - if (getConvertArgumentString(marker, s, argumentString, startIndex, endIndex)) { - if (!isFloat(argumentString)) { return false; } - argument = argumentString.toFloat(); - return true; - } - return false; -} - -bool getConvertArgument2(const String& marker, const String& s, float& arg1, float& arg2, int& startIndex, int& endIndex) { - String argumentString; - - if (getConvertArgumentString(marker, s, argumentString, startIndex, endIndex)) { - int pos_comma = argumentString.indexOf(','); - - if (pos_comma == -1) { return false; } - String arg1_s = argumentString.substring(0, pos_comma); - - if (!isFloat(arg1_s)) { return false; } - String arg2_s = argumentString.substring(pos_comma + 1); - - if (!isFloat(arg2_s)) { return false; } - arg1 = arg1_s.toFloat(); - arg2 = arg2_s.toFloat(); - return true; - } - return false; -} - -bool getConvertArgumentString(const String& marker, const String& s, String& argumentString, int& startIndex, int& endIndex) { - startIndex = s.indexOf(marker); - - if (startIndex == -1) { return false; } - - int startIndexArgument = startIndex + marker.length(); - - if (s.charAt(startIndexArgument) != '(') { - return false; - } - ++startIndexArgument; - endIndex = s.indexOf(')', startIndexArgument); - - if (endIndex == -1) { return false; } - - argumentString = s.substring(startIndexArgument, endIndex); - - if (argumentString.length() == 0) { return false; } - ++endIndex; // Must also strip ')' from the original string. - return true; -} - -// Parse conversions marked with "%conv_marker%(float)" -// Must be called last, since all sensor values must be converted, processed, etc. -void parseStandardConversions(String& s, boolean useURLencode) { - if (s.indexOf(F("%c_")) == -1) { - return; // Nothing to replace - } - float arg1 = 0.0; - int startIndex = 0; - int endIndex = 0; - - // These replacements should be done in a while loop per marker, - // since they also replace the numerical parameter. - // The marker may occur more than once per string, but with different parameters. - #define SMART_CONV(T, FUN) \ - while (getConvertArgument((T), s, arg1, startIndex, endIndex)) { repl(s.substring(startIndex, endIndex), (FUN), s, useURLencode); } - SMART_CONV(F("%c_w_dir%"), getBearing(arg1)) - SMART_CONV(F("%c_c2f%"), toString(CelsiusToFahrenheit(arg1), 2)) - SMART_CONV(F("%c_ms2Bft%"), String(m_secToBeaufort(arg1))) - SMART_CONV(F("%c_cm2imp%"), centimeterToImperialLength(arg1)) - SMART_CONV(F("%c_mm2imp%"), millimeterToImperialLength(arg1)) - SMART_CONV(F("%c_m2day%"), toString(minutesToDay(arg1), 2)) - SMART_CONV(F("%c_m2dh%"), minutesToDayHour(arg1)) - SMART_CONV(F("%c_m2dhm%"), minutesToDayHourMinute(arg1)) - SMART_CONV(F("%c_s2dhms%"), secondsToDayHourMinuteSecond(arg1)) - #undef SMART_CONV - - // Conversions with 2 parameters - #define SMART_CONV(T, FUN) \ - while (getConvertArgument2((T), s, arg1, arg2, startIndex, endIndex)) { repl(s.substring(startIndex, endIndex), (FUN), s, useURLencode); } - float arg2 = 0.0; - SMART_CONV(F("%c_dew_th%"), toString(compute_dew_point_temp(arg1, arg2), 2)) - #undef SMART_CONV -} diff --git a/src/StringProvider.ino b/src/StringProvider.ino index 53b10179c..4817a82a0 100644 --- a/src/StringProvider.ino +++ b/src/StringProvider.ino @@ -1,6 +1,11 @@ #include "StringProviderTypes.h" +#include "ESPEasyNetwork.h" +#ifdef HAS_ETHERNET +#include "ETH.h" +#endif #include "src/Helpers/CompiletimeDefines.h" +#include "src/Helpers/Scheduler.h" String getInternalLabel(LabelType::Enum label, char replaceSpace) { return to_internal_string(getLabel(label), replaceSpace); @@ -96,11 +101,30 @@ String getLabel(LabelType::Enum label) { case LabelType::FLASH_WRITE_COUNT: return F("Flash Writes"); case LabelType::SKETCH_SIZE: return F("Sketch Size"); case LabelType::SKETCH_FREE: return F("Sketch Free"); - case LabelType::SPIFFS_SIZE: return F("SPIFFS Size"); - case LabelType::SPIFFS_FREE: return F("SPIFFS Free"); + #ifdef USE_LITTLEFS + case LabelType::FS_SIZE: return F("Little FS Size"); + case LabelType::FS_FREE: return F("Little FS Free"); + #else + case LabelType::FS_SIZE: return F("SPIFFS Size"); + case LabelType::FS_FREE: return F("SPIFFS Free"); + #endif case LabelType::MAX_OTA_SKETCH_SIZE: return F("Max. OTA Sketch Size"); case LabelType::OTA_2STEP: return F("OTA 2-step Needed"); case LabelType::OTA_POSSIBLE: return F("OTA possible"); +#ifdef HAS_ETHERNET + case LabelType::ETH_IP_ADDRESS: return F("Eth IP Address"); + case LabelType::ETH_IP_SUBNET: return F("Eth IP Subnet"); + case LabelType::ETH_IP_ADDRESS_SUBNET: return F("Eth IP / Subnet"); + case LabelType::ETH_IP_GATEWAY: return F("Eth Gateway"); + case LabelType::ETH_IP_DNS: return F("Eth DNS"); + case LabelType::ETH_MAC: return F("Eth MAC"); + case LabelType::ETH_DUPLEX: return F("Eth Mode"); + case LabelType::ETH_SPEED: return F("Eth Speed"); + case LabelType::ETH_STATE: return F("Eth State"); + case LabelType::ETH_SPEED_STATE: return F("Eth Speed State"); + case LabelType::ETH_WIFI_MODE: return F("Eth Wifi Mode"); + case LabelType::ETH_CONNECTED: return F("Eth connected"); +#endif } return F("MissingString"); @@ -113,12 +137,8 @@ String getValue(LabelType::Enum label) { { case LabelType::UNIT_NR: return String(Settings.Unit); case LabelType::UNIT_NAME: return String(Settings.Name); // Only return the set name, no appended unit. - case LabelType::HOST_NAME: - #ifdef ESP32 - return WiFi.getHostname(); - #else - return WiFi.hostname(); - #endif + case LabelType::HOST_NAME: return NetworkGetHostname(); + case LabelType::LOCAL_TIME: return node_time.getDateTimeString('-',':',' '); case LabelType::UPTIME: return String(wdcounter / 2); @@ -144,20 +164,21 @@ String getValue(LabelType::Enum label) { case LabelType::IP_CONFIG: return useStaticIP() ? getLabel(LabelType::IP_CONFIG_STATIC) : getLabel(LabelType::IP_CONFIG_DYNAMIC); case LabelType::IP_CONFIG_STATIC: break; case LabelType::IP_CONFIG_DYNAMIC: break; - case LabelType::IP_ADDRESS: return WiFi.localIP().toString(); - case LabelType::IP_SUBNET: return WiFi.subnetMask().toString(); + case LabelType::IP_ADDRESS: return NetworkLocalIP().toString(); + case LabelType::IP_SUBNET: return NetworkSubnetMask().toString(); case LabelType::IP_ADDRESS_SUBNET: return String(getValue(LabelType::IP_ADDRESS) + F(" / ") + getValue(LabelType::IP_SUBNET)); - case LabelType::GATEWAY: return WiFi.gatewayIP().toString(); + case LabelType::GATEWAY: return NetworkGatewayIP().toString(); case LabelType::CLIENT_IP: return formatIP(web_server.client().remoteIP()); + #ifdef FEATURE_MDNS - case LabelType::M_DNS: return String(WifiGetHostname()) + F(".local"); + case LabelType::M_DNS: return String(NetworkGetHostname()) + F(".local"); #endif case LabelType::DNS: return String(getValue(LabelType::DNS_1) + F(" / ") + getValue(LabelType::DNS_2)); - case LabelType::DNS_1: return WiFi.dnsIP(0).toString(); - case LabelType::DNS_2: return WiFi.dnsIP(1).toString(); + case LabelType::DNS_1: return NetworkDnsIP(0).toString(); + case LabelType::DNS_2: return NetworkDnsIP(1).toString(); case LabelType::ALLOWED_IP_RANGE: return describeAllowedIPrange(); - case LabelType::STA_MAC: return WiFi.macAddress(); - case LabelType::AP_MAC: break; + case LabelType::STA_MAC: return NetworkMacAddress(); + case LabelType::AP_MAC: return WifiSoftAPmacAddress(); case LabelType::SSID: return WiFi.SSID(); case LabelType::BSSID: return WiFi.BSSIDstr(); case LabelType::CHANNEL: return String(WiFi.channel()); @@ -201,16 +222,55 @@ String getValue(LabelType::Enum label) { case LabelType::FLASH_WRITE_COUNT: break; case LabelType::SKETCH_SIZE: break; case LabelType::SKETCH_FREE: break; - case LabelType::SPIFFS_SIZE: break; - case LabelType::SPIFFS_FREE: break; + case LabelType::FS_SIZE: break; + case LabelType::FS_FREE: break; case LabelType::MAX_OTA_SKETCH_SIZE: break; case LabelType::OTA_2STEP: break; case LabelType::OTA_POSSIBLE: break; +#ifdef HAS_ETHERNET + case LabelType::ETH_IP_ADDRESS: return NetworkLocalIP().toString(); + case LabelType::ETH_IP_SUBNET: return NetworkSubnetMask().toString(); + case LabelType::ETH_IP_ADDRESS_SUBNET: return String(getValue(LabelType::ETH_IP_ADDRESS) + F(" / ") + getValue(LabelType::ETH_IP_SUBNET)); + case LabelType::ETH_IP_GATEWAY: return NetworkGatewayIP().toString(); + case LabelType::ETH_IP_DNS: return NetworkDnsIP(0).toString(); + case LabelType::ETH_MAC: return NetworkMacAddress(); + case LabelType::ETH_DUPLEX: return eth_connected ? (ETH.fullDuplex() ? F("Full Duplex") : F("Half Duplex")) : F("No Ethernet"); + case LabelType::ETH_SPEED: return eth_connected ? getEthSpeed() : F("No Ethernet"); + case LabelType::ETH_STATE: return eth_connected ? (ETH.linkUp() ? F("Link Up") : F("Link Down")) : F("No Ethernet"); + case LabelType::ETH_SPEED_STATE: return eth_connected ? getEthLinkSpeedState() : F("No Ethernet"); + case LabelType::ETH_WIFI_MODE: return (eth_wifi_mode == WIFI ? F("WIFI") : F("ETHERNET")); + case LabelType::ETH_CONNECTED: return (eth_connected ? F("CONNECTED") : F("DISCONNECTED")); // 0=disconnected, 1=connected +#endif } return F("MissingString"); } +#ifdef HAS_ETHERNET +String getEthSpeed() { + String result; + result.reserve(7); + result += ETH.linkSpeed(); + result += F("Mbps"); + return result; +} + +String getEthLinkSpeedState() { + String result; + result.reserve(29); + if (ETH.linkUp()) { + result += getValue(LabelType::ETH_STATE); + result += ' '; + result += getValue(LabelType::ETH_DUPLEX); + result += ' '; + result += getEthSpeed(); + } else { + result = getValue(LabelType::ETH_STATE); + } + return result; +} +#endif + String getExtendedValue(LabelType::Enum label) { switch (label) { diff --git a/src/StringProviderTypes.h b/src/StringProviderTypes.h index 04abfdbae..efca0d940 100644 --- a/src/StringProviderTypes.h +++ b/src/StringProviderTypes.h @@ -95,12 +95,25 @@ enum Enum : short { FLASH_WRITE_COUNT, SKETCH_SIZE, SKETCH_FREE, - SPIFFS_SIZE, - SPIFFS_FREE, + FS_SIZE, + FS_FREE, MAX_OTA_SKETCH_SIZE, OTA_2STEP, OTA_POSSIBLE, - +#ifdef HAS_ETHERNET + ETH_IP_ADDRESS, + ETH_IP_SUBNET, + ETH_IP_ADDRESS_SUBNET, + ETH_IP_GATEWAY, + ETH_IP_DNS, + ETH_MAC, + ETH_DUPLEX, + ETH_SPEED, + ETH_STATE, + ETH_SPEED_STATE, + ETH_WIFI_MODE, + ETH_CONNECTED, +#endif }; }; diff --git a/src/WebServer.ino b/src/WebServer.ino index 41bbd36c6..6c9a0d0f7 100644 --- a/src/WebServer.ino +++ b/src/WebServer.ino @@ -4,6 +4,8 @@ #include +#include "ESPEasyNetwork.h" +#include "ESPEasy_common.h" #include "src/Globals/CPlugins.h" #include "src/Globals/Device.h" #include "src/Globals/TXBuffer.h" @@ -223,9 +225,9 @@ void WebServerInit() web_server.on(F("/log"), handle_log); web_server.on(F("/login"), handle_login); web_server.on(F("/logjson"), handle_log_JSON); // Also part of WEBSERVER_NEW_UI -#ifndef NOTIFIER_SET_NONE +#ifdef USES_NOTIFIER web_server.on(F("/notifications"), handle_notifications); -#endif // ifndef NOTIFIER_SET_NONE +#endif #ifdef WEBSERVER_PINSTATES web_server.on(F("/pinstates"), handle_pinstates); #endif @@ -315,8 +317,8 @@ void set_mDNS() { if (webserverRunning) { addLog(LOG_LEVEL_INFO, F("WIFI : Starting mDNS...")); - bool mdns_started = MDNS.begin(WifiGetHostname().c_str()); - MDNS.setInstanceName(WifiGetHostname()); // Needed for when the hostname has changed. + bool mdns_started = MDNS.begin(NetworkGetHostname().c_str()); + MDNS.setInstanceName(NetworkGetHostname()); // Needed for when the hostname has changed. if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WIFI : "); @@ -543,12 +545,12 @@ void getWebPageTemplateVar(const String& varName) if ((i == MENU_INDEX_RULES) && !Settings.UseRules) { // hide rules menu item continue; } -#ifdef NOTIFIER_SET_NONE +#ifndef USES_NOTIFIER if (i == MENU_INDEX_NOTIFICATIONS) { // hide notifications menu item continue; } -#endif // ifdef NOTIFIER_SET_NONE +#endif addHtml(F("
192.168.4.1")); TXBuffer.endStream(); - ExecuteCommand_internal(VALUE_SOURCE_HTTP, sCommand.c_str()); + ExecuteCommand_internal(EventValueSource::Enum::VALUE_SOURCE_HTTP, sCommand.c_str()); } addHtml(F("OK")); diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index a0c434d52..73614888e 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -10,8 +10,6 @@ void handle_rules() { if (!isLoggedIn() || !Settings.UseRules) { return; } navMenuIndex = MENU_INDEX_RULES; - static byte currentSet = 1; - const byte rulesSet = getFormItemInt(F("set"), 1); #if defined(ESP8266) @@ -25,80 +23,48 @@ void handle_rules() { String error; - if (web_server.args() > 0) { - String log = F("Rules : Save rulesSet: "); - log += rulesSet; - log += F(" currentSet: "); - log += currentSet; - - if (currentSet == rulesSet) { - if (web_server.hasArg(F("rules"))) { - size_t rulesLength = web_server.arg(F("rules")).length(); - - // Reported length is with CRLF counted as a single byte. - // So rulesLength > reported_length is a valid situation. - size_t reported_length = getFormItemInt(F("rules_len"), 0); - - if (rulesLength > RULES_MAX_SIZE) { - error = F("Error: Data was not saved, exceeds web editor limit!"); - } - - if (reported_length > rulesLength) { - error = F("Error: Data was not saved, not received all. ("); - error += rulesLength; - error += '/'; - error += reported_length; - error += ')'; - } else { - // Save as soon as possible, as the webserver may already overwrite the args. - const byte *memAddress = reinterpret_cast(web_server.arg(F("rules")).c_str()); - error = doSaveToFile(fileName.c_str(), 0, memAddress, rulesLength, "w"); - } - } else { - error = F("Error: Data was not saved, rules argument missing or corrupted"); - } + // Make sure file exists + if (!ESPEASY_FS.exists(fileName)) + { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("Rules : Create new file: "); + log += fileName; + addLog(LOG_LEVEL_INFO, log); } - else // changed set, check if file exists and create new - { - if (!SPIFFS.exists(fileName)) - { - log += F(" Create new file: "); - log += fileName; - fs::File f = tryOpenFile(fileName, "w"); + fs::File f = tryOpenFile(fileName, "w"); - if (f) { f.close(); } - } - } - addLog(LOG_LEVEL_INFO, log); + if (f) { f.close(); } } + TXBuffer.startStream(); sendHeadandTail_stdtemplate(); addHtmlError(error); - if (rulesSet != currentSet) { - currentSet = rulesSet; - } - html_table_class_normal(); html_TR(); html_table_header(F("Rules")); - byte choice = rulesSet; - String options[RULESETS_MAX]; - int optionValues[RULESETS_MAX]; - - for (byte x = 0; x < RULESETS_MAX; x++) + html_TR_TD(); + addHtml(F("")); { - options[x] = F("Rules Set "); - options[x] += x + 1; - optionValues[x] = x + 1; + // Place combo box in its own scope to release these arrays as soon as possible + byte choice = rulesSet; + String options[RULESETS_MAX]; + int optionValues[RULESETS_MAX]; + + for (byte x = 0; x < RULESETS_MAX; x++) + { + options[x] = F("Rules Set "); + options[x] += x + 1; + optionValues[x] = x + 1; + } + + addSelector(F("set"), RULESETS_MAX, options, optionValues, NULL, choice, true, true); + addHelpButton(F("Tutorial_Rules")); + addRTDHelpButton(F("Rules/Rules.html")); } html_TR_TD(); - addHtml(F("")); - addSelector(F("set"), RULESETS_MAX, options, optionValues, NULL, choice, true, true); - addHelpButton(F("Tutorial_Rules")); - Rule_showRuleTextArea(fileName); html_TR_TD(); @@ -106,12 +72,13 @@ void handle_rules() { addHtml(F("")); addHtml(F("
Saved!
")); + addButton(fileName, F("Download to file")); + html_end_table(); + html_add_script(true); TXBuffer += jsSaveRules; html_add_script_end(); - addButton(fileName, F("Download to file")); - html_end_table(); sendHeadandTail_stdtemplate(true); TXBuffer.endStream(); @@ -349,7 +316,7 @@ void handle_rules_delete() { if (fileName.length() > 0) { - removed = SPIFFS.remove(fileName); + removed = ESPEASY_FS.remove(fileName); } if (removed) @@ -422,7 +389,7 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { Serial.print(F("File name: ")); Serial.println(fileName); #endif // ifdef WEBSERVER_RULES_DEBUG - bool isEdit = SPIFFS.exists(fileName); + bool isEdit = ESPEASY_FS.exists(fileName); if (web_server.args() > 0) { @@ -596,7 +563,7 @@ bool EnumerateFileAndDirectory(String & rootPath bool next = true; #ifdef ESP8266 - fs::Dir dir = SPIFFS.openDir(rootPath); + fs::Dir dir = ESPEASY_FS.openDir(rootPath); Serial.print(F("Enumerate files of ")); Serial.println(rootPath); @@ -620,7 +587,7 @@ bool EnumerateFileAndDirectory(String & rootPath hasMore = dir.next(); #endif // ifdef ESP8266 #ifdef ESP32 - File root = SPIFFS.open(rootPath); + File root = ESPEASY_FS.open(rootPath); if (root) { diff --git a/src/WebServer_SetupPage.ino b/src/WebServer_SetupPage.ino index b7c7b510f..37eecab15 100644 --- a/src/WebServer_SetupPage.ino +++ b/src/WebServer_SetupPage.ino @@ -14,7 +14,7 @@ void handle_setup() { // Do not check client IP range allowed. TXBuffer.startStream(); - if (!WiFiConnected()) + if (!NetworkConnected()) { sendHeadandTail(F("TmplAP")); static byte status = 0; @@ -78,7 +78,7 @@ void handle_setup() { void handle_setup_scan_and_show(const String& ssid, const String& other, const String& password) { if (WiFi.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + WifiScan(false, false); setWifiMode(cur_wifimode); } @@ -188,7 +188,7 @@ void handle_setup_finish() { html_TD(); if (!clientIPinSubnet()) { - String host = formatIP(WiFi.localIP()); + String host = formatIP(NetworkLocalIP()); String url = F("http://"); url += host; url += F("/config"); diff --git a/src/WebServer_SysInfoPage.ino b/src/WebServer_SysInfoPage.ino index b37c3544a..ec4bc5174 100644 --- a/src/WebServer_SysInfoPage.ino +++ b/src/WebServer_SysInfoPage.ino @@ -2,6 +2,12 @@ #include "src/DataStructs/RTCStruct.h" #include "src/Globals/CRCValues.h" #include "src/Static/WebStaticData.h" +#include "ESPEasy_common.h" + +#include "src/Commands/Diagnostic.h" + +#include "src/Helpers/Hardware.h" + #ifdef WEBSERVER_NEW_UI @@ -60,33 +66,33 @@ void handle_sysinfo_json() { } json_number(F("rssi"), String(WiFi.RSSI())); json_prop(F("dhcp"), useStaticIP() ? getLabel(LabelType::IP_CONFIG_STATIC) : getLabel(LabelType::IP_CONFIG_DYNAMIC)); - json_prop(F("ip"), formatIP(WiFi.localIP())); - json_prop(F("subnet"), formatIP(WiFi.subnetMask())); - json_prop(F("gw"), formatIP(WiFi.gatewayIP())); - json_prop(F("dns1"), formatIP(WiFi.dnsIP(0))); - json_prop(F("dns2"), formatIP(WiFi.dnsIP(1))); + json_prop(F("ip"), formatIP(NetworkLocalIP())); + json_prop(F("subnet"), formatIP(NetworkSubnetMask())); + json_prop(F("gw"), formatIP(NetworkGatewayIP())); + json_prop(F("dns1"), formatIP(NetworkDnsIP(0))); + json_prop(F("dns2"), formatIP(NetworkDnsIP(1))); json_prop(F("allowed_range"), describeAllowedIPrange()); - - - uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = WiFi.macAddress(mac); - char macaddress[20]; - formatMAC(macread, macaddress); - - json_prop(F("sta_mac"), macaddress); - - macread = WiFi.softAPmacAddress(mac); - formatMAC(macread, macaddress); - - json_prop(F("ap_mac"), macaddress); - json_prop(F("ssid"), WiFi.SSID()); - json_prop(F("bssid"), WiFi.BSSIDstr()); - json_number(F("channel"), String(WiFi.channel())); - json_prop(F("connected"), format_msec_duration(timeDiff(lastConnectMoment, millis()))); - json_prop(F("ldr"), getLastDisconnectReason()); + json_prop(F("sta_mac"), NetworkMacAddress()); + json_prop(F("ap_mac"), WifiSoftAPmacAddress()); + json_prop(F("ssid"), WiFi.SSID()); + json_prop(F("bssid"), WiFi.BSSIDstr()); + json_number(F("channel"), String(WiFi.channel())); + json_prop(F("connected"), format_msec_duration(timeDiff(lastConnectMoment, millis()))); + json_prop(F("ldr"), getLastDisconnectReason()); json_number(F("reconnects"), String(wifi_reconnects)); json_close(); +#ifdef HAS_ETHERNET + json_open(false, F("ethernet")); + json_prop(F("ethwifimode"), getValue(LabelType::ETH_WIFI_MODE)); + json_prop(F("ethconnected"), getValue(LabelType::ETH_CONNECTED); + json_prop(F("ethduplex"), getValue(LabelType::ETH_DUPLEX); + json_prop(F("ethspeed"), getValue(LabelType::ETH_SPEED); + json_prop(F("ethstate"), getValue(LabelType::ETH_STATE); + json_prop(F("ethspeedstate"), getValue(LabelType::ETH_SPEED_STATE); + json.close(); +#endif + json_open(false, F("firmware")); json_prop(F("build"), String(BUILD)); json_prop(F("notes"), F(BUILD_NOTES)); @@ -220,6 +226,10 @@ void handle_sysinfo() { handle_sysinfo_Network(); +#ifdef HAS_ETHERNET + handle_sysinfo_Ethernet(); +#endif + handle_sysinfo_WiFiSettings(); handle_sysinfo_Firmware(); @@ -265,7 +275,7 @@ void handle_sysinfo_basicInfo() { addRowLabelValue(LabelType::CPU_ECO_MODE); int freeMem = ESP.getFreeHeap(); - addRowLabel(F("Free Mem")); + addRowLabel(getLabel(LabelType::FREE_MEM)); { String html; html.reserve(64); @@ -278,7 +288,7 @@ void handle_sysinfo_basicInfo() { html += ')'; addHtml(html); } - addRowLabel(F("Free Stack")); + addRowLabel(getLabel(LabelType::FREE_STACK)); { String html; html.reserve(64); @@ -311,12 +321,36 @@ void handle_sysinfo_basicInfo() { addRowLabelValue(LabelType::RESET_REASON); addRowLabelValue(LabelType::LAST_TASK_BEFORE_REBOOT); addRowLabelValue(LabelType::SW_WD_COUNT); + + #ifdef HAS_ETHERNET + addRowLabel(F("Network Type")); + addRowLabelValue(LabelType::ETH_WIFI_MODE); + #endif } +#ifdef HAS_ETHERNET +void handle_sysinfo_Ethernet() { + if(eth_wifi_mode == ETHERNET) { + addTableSeparator(F("Ethernet"), 2, 3); + addRowLabelValue(LabelType::ETH_STATE); + addRowLabelValue(LabelType::ETH_SPEED); + addRowLabelValue(LabelType::ETH_DUPLEX); + addRowLabelValue(LabelType::ETH_MAC); + addRowLabelValue(LabelType::ETH_IP_ADDRESS_SUBNET); + addRowLabelValue(LabelType::ETH_IP_GATEWAY); + addRowLabelValue(LabelType::ETH_IP_DNS); + } +} +#endif + void handle_sysinfo_Network() { addTableSeparator(F("Network"), 2, 3, F("Wifi")); - if (WiFiConnected()) + if ( + #ifdef HAS_ETHERNET + eth_wifi_mode == WIFI && + #endif + NetworkConnected()) { addRowLabel(F("Wifi")); # if defined(ESP8266) @@ -354,20 +388,8 @@ void handle_sysinfo_Network() { addRowLabelValue(LabelType::CLIENT_IP); addRowLabelValue(LabelType::DNS); addRowLabelValue(LabelType::ALLOWED_IP_RANGE); - addRowLabel(getLabel(LabelType::STA_MAC)); - - { - uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = WiFi.macAddress(mac); - char macaddress[20]; - formatMAC(macread, macaddress); - addHtml(macaddress); - - addRowLabel(getLabel(LabelType::AP_MAC)); - macread = WiFi.softAPmacAddress(mac); - formatMAC(macread, macaddress); - addHtml(macaddress); - } + addRowLabelValue(LabelType::STA_MAC); + addRowLabelValue(LabelType::AP_MAC); addRowLabel(getLabel(LabelType::SSID)); { @@ -596,7 +618,7 @@ void handle_sysinfo_Storage() { } - addRowLabel(getLabel(LabelType::SPIFFS_SIZE)); + addRowLabel(getLabel(LabelType::FS_SIZE)); { String html; html.reserve(32); @@ -620,7 +642,7 @@ void handle_sysinfo_Storage() { { # if defined(ESP8266) fs::FSInfo fs_info; - SPIFFS.info(fs_info); + ESPEASY_FS.info(fs_info); addRowLabel(F("Maximum open files")); addHtml(String(fs_info.maxOpenFiles)); diff --git a/src/WebServer_SysVarPage.ino b/src/WebServer_SysVarPage.ino index c480a2297..f0e70f2e8 100644 --- a/src/WebServer_SysVarPage.ino +++ b/src/WebServer_SysVarPage.ino @@ -44,11 +44,24 @@ void handle_sysvars() { #endif // if defined(ESP8266) addSysVar_enum_html(SystemVariables::IP); addSysVar_enum_html(SystemVariables::IP4); + addSysVar_enum_html(SystemVariables::SUBNET); + addSysVar_enum_html(SystemVariables::GATEWAY); + addSysVar_enum_html(SystemVariables::DNS); addSysVar_enum_html(SystemVariables::RSSI); addSysVar_enum_html(SystemVariables::SSID); addSysVar_enum_html(SystemVariables::BSSID); addSysVar_enum_html(SystemVariables::WI_CH); +#ifdef HAS_ETHERNET + addTableSeparator(F("Ethernet"), 3, 3); + addSysVar_enum_html(SystemVariables::ETHWIFIMODE); + addSysVar_enum_html(SystemVariables::ETHCONNECTED); + addSysVar_enum_html(SystemVariables::ETHDUPLEX); + addSysVar_enum_html(SystemVariables::ETHSPEED); + addSysVar_enum_html(SystemVariables::ETHSTATE); + addSysVar_enum_html(SystemVariables::ETHSPEEDSTATE); + #endif + addTableSeparator(F("System"), 3, 3); addSysVar_enum_html(SystemVariables::UNIT_sysvar); addSysVar_enum_html(SystemVariables::SYSLOAD); diff --git a/src/WebServer_TimingStats.ino b/src/WebServer_TimingStats.ino index 0f75c08f3..cb38bafa7 100644 --- a/src/WebServer_TimingStats.ino +++ b/src/WebServer_TimingStats.ino @@ -1,5 +1,7 @@ +#include "ESPEasy_common.h" -#ifdef WEBSERVER_TIMINGSTATS + +#if defined(WEBSERVER_TIMINGSTATS) && defined(USES_TIMING_STATS) #include "src/Globals/Device.h" diff --git a/src/WebServer_ToolsPage.ino b/src/WebServer_ToolsPage.ino index 3d1824e58..c24b2ba56 100644 --- a/src/WebServer_ToolsPage.ino +++ b/src/WebServer_ToolsPage.ino @@ -1,5 +1,7 @@ #ifdef WEBSERVER_TOOLS +#include "src/Commands/InternalCommands.h" + // ******************************************************************************** // Web Interface Tools page // ******************************************************************************** @@ -31,7 +33,7 @@ void handle_tools() { if (webrequest.length() > 0) { - ExecuteCommand_all(VALUE_SOURCE_WEB_FRONTEND, webrequest.c_str()); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_WEB_FRONTEND, webrequest.c_str()); } if (printWebString.length() > 0) diff --git a/src/WebServer_WiFiScanner.ino b/src/WebServer_WiFiScanner.ino index 71ac4691d..f32c50866 100644 --- a/src/WebServer_WiFiScanner.ino +++ b/src/WebServer_WiFiScanner.ino @@ -65,7 +65,7 @@ void handle_wifiscanner() { if (!isLoggedIn()) { return; } WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + WifiScan(false, false); setWifiMode(cur_wifimode); navMenuIndex = MENU_INDEX_TOOLS; diff --git a/src/_C001.ino b/src/_C001.ino index 13e82e5e0..40138f9ca 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -46,27 +46,26 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& { // We now create a URI for the request String url; + url.reserve(128); + url = F("/json.htm?type=command¶m="); + switch (event->sensorType) { case SENSOR_TYPE_SWITCH: - url = F("/json.htm?type=command¶m=switchlight&idx="); - url += event->idx; - url += F("&switchcmd="); - if (UserVar[event->BaseVarIndex] == 0) - url += F("Off"); - else - url += F("On"); - break; case SENSOR_TYPE_DIMMER: - url = F("/json.htm?type=command¶m=switchlight&idx="); + url += F("switchlight&idx="); url += event->idx; url += F("&switchcmd="); if (UserVar[event->BaseVarIndex] == 0) { - url += ("Off"); + url += F("Off"); } else { - url += F("Set%20Level&level="); - url += UserVar[event->BaseVarIndex]; + if (event->sensorType == SENSOR_TYPE_SWITCH) { + url += F("On"); + } else { + url += F("Set%20Level&level="); + url += UserVar[event->BaseVarIndex]; + } } break; @@ -82,7 +81,7 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& case SENSOR_TYPE_WIND: case SENSOR_TYPE_STRING: default: - url = F("/json.htm?type=command¶m=udevice&idx="); + url += F("udevice&idx="); url += event->idx; url += F("&nvalue=0"); url += F("&svalue="); diff --git a/src/_C002.ino b/src/_C002.ino index f49d2c64c..1c8c9b97b 100644 --- a/src/_C002.ino +++ b/src/_C002.ino @@ -8,8 +8,12 @@ #define CPLUGIN_ID_002 2 #define CPLUGIN_NAME_002 "Domoticz MQTT" +#include "src/Commands/InternalCommands.h" #include +String CPlugin_002_pubname; +bool CPlugin_002_retain = false; + bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& string) { bool success = false; @@ -40,6 +44,8 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& MakeControllerSettings(ControllerSettings); LoadControllerSettings(event->ControllerIndex, ControllerSettings); MQTTDelayHandler.configureControllerSettings(ControllerSettings); + CPlugin_002_pubname = ControllerSettings.Publish; + CPlugin_002_retain = ControllerSettings.mqtt_retainFlag(); break; } @@ -149,7 +155,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& } if (action.length() > 0) { - ExecuteCommand_plugin(x, VALUE_SOURCE_MQTT, action.c_str()); + ExecuteCommand_plugin(x, EventValueSource::Enum::VALUE_SOURCE_MQTT, action.c_str()); // trigger rulesprocessing if (Settings.UseRules) { @@ -171,16 +177,6 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& { if (event->idx != 0) { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - - /* - if (!ControllerSettings.checkHostReachable(true)) { - success = false; - break; - } - */ - DynamicJsonDocument root(200); root[F("idx")] = event->idx; root[F("RSSI")] = mapRSSItoDomoticz(); @@ -236,10 +232,10 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_DEBUG, log); #endif // ifndef BUILD_NO_DEBUG - String pubname = ControllerSettings.Publish; + String pubname = CPlugin_002_pubname; parseControllerVariables(pubname, event, false); - success = MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), ControllerSettings.mqtt_retainFlag()); + success = MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), CPlugin_002_retain); } // if ixd !=0 else { diff --git a/src/_C005.ino b/src/_C005.ino index b5906b2bd..95211674d 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -7,6 +7,10 @@ #define CPLUGIN_ID_005 5 #define CPLUGIN_NAME_005 "Home Assistant (openHAB) MQTT" +String CPlugin_005_pubname; +bool CPlugin_005_mqtt_retainFlag; + + bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& string) { bool success = false; @@ -37,6 +41,8 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& MakeControllerSettings(ControllerSettings); LoadControllerSettings(event->ControllerIndex, ControllerSettings); MQTTDelayHandler.configureControllerSettings(ControllerSettings); + CPlugin_005_pubname = ControllerSettings.Publish; + CPlugin_005_mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); break; } @@ -64,7 +70,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& if (lastPartTopic == F("cmd")) { cmd = event->String2; parseCommandString(&TempEvent, cmd); - TempEvent.Source = VALUE_SOURCE_MQTT; + TempEvent.Source = EventValueSource::Enum::VALUE_SOURCE_MQTT; validTopic = true; } else { if (lastindex > 0) { @@ -94,23 +100,16 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - if (!ControllerSettings.checkHostReachable(true)) { - success = false; - break; - } - statusLED(true); + String pubname = CPlugin_005_pubname; + bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { String dummy; PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - String pubname = ControllerSettings.Publish; parseControllerVariables(pubname, event, false); - String value = ""; byte valueCount = getValueCountFromSensorType(event->sensorType); for (byte x = 0; x < valueCount; x++) { @@ -120,15 +119,23 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& String tmppubname = pubname; tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - value = formatUserVarNoCheck(event, x); - - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), ControllerSettings.mqtt_retainFlag()); + String value = ""; + // Small optimization so we don't try to copy potentially large strings + if (event->sensorType == SENSOR_TYPE_STRING) { + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + value = event->String2.substring(0, 20); // For the log + } else { + value = formatUserVarNoCheck(event, x); + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + } #ifndef BUILD_NO_DEBUG - String log = F("MQTT : "); - log += tmppubname; - log += ' '; - log += value; - addLog(LOG_LEVEL_DEBUG, log); + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + String log = F("MQTT : "); + log += tmppubname; + log += ' '; + log += value; + addLog(LOG_LEVEL_DEBUG, log); + } #endif } break; diff --git a/src/_C006.ino b/src/_C006.ino index 6cc4fa7f0..0b13d7e95 100644 --- a/src/_C006.ino +++ b/src/_C006.ino @@ -7,6 +7,10 @@ #define CPLUGIN_ID_006 6 #define CPLUGIN_NAME_006 "PiDome MQTT" +String CPlugin_006_pubname; +bool CPlugin_006_mqtt_retainFlag; + + bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& string) { bool success = false; @@ -37,6 +41,8 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& MakeControllerSettings(ControllerSettings); LoadControllerSettings(event->ControllerIndex, ControllerSettings); MQTTDelayHandler.configureControllerSettings(ControllerSettings); + CPlugin_006_pubname = ControllerSettings.Publish; + CPlugin_006_mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); break; } @@ -87,12 +93,12 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { success = false; break; } - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); + String pubname = CPlugin_006_pubname; + bool mqtt_retainFlag = CPlugin_006_mqtt_retainFlag; statusLED(true); @@ -101,17 +107,20 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - String pubname = ControllerSettings.Publish; parseControllerVariables(pubname, event, false); - String value = ""; byte valueCount = getValueCountFromSensorType(event->sensorType); for (byte x = 0; x < valueCount; x++) { String tmppubname = pubname; tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), ControllerSettings.mqtt_retainFlag()); + // Small optimization so we don't try to copy potentially large strings + if (event->sensorType == SENSOR_TYPE_STRING) { + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + } else { + String value = formatUserVarNoCheck(event, x); + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + } } break; } diff --git a/src/_C008.ino b/src/_C008.ino index 88bed66e5..59487f393 100644 --- a/src/_C008.ino +++ b/src/_C008.ino @@ -50,33 +50,49 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - // Collect the values at the same run, to make sure all are from the same sample - byte valueCount = getValueCountFromSensorType(event->sensorType); - C008_queue_element element(event, valueCount); - if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { - String dummy; - PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); + String pubname; + { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("C008 : Generic HTTP - Cannot send, out of RAM")); + break; + } + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + pubname = ControllerSettings.Publish; } - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); + // FIXME TD-er must define a proper move operator + byte valueCount = getValueCountFromSensorType(event->sensorType); + success = C008_DelayHandler.addToQueue(C008_queue_element(event, valueCount)); + if (success) { + // Element was added. + // Now we try to append to the existing element + // and thus preventing the need to create a long string only to copy it to a queue element. + C008_queue_element &element = C008_DelayHandler.sendQueue.back(); - for (byte x = 0; x < valueCount; x++) - { - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - element.txt[x] = "/"; - element.txt[x] += ControllerSettings.Publish; - element.txt[x].replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - element.txt[x].replace(F("%value%"), formattedValue); - parseControllerVariables(element.txt[x], event, true); + // Collect the values at the same run, to make sure all are from the same sample + if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { + String dummy; + PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); + } + + for (byte x = 0; x < valueCount; x++) + { + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + if (isvalid) { + element.txt[x] = "/"; + element.txt[x] += pubname; + element.txt[x].replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); + element.txt[x].replace(F("%value%"), formattedValue); + parseControllerVariables(element.txt[x], event, true); #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); + addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); #endif + } } } - success = C008_DelayHandler.addToQueue(element); scheduleNextDelayQueue(TIMER_C008_DELAY_QUEUE, C008_DelayHandler.getNextScheduleTime()); break; } diff --git a/src/_C009.ino b/src/_C009.ino index c7a86ad3b..ddca63a64 100644 --- a/src/_C009.ino +++ b/src/_C009.ino @@ -68,7 +68,8 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& { element.txt[x] = formatUserVarNoCheck(event, x); } - success = C009_DelayHandler.addToQueue(element); + // FIXME TD-er must define a proper move operator + success = C009_DelayHandler.addToQueue(C009_queue_element(element)); scheduleNextDelayQueue(TIMER_C009_DELAY_QUEUE, C009_DelayHandler.getNextScheduleTime()); break; } @@ -123,9 +124,9 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element // embed IP, important if there is NAT/PAT // char ipStr[20]; - // IPAddress ip = WiFi.localIP(); + // IPAddress ip = NetworkLocalIP(); // sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); - ESP[F("ip")] = WiFi.localIP().toString(); + ESP[F("ip")] = NetworkLocalIP().toString(); // Create nested SENSOR json object JsonObject SENSOR = data.createNestedObject(String(F("SENSOR"))); diff --git a/src/_C010.ino b/src/_C010.ino index 549971049..6ebe6bc03 100644 --- a/src/_C010.ino +++ b/src/_C010.ino @@ -63,7 +63,8 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); } } - success = C010_DelayHandler.addToQueue(element); + // FIXME TD-er must define a proper move operator + success = C010_DelayHandler.addToQueue(C010_queue_element(element)); scheduleNextDelayQueue(TIMER_C010_DELAY_QUEUE, C010_DelayHandler.getNextScheduleTime()); break; } diff --git a/src/_C011.ino b/src/_C011.ino index 6beab4c61..e6b3eabca 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -56,59 +56,62 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { String escapeBuffer; - - C011_ConfigStruct customConfig; - - LoadCustomControllerSettings(event->ControllerIndex,(byte*)&customConfig, sizeof(customConfig)); - customConfig.zero_last(); - { - byte choice = 0; - String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; - for (byte i = 0; i < 5; i++) + std::shared_ptr customConfig(new C011_ConfigStruct); + if (customConfig) { + LoadCustomControllerSettings(event->ControllerIndex,(byte*)customConfig.get(), sizeof(customConfig)); + customConfig->zero_last(); { - if (methods[i].equals(customConfig.HttpMethod)) { - choice = i; + byte choice = 0; + String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; + for (byte i = 0; i < 5; i++) + { + if (methods[i].equals(customConfig->HttpMethod)) { + choice = i; + } } + addFormSelector(F("HTTP Method"), F("P011httpmethod"), 5, methods, NULL, choice); } - addFormSelector(F("HTTP Method"), F("P011httpmethod"), 5, methods, NULL, choice); - } - addFormTextBox(F("HTTP URI"), F("P011httpuri"), customConfig.HttpUri, C011_HTTP_URI_MAX_LEN-1); - { - String escapeBuffer = customConfig.HttpHeader; - htmlEscape(escapeBuffer); - addFormTextArea(F("HTTP Header"), F("P011httpheader"), escapeBuffer, C011_HTTP_HEADER_MAX_LEN-1, 4, 50); - } - { - String escapeBuffer = customConfig.HttpBody; - htmlEscape(escapeBuffer); - addFormTextArea(F("HTTP Body"), F("P011httpbody"), escapeBuffer, C011_HTTP_BODY_MAX_LEN-1, 8, 50); + addFormTextBox(F("HTTP URI"), F("P011httpuri"), customConfig->HttpUri, C011_HTTP_URI_MAX_LEN-1); + { + String escapeBuffer = customConfig->HttpHeader; + htmlEscape(escapeBuffer); + addFormTextArea(F("HTTP Header"), F("P011httpheader"), escapeBuffer, C011_HTTP_HEADER_MAX_LEN-1, 4, 50); + } + { + String escapeBuffer = customConfig->HttpBody; + htmlEscape(escapeBuffer); + addFormTextArea(F("HTTP Body"), F("P011httpbody"), escapeBuffer, C011_HTTP_BODY_MAX_LEN-1, 8, 50); + } } break; } case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: { - C011_ConfigStruct customConfig; - byte choice = 0; - String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; - for (byte i = 0; i < 5; i++) - { - if (methods[i].equals(customConfig.HttpMethod)) { - choice = i; + std::shared_ptr customConfig(new C011_ConfigStruct); + if (customConfig) { + byte choice = 0; + String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; + for (byte i = 0; i < 5; i++) + { + if (methods[i].equals(customConfig->HttpMethod)) { + choice = i; + } } - } - int httpmethod = getFormItemInt(F("P011httpmethod"), choice); - String httpuri = web_server.arg(F("P011httpuri")); - String httpheader = web_server.arg(F("P011httpheader")); - String httpbody = web_server.arg(F("P011httpbody")); - strlcpy(customConfig.HttpMethod, methods[httpmethod].c_str(), sizeof(customConfig.HttpMethod)); - strlcpy(customConfig.HttpUri, httpuri.c_str(), sizeof(customConfig.HttpUri)); - strlcpy(customConfig.HttpHeader, httpheader.c_str(), sizeof(customConfig.HttpHeader)); - strlcpy(customConfig.HttpBody, httpbody.c_str(), sizeof(customConfig.HttpBody)); - customConfig.zero_last(); - SaveCustomControllerSettings(event->ControllerIndex,(byte*)&customConfig, sizeof(customConfig)); + int httpmethod = getFormItemInt(F("P011httpmethod"), choice); + String httpuri = web_server.arg(F("P011httpuri")); + String httpheader = web_server.arg(F("P011httpheader")); + String httpbody = web_server.arg(F("P011httpbody")); + + strlcpy(customConfig->HttpMethod, methods[httpmethod].c_str(), sizeof(customConfig->HttpMethod)); + strlcpy(customConfig->HttpUri, httpuri.c_str(), sizeof(customConfig->HttpUri)); + strlcpy(customConfig->HttpHeader, httpheader.c_str(), sizeof(customConfig->HttpHeader)); + strlcpy(customConfig->HttpBody, httpbody.c_str(), sizeof(customConfig->HttpBody)); + customConfig->zero_last(); + SaveCustomControllerSettings(event->ControllerIndex,(byte*)customConfig.get(), sizeof(customConfig)); + } break; } @@ -154,51 +157,75 @@ bool do_process_c011_delay_queue(int controller_number, const C011_queue_element //******************************************************************************** boolean Create_schedule_HTTP_C011(struct EventStruct *event) { - int controller_number = CPLUGIN_ID_011; - if (!WiFiConnected(10)) { - return false; - } - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - - C011_ConfigStruct customConfig; - LoadCustomControllerSettings(event->ControllerIndex,(byte*)&customConfig, sizeof(customConfig)); - customConfig.zero_last(); - - WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) - return false; - + String authHeader; + String hostportString; if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { String dummy; PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - String payload = create_http_request_auth( - controller_number, event->ControllerIndex, ControllerSettings, - String(customConfig.HttpMethod), customConfig.HttpUri); - - // Remove extra newline, see https://github.com/letscontrolit/ESPEasy/issues/1970 - removeExtraNewLine(payload); - if (strlen(customConfig.HttpHeader) > 0) { - payload += customConfig.HttpHeader; - removeExtraNewLine(payload); - } - ReplaceTokenByValue(payload, event); - - if (strlen(customConfig.HttpBody) > 0) { - String body = String(customConfig.HttpBody); - ReplaceTokenByValue(body, event); - payload += F("Content-Length: "); - payload += String(body.length()); - addNewLine(payload); - addNewLine(payload); // Need 2 CRLF between header and body. - payload += body; - } - addNewLine(payload); + // Have the ControllerSettings in a separate scope so we can free it as soon as possible + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + return false; + } + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + + authHeader = get_auth_header(event->ControllerIndex, ControllerSettings); + const bool defaultport = ControllerSettings.Port == 0 || ControllerSettings.Port == 80; + hostportString = defaultport ? ControllerSettings.getHost() : ControllerSettings.getHostPortString(); + } + + + std::shared_ptr customConfig(new C011_ConfigStruct); + if (!customConfig) { + return false; + } + LoadCustomControllerSettings(event->ControllerIndex,(byte*)customConfig.get(), sizeof(customConfig)); + customConfig->zero_last(); + + bool success = false; + { + String payload = do_create_http_request( + hostportString, + customConfig->HttpMethod, + customConfig->HttpUri, + authHeader, + "", + -1); + + // Remove extra newline, see https://github.com/letscontrolit/ESPEasy/issues/1970 + removeExtraNewLine(payload); + + // Add a new element to the queue with the minimal payload + success = C011_DelayHandler.addToQueue(C011_queue_element(event->ControllerIndex, payload)); + } + if (success) { + // Element was added. + // Now we try to append to the existing element + // and thus preventing the need to create a long string only to copy it to a queue element. + C011_queue_element &element = C011_DelayHandler.sendQueue.back(); + + if (strlen(customConfig->HttpHeader) > 0) { + element.txt += customConfig->HttpHeader; + removeExtraNewLine(element.txt); + } + ReplaceTokenByValue(element.txt, event); + + if (strlen(customConfig->HttpBody) > 0) + { + String body = String(customConfig->HttpBody); + ReplaceTokenByValue(body, event); + element.txt += F("Content-Length: "); + element.txt += String(body.length()); + addNewLine(element.txt); + addNewLine(element.txt); // Need 2 CRLF between header and body. + element.txt += body; + } + addNewLine(element.txt); + } - bool success = C011_DelayHandler.addToQueue(C011_queue_element(event->ControllerIndex, payload)); scheduleNextDelayQueue(TIMER_C011_DELAY_QUEUE, C011_DelayHandler.getNextScheduleTime()); return success; } diff --git a/src/_C012.ino b/src/_C012.ino index 35ba99aeb..d5a639831 100644 --- a/src/_C012.ino +++ b/src/_C012.ino @@ -5,6 +5,8 @@ // #ifdef PLUGIN_BUILD_TESTING +#include "src/Commands/Blynk.h" + #define CPLUGIN_012 #define CPLUGIN_ID_012 12 #define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]" @@ -58,7 +60,8 @@ bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); } } - success = C012_DelayHandler.addToQueue(element); + // FIXME TD-er must define a proper move operator + success = C012_DelayHandler.addToQueue(C012_queue_element(element)); scheduleNextDelayQueue(TIMER_C012_DELAY_QUEUE, C012_DelayHandler.getNextScheduleTime()); break; } @@ -93,91 +96,11 @@ bool do_process_c012_delay_queue(int controller_number, const C012_queue_element if (element.checkDone(true)) return true; } - if (!WiFiConnected()) { + if (!NetworkConnected()) { return false; } return element.checkDone(Blynk_get(element.txt[element.valuesSent], element.controller_idx)); } -boolean Blynk_get(const String& command, controllerIndex_t controllerIndex, float *data ) -{ - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - if ((getControllerPass(controllerIndex, ControllerSettings).length() == 0)) { - addLog(LOG_LEVEL_ERROR, F("Blynk : No password set")); - return false; - } - - WiFiClient client; - if (!try_connect_host(CPLUGIN_ID_012, client, ControllerSettings)) - return false; - - - // We now create a URI for the request - char request[300] = {0}; - sprintf_P(request, - PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"), - getControllerPass(controllerIndex, ControllerSettings).c_str(), - command.c_str(), - ControllerSettings.getHost().c_str()); - addLog(LOG_LEVEL_DEBUG, request); - client.print(request); - bool success = !ControllerSettings.MustCheckReply; - if (ControllerSettings.MustCheckReply || data) { - unsigned long timer = millis() + 200; - while (!client_available(client) && !timeOutReached(timer)) - delay(1); - - char log[80] = {0}; - timer = millis() + 1500; - // Read all the lines of the reply from server and log them - while (client_available(client) && !success && !timeOutReached(timer)) { - String line; - safeReadStringUntil(client, line, '\n'); - addLog(LOG_LEVEL_DEBUG_MORE, line); - // success ? - if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) { - strcpy_P(log, PSTR("HTTP : Success")); - if (!data) success = true; - } - else if (line.substring(0, 24) == F("HTTP/1.1 400 Bad Request")) { - strcpy_P(log, PSTR("HTTP : Unauthorized")); - } - else if (line.substring(0, 25) == F("HTTP/1.1 401 Unauthorized")) { - strcpy_P(log, PSTR("HTTP : Unauthorized")); - } - addLog(LOG_LEVEL_DEBUG, log); - - // data only - if (data && line.startsWith("[")) - { - String strValue = line; - byte pos = strValue.indexOf('"',2); - strValue = strValue.substring(2, pos); - strValue.trim(); - float value = strValue.toFloat(); - *data = value; - success = true; - - char value_char[5] = {0}; - strValue.toCharArray(value_char, 5); - sprintf_P(log, PSTR("Blynk get - %s => %s"),command.c_str(), value_char ); - addLog(LOG_LEVEL_DEBUG, log); - } - delay(0); - } - } - addLog(LOG_LEVEL_DEBUG, F("HTTP : closing connection (012)")); - - client.flush(); - client.stop(); - - // important - backgroundtasks - free mem - unsigned long timer = millis() + ControllerSettings.ClientTimeout; - while (!timeOutReached(timer)) - backgroundtasks(); - - return success; -} #endif diff --git a/src/_C013.ino b/src/_C013.ino index 2b17d2332..005119814 100644 --- a/src/_C013.ino +++ b/src/_C013.ino @@ -114,7 +114,7 @@ bool CPlugin_013(CPlugin::Function function, struct EventStruct *event, String& // ******************************************************************************** void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } @@ -158,7 +158,7 @@ void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskInde void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } struct C013_SensorDataStruct dataReply; @@ -196,7 +196,7 @@ void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskInde \*********************************************************************************************/ void C013_sendUDP(byte unit, byte *data, byte size) { - if (!WiFiConnected(10)) { + if (!NetworkConnected(10)) { return; } NodesMap::iterator it; diff --git a/src/_C014.ino b/src/_C014.ino index 966d6d65e..825c60a45 100644 --- a/src/_C014.ino +++ b/src/_C014.ino @@ -37,6 +37,9 @@ byte msgCounter=0; // counter for send Messages (currently for information / log only! +String CPlugin_014_pubname; +bool CPlugin_014_mqtt_retainFlag; + // send MQTT Message with complete Topic / Payload bool CPlugin_014_sendMQTTmsg(String& topic, const char* payload, int& errorCounter) { @@ -157,6 +160,8 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& MakeControllerSettings(ControllerSettings); LoadControllerSettings(event->ControllerIndex, ControllerSettings); MQTTDelayHandler.configureControllerSettings(ControllerSettings); + CPlugin_014_pubname = ControllerSettings.Publish; + CPlugin_014_mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); break; } @@ -207,12 +212,6 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_GOT_CONNECTED: //// call after connected to mqtt server to publich device autodicover features { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - if (!ControllerSettings.checkHostReachable(true)) { - success = false; - break; - } statusLED(true); // send autodiscover header @@ -243,10 +242,10 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& // $localip Device → Controller IP of the device on the local network Yes Yes #ifdef CPLUGIN_014_V3 - CPlugin_014_sendMQTTdevice(pubname,"$localip",formatIP(WiFi.localIP()).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname,"$localip",formatIP(NetworkLocalIP()).c_str(),errorCounter); // $mac Device → Controller Mac address of the device network interface. The format MUST be of the type A1:B2:C3:D4:E5:F6 Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$mac",WiFi.macAddress().c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname,"$mac",NetworkMacAddress().c_str(),errorCounter); // $implementation Device → Controller An identifier for the Homie implementation (example esp8266) Yes Yes #if defined(ESP8266) @@ -533,7 +532,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& taskIndex_t taskIndex = INVALID_TASK_INDEX; struct EventStruct TempEvent; TempEvent.TaskIndex = event->TaskIndex; - TempEvent.Source = VALUE_SOURCE_MQTT; // to trigger the correct acknowledgment + TempEvent.Source = EventValueSource::Enum::VALUE_SOURCE_MQTT; // to trigger the correct acknowledgment int lastindex = event->String1.lastIndexOf('/'); errorCounter = 0; if (event->String1.substring(lastindex + 1) == F("set")) @@ -686,12 +685,9 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - if (!ControllerSettings.checkHostReachable(true)) { - success = false; - break; - } + String pubname = CPlugin_014_pubname; + bool mqtt_retainFlag = CPlugin_014_mqtt_retainFlag; + statusLED(true); if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { @@ -699,7 +695,6 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - String pubname = ControllerSettings.Publish; parseControllerVariables(pubname, event, false); String value = ""; @@ -708,9 +703,15 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& { String tmppubname = pubname; tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), ControllerSettings.mqtt_retainFlag()); + // Small optimization so we don't try to copy potentially large strings + if (event->sensorType == SENSOR_TYPE_STRING) { + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + value = event->String2.substring(0, 20); // For the log + } else { + value = formatUserVarNoCheck(event, x); + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + } if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("C014 : Sent to "); log += tmppubname; diff --git a/src/_C015.ino b/src/_C015.ino index ed64025a3..7d1ccca0e 100644 --- a/src/_C015.ino +++ b/src/_C015.ino @@ -212,7 +212,7 @@ bool do_process_c015_delay_queue(int controller_plugin_number, const C015_queue_ // controller has been disabled. Answer true to flush queue. return true; - if (!WiFiConnected()) { + if (!NetworkConnected()) { return false; } @@ -231,7 +231,7 @@ bool do_process_c015_delay_queue(int controller_plugin_number, const C015_queue_ boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct& ControllerSettings){ - if (!WiFiConnected()) + if (!NetworkConnected()) return false; if (!Blynk.connected()){ diff --git a/src/_C016.ino b/src/_C016.ino index b877e3bc6..56fb346c7 100644 --- a/src/_C016.ino +++ b/src/_C016.ino @@ -16,7 +16,7 @@ Typical sample sets contain: These are the result of any plugin sending data to this controller. The controller can save the samples from RTC memory to several places on the flash: -- Files on SPIFFS +- Files on FS - Part reserved for OTA update (TODO) - Unused flash after the partitioned space (TODO) @@ -49,7 +49,7 @@ bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesHost = false; Protocol[protocolCount].usesPort = false; Protocol[protocolCount].usesSampleSets = false; - Protocol[protocolCount].needsWiFi = false; + Protocol[protocolCount].needsNetwork = false; break; } diff --git a/src/_C017.ino b/src/_C017.ino index 8e9cf7190..a4282ee27 100644 --- a/src/_C017.ino +++ b/src/_C017.ino @@ -56,7 +56,8 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & { element.txt[x] = formatUserVarNoCheck(event, x); } - success = C017_DelayHandler.addToQueue(element); + // FIXME TD-er must define a proper move operator + success = C017_DelayHandler.addToQueue(C017_queue_element(element)); scheduleNextDelayQueue(TIMER_C017_DELAY_QUEUE, C017_DelayHandler.getNextScheduleTime()); break; } @@ -86,7 +87,7 @@ bool do_process_c017_delay_queue(int controller_number, const C017_queue_element if (valueCount == 0) return true; //exit if we don't have anything to send. - if (!WiFiConnected(10)) + if (!NetworkConnected(10)) { return false; } diff --git a/src/_C018.ino b/src/_C018.ino index 9e49ddc74..18dd98364 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -431,7 +431,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesCheckReply = false; Protocol[protocolCount].usesTimeout = false; Protocol[protocolCount].usesSampleSets = true; - Protocol[protocolCount].needsWiFi = false; + Protocol[protocolCount].needsNetwork = false; break; } diff --git a/src/_CPlugin_DomoticzHelper.ino b/src/_CPlugin_DomoticzHelper.ino index 1212d6b2e..161e610ed 100644 --- a/src/_CPlugin_DomoticzHelper.ino +++ b/src/_CPlugin_DomoticzHelper.ino @@ -1,4 +1,8 @@ #ifdef USES_DOMOTICZ + +#include "src/Helpers/Convert.h" + + // HUM_STAT can be one of: // 0=Normal diff --git a/src/_CPlugin_Helper.cpp b/src/_CPlugin_Helper.cpp index 43c8d2beb..3764deac6 100644 --- a/src/_CPlugin_Helper.cpp +++ b/src/_CPlugin_Helper.cpp @@ -272,12 +272,12 @@ bool count_connection_results(bool success, const String& prefix, int controller bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettingsStruct& ControllerSettings) { START_TIMER; - if (!WiFiConnected()) { return false; } + if (!NetworkConnected()) { return false; } client.setTimeout(ControllerSettings.ClientTimeout); #ifndef BUILD_NO_DEBUG log_connecting_to(F("UDP : "), controller_number, ControllerSettings); #endif // ifndef BUILD_NO_DEBUG - bool success = ControllerSettings.beginPacket(client) != 0; + bool success = ControllerSettings.beginPacket(client); const bool result = count_connection_results( success, F("UDP : "), controller_number, ControllerSettings); @@ -292,7 +292,7 @@ bool try_connect_host(int controller_number, WiFiClient& client, ControllerSetti bool try_connect_host(int controller_number, WiFiClient& client, ControllerSettingsStruct& ControllerSettings, const String& loglabel) { START_TIMER; - if (!WiFiConnected()) { return false; } + if (!NetworkConnected()) { return false; } // Use WiFiClient class to create TCP connections client.setTimeout(ControllerSettings.ClientTimeout); diff --git a/src/_CPlugin_Helper.h b/src/_CPlugin_Helper.h index 8bddf7a48..525db1efc 100644 --- a/src/_CPlugin_Helper.h +++ b/src/_CPlugin_Helper.h @@ -3,6 +3,8 @@ #include #include "src/Globals/CPlugins.h" +#include "src/Helpers/Numerical.h" +#include "src/Helpers/StringConverter.h" struct ControllerSettingsStruct; class WiFiUDP; diff --git a/src/_N001_Email.ino b/src/_N001_Email.ino index 0eadf8aee..2b73eead2 100644 --- a/src/_N001_Email.ino +++ b/src/_N001_Email.ino @@ -71,7 +71,7 @@ boolean NPlugin_001(NPlugin::Function function, struct EventStruct *event, Strin } -#ifndef NOTIFIER_SET_NONE +#ifdef USES_NOTIFIER boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg) { diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 6f963c708..c2cf32533 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -164,26 +164,30 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) globalMapPortStatus[key].previousTask = event->TaskIndex; } - String options[2]; - options[0] = F("Switch"); - options[1] = F("Dimmer"); - int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER }; - const byte switchtype = P001_getSwitchType(event); - addFormSelector(F("Switch Type"), F("p001_type"), 2, options, optionValues, switchtype); - - if (switchtype == PLUGIN_001_TYPE_DIMMER) { - addFormNumericBox(F("Dim value"), F("p001_dimvalue"), PCONFIG(1), 0, 255); + String options[2]; + options[0] = F("Switch"); + options[1] = F("Dimmer"); + int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER }; + const byte switchtype = P001_getSwitchType(event); + addFormSelector(F("Switch Type"), F("p001_type"), 2, options, optionValues, switchtype); + + if (switchtype == PLUGIN_001_TYPE_DIMMER) + { + addFormNumericBox(F("Dim value"), F("p001_dimvalue"), PCONFIG(1), 0, 255); + } } - byte choice = PCONFIG(2); - String buttonOptions[3]; - buttonOptions[0] = F("Normal Switch"); - buttonOptions[1] = F("Push Button Active Low"); - buttonOptions[2] = F("Push Button Active High"); - int buttonOptionValues[3] = - { PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH }; - addFormSelector(F("Switch Button Type"), F("p001_button"), 3, buttonOptions, buttonOptionValues, choice); + { + byte choice = PCONFIG(2); + String buttonOptions[3]; + buttonOptions[0] = F("Normal Switch"); + buttonOptions[1] = F("Push Button Active Low"); + buttonOptions[2] = F("Push Button Active High"); + int buttonOptionValues[3] = + { PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH }; + addFormSelector(F("Switch Button Type"), F("p001_button"), 3, buttonOptions, buttonOptionValues, choice); + } addFormCheckBox(F("Send Boot state"), F("p001_boot"), PCONFIG(3)); @@ -197,15 +201,17 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) PCONFIG_FLOAT(1) = PLUGIN_001_DOUBLECLICK_MIN_INTERVAL; } - byte choiceDC = PCONFIG(4); - String buttonDC[4]; - buttonDC[0] = F("Disabled"); - buttonDC[1] = F("Active only on LOW (EVENT=3)"); - buttonDC[2] = F("Active only on HIGH (EVENT=3)"); - buttonDC[3] = F("Active on LOW & HIGH (EVENT=3)"); - int buttonDCValues[4] = { PLUGIN_001_DC_DISABLED, PLUGIN_001_DC_LOW, PLUGIN_001_DC_HIGH, PLUGIN_001_DC_BOTH }; + { + byte choiceDC = PCONFIG(4); + String buttonDC[4]; + buttonDC[0] = F("Disabled"); + buttonDC[1] = F("Active only on LOW (EVENT=3)"); + buttonDC[2] = F("Active only on HIGH (EVENT=3)"); + buttonDC[3] = F("Active on LOW & HIGH (EVENT=3)"); + int buttonDCValues[4] = { PLUGIN_001_DC_DISABLED, PLUGIN_001_DC_LOW, PLUGIN_001_DC_HIGH, PLUGIN_001_DC_BOTH }; - addFormSelector(F("Doubleclick event"), F("p001_dc"), 4, buttonDC, buttonDCValues, choiceDC); + addFormSelector(F("Doubleclick event"), F("p001_dc"), 4, buttonDC, buttonDCValues, choiceDC); + } addFormNumericBox(F("Doubleclick max. interval (ms)"), F("p001_dcmaxinterval"), @@ -218,15 +224,17 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) PCONFIG_FLOAT(2) = PLUGIN_001_LONGPRESS_MIN_INTERVAL; } - byte choiceLP = PCONFIG(5); - String buttonLP[4]; - buttonLP[0] = F("Disabled"); - buttonLP[1] = F("Active only on LOW (EVENT= 10 [NORMAL] or 11 [INVERSED])"); - buttonLP[2] = F("Active only on HIGH (EVENT= 11 [NORMAL] or 10 [INVERSED])"); - buttonLP[3] = F("Active on LOW & HIGH (EVENT= 10 or 11)"); - int buttonLPValues[4] = - { PLUGIN_001_LONGPRESS_DISABLED, PLUGIN_001_LONGPRESS_LOW, PLUGIN_001_LONGPRESS_HIGH, PLUGIN_001_LONGPRESS_BOTH }; - addFormSelector(F("Longpress event"), F("p001_lp"), 4, buttonLP, buttonLPValues, choiceLP); + { + byte choiceLP = PCONFIG(5); + String buttonLP[4]; + buttonLP[0] = F("Disabled"); + buttonLP[1] = F("Active only on LOW (EVENT= 10 [NORMAL] or 11 [INVERSED])"); + buttonLP[2] = F("Active only on HIGH (EVENT= 11 [NORMAL] or 10 [INVERSED])"); + buttonLP[3] = F("Active on LOW & HIGH (EVENT= 10 or 11)"); + int buttonLPValues[4] = + { PLUGIN_001_LONGPRESS_DISABLED, PLUGIN_001_LONGPRESS_LOW, PLUGIN_001_LONGPRESS_HIGH, PLUGIN_001_LONGPRESS_BOTH }; + addFormSelector(F("Longpress event"), F("p001_lp"), 4, buttonLP, buttonLPValues, choiceLP); + } addFormNumericBox(F("Longpress min. interval (ms)"), F("p001_lpmininterval"), diff --git a/src/_P008_RFID.ino b/src/_P008_RFID.ino index 8ceda3f2e..0f9045214 100644 --- a/src/_P008_RFID.ino +++ b/src/_P008_RFID.ino @@ -73,6 +73,19 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string) break; } + case PLUGIN_TIMER_IN: + { + if (Plugin_008_init) { + // Reset card id on timeout + UserVar[event->BaseVarIndex] = 0; + UserVar[event->BaseVarIndex + 1] = 0; + addLog(LOG_LEVEL_INFO, F("RFID : Removed Tag")); + sendData(event); + success = true; + } + break; + } + case PLUGIN_ONCE_A_SECOND: { if (Plugin_008_init) @@ -83,8 +96,6 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string) { // a number of keys were pressed and finished by # Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 4; // Strip # - UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); - UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); } else if (Plugin_008_bitCount == Plugin_008_WiegandSize) { @@ -94,8 +105,6 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string) Plugin_008_keyBuffer &= 0xFFFFFF; else Plugin_008_keyBuffer &= 0xFFFFFFFF; - UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); - UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); } else { @@ -113,10 +122,24 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string) } break; } + + unsigned long old_key = ((uint32_t) UserVar[event->BaseVarIndex]) | ((uint32_t) UserVar[event->BaseVarIndex + 1])<<16; + bool new_key = false; + + if (old_key != Plugin_008_keyBuffer) { + UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); + UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); + new_key = true; + } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - // write log - String log = F("RFID : Tag: "); + // write log + String log = F("RFID : "); + if (new_key) { + log += F("New Tag: "); + } else { + log += F("Old Tag: "); + } log += (unsigned long) Plugin_008_keyBuffer; log += F(" Bits: "); log += Plugin_008_bitCount; @@ -126,7 +149,9 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string) Plugin_008_keyBuffer = 0; Plugin_008_bitCount = 0; Plugin_008_timeoutCount = 0; - sendData(event); + + if (new_key) sendData(event); + setPluginTaskTimer(500, event->TaskIndex, event->Par1); } } break; diff --git a/src/_P012_LCD.ino b/src/_P012_LCD.ino index b1826720e..382c09809 100644 --- a/src/_P012_LCD.ino +++ b/src/_P012_LCD.ino @@ -117,6 +117,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string) PCONFIG(2) = getFormItemInt(F("p012_timer")); PCONFIG(3) = getFormItemInt(F("p012_mode")); + // FIXME TD-er: This is a huge stack allocated object. char deviceTemplate[P12_Nlines][P12_Nchars]; String error; for (byte varNr = 0; varNr < P12_Nlines; varNr++) @@ -189,6 +190,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string) case PLUGIN_READ: { + // FIXME TD-er: This is a huge stack allocated object. char deviceTemplate[P12_Nlines][P12_Nchars]; LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); diff --git a/src/_P017_PN532.ino b/src/_P017_PN532.ino index e67ef4ad5..402df7c5e 100644 --- a/src/_P017_PN532.ino +++ b/src/_P017_PN532.ino @@ -71,7 +71,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { // FIXME TD-er: Why is this using pin3 and not pin1? And why isn't this using the normal pin selection functions? - addFormPinSelect(F("Reset Pin"), F("taskdevicepin3"), CONFIG_PIN3); + addFormPinSelect(F("Reset Pin"), F("taskdevicepin3"), CONFIG_PIN3); success = true; break; } @@ -92,6 +92,17 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string) break; } + case PLUGIN_TIMER_IN: + { + // Reset card id on timeout + UserVar[event->BaseVarIndex] = 0; + UserVar[event->BaseVarIndex + 1] = 0; + addLog(LOG_LEVEL_INFO, F("RFID : Removed Tag")); + sendData(event); + success = true; + break; + } + case PLUGIN_TEN_PER_SECOND: { static unsigned long tempcounter = 0; @@ -101,7 +112,9 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string) counter++; if (counter == 3 ) { - if (digitalRead(4) == 0 || digitalRead(5) == 0) + // TODO: Clock stretching issue https://github.com/esp8266/Arduino/issues/1541 + if (Settings.Pin_i2c_sda >= 0 && Settings.Pin_i2c_scl>= 0 + && (digitalRead(Settings.Pin_i2c_sda)==0 || digitalRead(Settings.Pin_i2c_scl)==0)) { addLog(LOG_LEVEL_ERROR, F("PN532: BUS error")); Plugin_017_Init(CONFIG_PIN3); @@ -134,15 +147,30 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string) key <<= 8; key += uid[i]; } - UserVar[event->BaseVarIndex] = (key & 0xFFFF); - UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); - String log = F("PN532: Tag: "); - log += key; - tempcounter++; - log += ' '; - log += tempcounter; - addLog(LOG_LEVEL_INFO, log); - sendData(event); + unsigned long old_key = ((uint32_t) UserVar[event->BaseVarIndex]) | ((uint32_t) UserVar[event->BaseVarIndex + 1])<<16; + bool new_key = false; + if (old_key != key) { + UserVar[event->BaseVarIndex] = (key & 0xFFFF); + UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); + new_key = true; + } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("PN532: "); + if (new_key) { + log += F("New Tag: "); + } else { + log += F("Old Tag: "); + } + log += key; + tempcounter++; + log += ' '; + log += tempcounter; + addLog(LOG_LEVEL_INFO, log); + } + + if (new_key) sendData(event); + setPluginTaskTimer(500, event->TaskIndex, event->Par1); } } break; diff --git a/src/_P023_OLED.ino b/src/_P023_OLED.ino index ebd2e0c2e..bc24a92b6 100644 --- a/src/_P023_OLED.ino +++ b/src/_P023_OLED.ino @@ -129,6 +129,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string) PCONFIG(3) = getFormItemInt(F("p023_size")); PCONFIG(4) = getFormItemInt(F("p023_font_width")); + // FIXME TD-er: This is a huge stack allocated object. char deviceTemplate[P23_Nlines][P23_Nchars]; String error; for (byte varNr = 0; varNr < P23_Nlines; varNr++) diff --git a/src/_P025_ADS1115.ino b/src/_P025_ADS1115.ino index 8072f86ab..ba2ef1d87 100644 --- a/src/_P025_ADS1115.ino +++ b/src/_P025_ADS1115.ino @@ -66,38 +66,44 @@ boolean Plugin_025(byte function, struct EventStruct *event, String& string) CONFIG_PORT = 0; } - #define ADS1115_I2C_OPTION 4 - byte addr = PCONFIG(0); - int optionValues[ADS1115_I2C_OPTION] = { 0x48, 0x49, 0x4A, 0x4B }; - addFormSelectorI2C(F("p025_i2c"), ADS1115_I2C_OPTION, optionValues, addr); + { + #define ADS1115_I2C_OPTION 4 + byte addr = PCONFIG(0); + int optionValues[ADS1115_I2C_OPTION] = { 0x48, 0x49, 0x4A, 0x4B }; + addFormSelectorI2C(F("p025_i2c"), ADS1115_I2C_OPTION, optionValues, addr); + } addFormSubHeader(F("Input")); - #define ADS1115_PGA_OPTION 6 - byte pga = PCONFIG(1); - String pgaOptions[ADS1115_PGA_OPTION] = { - F("2/3x gain (FS=6.144V)"), - F("1x gain (FS=4.096V)"), - F("2x gain (FS=2.048V)"), - F("4x gain (FS=1.024V)"), - F("8x gain (FS=0.512V)"), - F("16x gain (FS=0.256V)") - }; - addFormSelector(F("Gain"), F("p025_gain"), ADS1115_PGA_OPTION, pgaOptions, NULL, pga); + { + #define ADS1115_PGA_OPTION 6 + byte pga = PCONFIG(1); + String pgaOptions[ADS1115_PGA_OPTION] = { + F("2/3x gain (FS=6.144V)"), + F("1x gain (FS=4.096V)"), + F("2x gain (FS=2.048V)"), + F("4x gain (FS=1.024V)"), + F("8x gain (FS=0.512V)"), + F("16x gain (FS=0.256V)") + }; + addFormSelector(F("Gain"), F("p025_gain"), ADS1115_PGA_OPTION, pgaOptions, NULL, pga); + } - #define ADS1115_MUX_OPTION 8 - byte mux = PCONFIG(2); - String muxOptions[ADS1115_MUX_OPTION] = { - F("AIN0 - AIN1 (Differential)"), - F("AIN0 - AIN3 (Differential)"), - F("AIN1 - AIN3 (Differential)"), - F("AIN2 - AIN3 (Differential)"), - F("AIN0 - GND (Single-Ended)"), - F("AIN1 - GND (Single-Ended)"), - F("AIN2 - GND (Single-Ended)"), - F("AIN3 - GND (Single-Ended)"), - }; - addFormSelector(F("Input Multiplexer"), F("p025_mode"), ADS1115_MUX_OPTION, muxOptions, NULL, mux); + { + #define ADS1115_MUX_OPTION 8 + byte mux = PCONFIG(2); + String muxOptions[ADS1115_MUX_OPTION] = { + F("AIN0 - AIN1 (Differential)"), + F("AIN0 - AIN3 (Differential)"), + F("AIN1 - AIN3 (Differential)"), + F("AIN2 - AIN3 (Differential)"), + F("AIN0 - GND (Single-Ended)"), + F("AIN1 - GND (Single-Ended)"), + F("AIN2 - GND (Single-Ended)"), + F("AIN3 - GND (Single-Ended)"), + }; + addFormSelector(F("Input Multiplexer"), F("p025_mode"), ADS1115_MUX_OPTION, muxOptions, NULL, mux); + } addFormSubHeader(F("Two Point Calibration")); diff --git a/src/_P026_Sysinfo.ino b/src/_P026_Sysinfo.ino index 33ed4424b..d1f60864b 100644 --- a/src/_P026_Sysinfo.ino +++ b/src/_P026_Sysinfo.ino @@ -212,22 +212,22 @@ float P026_get_value(int type) } case 5: { - value = WiFi.localIP()[0]; + value = NetworkLocalIP()[0]; break; } case 6: { - value = WiFi.localIP()[1]; + value = NetworkLocalIP()[1]; break; } case 7: { - value = WiFi.localIP()[2]; + value = NetworkLocalIP()[2]; break; } case 8: { - value = WiFi.localIP()[3]; + value = NetworkLocalIP()[3]; break; } case 9: diff --git a/src/_P027_INA219.ino b/src/_P027_INA219.ino index e1571209b..9ba564a3d 100644 --- a/src/_P027_INA219.ino +++ b/src/_P027_INA219.ino @@ -76,7 +76,6 @@ typedef struct { } ina219_data; ina219_data _ina219_data[4]; -int Plugin_27_i2c_addresses[4] = { INA219_ADDRESS, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; uint8_t Plugin_027_i2c_addr(struct EventStruct *event) { return (uint8_t)PCONFIG(1); @@ -131,22 +130,27 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { - byte choiceMode = PCONFIG(0); - String optionsMode[3]; - optionsMode[0] = F("32V, 2A"); - optionsMode[1] = F("32V, 1A"); - optionsMode[2] = F("16V, 0.4A"); - int optionValuesMode[3]; - optionValuesMode[0] = 0; - optionValuesMode[1] = 1; - optionValuesMode[2] = 2; - addFormSelector(F("Measure range"), F("p027_range"), 3, optionsMode, optionValuesMode, choiceMode); - - addFormSelectorI2C(F("p027_i2c"), 4, Plugin_27_i2c_addresses, Plugin_027_i2c_addr(event)); - - byte choiceMeasureType = PCONFIG(2); - String options[4] = { F("Voltage"), F("Current"), F("Power"), F("Voltage/Current/Power") }; - addFormSelector(F("Measurement Type"), F("p027_measuretype"), 4, options, NULL, choiceMeasureType ); + { + byte choiceMode = PCONFIG(0); + String optionsMode[3]; + optionsMode[0] = F("32V, 2A"); + optionsMode[1] = F("32V, 1A"); + optionsMode[2] = F("16V, 0.4A"); + int optionValuesMode[3]; + optionValuesMode[0] = 0; + optionValuesMode[1] = 1; + optionValuesMode[2] = 2; + addFormSelector(F("Measure range"), F("p027_range"), 3, optionsMode, optionValuesMode, choiceMode); + } + { + int Plugin_27_i2c_addresses[4] = { INA219_ADDRESS, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; + addFormSelectorI2C(F("p027_i2c"), 4, Plugin_27_i2c_addresses, Plugin_027_i2c_addr(event)); + } + { + byte choiceMeasureType = PCONFIG(2); + String options[4] = { F("Voltage"), F("Current"), F("Power"), F("Voltage/Current/Power") }; + addFormSelector(F("Measurement Type"), F("p027_measuretype"), 4, options, NULL, choiceMeasureType ); + } success = true; break; diff --git a/src/_P033_Dummy.ino b/src/_P033_Dummy.ino index 6db1ed13c..4d402dc8a 100644 --- a/src/_P033_Dummy.ino +++ b/src/_P033_Dummy.ino @@ -41,6 +41,7 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string) case PLUGIN_GET_DEVICEVALUENAMES: { + // FIXME TD-er: Copy names as done in P026_Sysinfo.ino. strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_033)); break; } diff --git a/src/_P036_FrameOLED.ino b/src/_P036_FrameOLED.ino index 37c59c5a8..c0c90d3a4 100644 --- a/src/_P036_FrameOLED.ino +++ b/src/_P036_FrameOLED.ino @@ -864,7 +864,7 @@ void display_header() { } switch (_HeaderContent) { case eSSID: - if (WiFiConnected()) { + if (NetworkConnected()) { strHeader = WiFi.SSID(); } else { @@ -1341,7 +1341,7 @@ void display_scrolling_lines(int nlines) { //Draw Signal Strength Bars, return true when there was an update. bool display_wifibars() { - const bool connected = WiFiConnected(); + const bool connected = NetworkConnected(); const int nbars_filled = (WiFi.RSSI() + 100) / 12; // all bars filled if RSSI better than -46dB const int newState = connected ? nbars_filled : P36_WIFI_STATE_NOT_CONNECTED; if (newState == lastWiFiState) @@ -1363,7 +1363,7 @@ bool display_wifibars() { display->setColor(BLACK); display->fillRect(x , y, size_x, size_y); display->setColor(WHITE); - if (WiFiConnected()) { + if (NetworkConnected()) { for (uint8_t ibar = 0; ibar < nbars; ibar++) { int16_t height = size_y * (ibar + 1) / nbars; int16_t xpos = x + ibar * width; diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index 594ca60ab..9ae62f2fa 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -377,19 +377,17 @@ void mqttcallback_037(char* c_topic, byte* b_payload, unsigned int length) return; } - // We generate a temp event structure to pass to the plugins - - struct EventStruct TempEvent; - - TempEvent.String1 = topic; // This is the topic of the message - TempEvent.String2 = payload; // This is the payload - // Here we loop over all tasks and call each 037 plugin with function PLUGIN_IMPORT for (taskIndex_t y = 0; y < TASKS_MAX; y++) { if (Settings.TaskDeviceNumber[y] == PLUGIN_ID_037) // if we have found a 037 device, then give it something to think about! { + // We generate a temp event structure to pass to the plugins + struct EventStruct TempEvent; + + TempEvent.String1 = topic; // This is the topic of the message + TempEvent.String2 = payload; // This is the payload TempEvent.TaskIndex = y; LoadTaskSettings(TempEvent.TaskIndex); TempEvent.BaseVarIndex = y * VARS_PER_TASK; // This is the index in Uservar where values for this task are stored @@ -418,11 +416,16 @@ boolean MQTTConnect_037() if (MQTTclient_037->connected()) return true; // define stuff for the client - this could also be done in the intial declaration of MQTTclient_037 - if (!WiFiConnected(100)) { + if (!NetworkConnected(100)) { Plugin_037_update_connect_status(); return false; // Not connected, so no use in wasting time to connect to a host. } MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("IMPT : Cannot load controller settings, out of RAM")); + return false; + } + LoadControllerSettings(enabledMqttController, ControllerSettings); if (ControllerSettings.UseDNS) { MQTTclient_037->setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port); diff --git a/src/_P040_ID12.ino b/src/_P040_ID12.ino index b4c67b7ae..ea966cb48 100644 --- a/src/_P040_ID12.ino +++ b/src/_P040_ID12.ino @@ -139,12 +139,11 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string) unsigned long key = 0, old_key = 0; old_key = ((uint32_t) UserVar[event->BaseVarIndex]) | ((uint32_t) UserVar[event->BaseVarIndex + 1])<<16; for (byte i = 1; i < 5; i++) key = key | (((unsigned long) code[i] << ((4 - i) * 8))); - bool new_key = false; + bool new_key = false; if (old_key != key) { UserVar[event->BaseVarIndex] = (key & 0xFFFF); UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); new_key = true; - sendData(event); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -157,6 +156,8 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string) log += key; addLog(LOG_LEVEL_INFO, log); } + + if (new_key) sendData(event); setPluginTaskTimer(500, event->TaskIndex, event->Par1); } } diff --git a/src/_P042_Candle.ino b/src/_P042_Candle.ino index eae112b43..2c1014baa 100644 --- a/src/_P042_Candle.ino +++ b/src/_P042_Candle.ino @@ -144,27 +144,28 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string) { addHtml(F("\n")); - char tmpString[128]; - String options[8]; - // int optionValues[8]; - - options[0] = F("Off"); - options[1] = F("Static Light"); - options[2] = F("Simple Candle"); - options[3] = F("Advanced Candle"); - options[4] = F("Police"); - options[5] = F("Blink"); - options[6] = F("Strobe"); - options[7] = F("Color Fader"); - - byte choice = PCONFIG(4); - if (choice > sizeof(options) - 1) { - choice = 2; - } + String options[8]; + // int optionValues[8]; - // Candle Type Selection - addFormSelector(F("Flame Type"), F("web_Candle_Type"), 8, options, NULL, choice); + options[0] = F("Off"); + options[1] = F("Static Light"); + options[2] = F("Simple Candle"); + options[3] = F("Advanced Candle"); + options[4] = F("Police"); + options[5] = F("Blink"); + options[6] = F("Strobe"); + options[7] = F("Color Fader"); + + byte choice = PCONFIG(4); + if (choice > sizeof(options) - 1) + { + choice = 2; + } + + // Candle Type Selection + addFormSelector(F("Flame Type"), F("web_Candle_Type"), 8, options, NULL, choice); + } // Advanced Color options Candle_color = (ColorType)PCONFIG(5); @@ -204,8 +205,11 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string) addHtml(String(PCONFIG(3))); addHtml(F("'> max")); - sprintf_P(tmpString, PSTR("Brightness Value:"), PCONFIG(3)); - addHtml(tmpString); + { + char tmpString[128]; + sprintf_P(tmpString, PSTR("Brightness Value:"), PCONFIG(3)); + addHtml(tmpString); + } // Some Javascript we need to update the items addHtml(F("" + "} " }; static const char jsClipboardCopyPart1[] PROGMEM = { @@ -119,15 +118,38 @@ static const char jsClipboardCopyPart3[] PROGMEM = { static const char jsSaveRules[] PROGMEM = { - "function saveRulesFile(){document.getElementById(\"save_button\");" - "let e=document.getElementById(\"size\"),t=document.getElementById(\"rules\").value;" - "t=t.replace(/\\r?\\n/g,\"\\r\\n\");" - "let n=document.getElementById(\"set\").value,l=new File([t],\"rules\"+n+\".txt\",{type:\"text/plain\"}),a=new FormData;" - "a.append(\"file\",l),a.append(\"enctype\",\"multipart/form-data\");" - "let o=\"/rules\"+n+\".txt?callback=\"+Date.now();" - "fetch(o).then(e=>e.text()).then(l=>{if(t===l)console.log(\"nothing to save...\");" - "else{fetch(\"/upload\",{method:\"POST\",body:a}).then(e=>e.text()).then(l=>{let a=\"/rules\"+n+\".txt?callback=\"+Date.now();" - "fetch(a).then(e=>e.text()).then(n=>{t===n?(toasting(),e.innerHTML=t.length):console.log(\"error when saving...\")})})}})}" +"function saveRulesFile() {" +"\"use strict\";" +"let e = document.getElementById(\"size\");" +"let t = document.getElementById(\"rules\").value;" +"t = t.replace(/\\r?\\n/g, \"\\r\\n\");" +"let n = document.getElementById(\"set\").value;" +"let l = new File([t],\"rules\" + n + \".txt\",{" +"type: \"text/plain\"" +"});" +"let a = new FormData();" +"a.append(\"file\", l);" +"a.append(\"enctype\", \"multipart/form-data\");" +"let o = \"/rules\" + n + \".txt?callback=\" + Date.now();" +"fetch(o).then(e=>e.text()).then(l=>{" +"if (t === l)" +"console.log(\"nothing to save...\");" +"else {" +"fetch(\"/upload\", {" +"method: \"POST\"," +"body: a" +"}).then(e=>e.text()).then(l=>{" +"let a = \"/rules\" + n + \".txt?callback=\" + Date.now();" +"fetch(a).then(e=>e.text()).then(n=>{" +"if (t === n) {" +"toasting();" +"e.innerHTML = t.length;" +"} else {" +"console.log(\"error when saving...\");" +"}});" +"});" +"}});" +"}" }; static const char DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS[] PROGMEM = {0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x73,0x29,0x7b,0x76,0x61,0x72,0x20,0x61,0x2c,0x6c,0x2c,0x6f,0x3d,0x30,0x3b,0x69,0x73,0x4e,0x61,0x4e,0x28,0x73,0x29,0x26,0x26,0x28,0x73,0x3d,0x31,0x29,0x2c,0x6e,0x75,0x6c,0x6c,0x3d,0x3d,0x65,0x26,0x26,0x28,0x65,0x3d,0x31,0x65,0x33,0x29,0x3b,0x76,0x61,0x72,0x20,0x6e,0x3d,0x73,0x65,0x74,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x29,0x7b,0x6f,0x3e,0x30,0x3f,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x3a,0x2b,0x2b,0x73,0x3e,0x31,0x3f,0x6f,0x3d,0x31,0x3a,0x28,0x66,0x65,0x74,0x63,0x68,0x28,0x22,0x2f,0x6a,0x73,0x6f,0x6e,0x3f,0x76,0x69,0x65,0x77,0x3d,0x73,0x65,0x6e,0x73,0x6f,0x72,0x75,0x70,0x64,0x61,0x74,0x65,0x22,0x29,0x2e,0x74,0x68,0x65,0x6e,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x76,0x61,0x72,0x20,0x6f,0x3b,0x32,0x30,0x30,0x3d,0x3d,0x3d,0x73,0x2e,0x73,0x74,0x61,0x74,0x75,0x73,0x3f,0x73,0x2e,0x6a,0x73,0x6f,0x6e,0x28,0x29,0x2e,0x74,0x68,0x65,0x6e,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x66,0x6f,0x72,0x28,0x65,0x3d,0x73,0x2e,0x54,0x54,0x4c,0x2c,0x61,0x3d,0x30,0x3b,0x61,0x3c,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x2e,0x6c,0x65,0x6e,0x67,0x74,0x68,0x3b,0x61,0x2b,0x2b,0x29,0x69,0x66,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x68,0x61,0x73,0x4f,0x77,0x6e,0x50,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x28,0x22,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x22,0x29,0x29,0x66,0x6f,0x72,0x28,0x6c,0x3d,0x30,0x3b,0x6c,0x3c,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x2e,0x6c,0x65,0x6e,0x67,0x74,0x68,0x3b,0x6c,0x2b,0x2b,0x29,0x74,0x72,0x79,0x7b,0x6f,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x7d,0x63,0x61,0x74,0x63,0x68,0x28,0x65,0x29,0x7b,0x6f,0x3d,0x65,0x2e,0x6e,0x61,0x6d,0x65,0x7d,0x66,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x7b,0x69,0x66,0x28,0x22,0x54,0x79,0x70,0x65,0x45,0x72,0x72,0x6f,0x72,0x22,0x21,0x3d,0x3d,0x6f,0x29,0x7b,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x2c,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x56,0x61,0x6c,0x75,0x65,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x4e,0x72,0x44,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x2c,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x3d,0x70,0x61,0x72,0x73,0x65,0x46,0x6c,0x6f,0x61,0x74,0x28,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x29,0x2e,0x74,0x6f,0x46,0x69,0x78,0x65,0x64,0x28,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0x76,0x61,0x72,0x20,0x72,0x3d,0x22,0x76,0x61,0x6c,0x75,0x65,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2b,0x22,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2c,0x74,0x3d,0x22,0x76,0x61,0x6c,0x75,0x65,0x6e,0x61,0x6d,0x65,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2b,0x22,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2c,0x75,0x3d,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x72,0x29,0x2c,0x63,0x3d,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x74,0x29,0x3b,0x6e,0x75,0x6c,0x6c,0x21,0x3d,0x3d,0x75,0x26,0x26,0x28,0x75,0x2e,0x69,0x6e,0x6e,0x65,0x72,0x48,0x54,0x4d,0x4c,0x3d,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x29,0x2c,0x6e,0x75,0x6c,0x6c,0x21,0x3d,0x3d,0x63,0x26,0x26,0x28,0x63,0x2e,0x69,0x6e,0x6e,0x65,0x72,0x48,0x54,0x4d,0x4c,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x4e,0x61,0x6d,0x65,0x2b,0x22,0x3a,0x22,0x29,0x7d,0x7d,0x65,0x3d,0x73,0x2e,0x54,0x54,0x4c,0x2c,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x2c,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x30,0x29,0x7d,0x29,0x3a,0x63,0x6f,0x6e,0x73,0x6f,0x6c,0x65,0x2e,0x6c,0x6f,0x67,0x28,0x22,0x4c,0x6f,0x6f,0x6b,0x73,0x20,0x6c,0x69,0x6b,0x65,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x77,0x61,0x73,0x20,0x61,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0x2e,0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x20,0x43,0x6f,0x64,0x65,0x3a,0x20,0x22,0x2b,0x73,0x2e,0x73,0x74,0x61,0x74,0x75,0x73,0x29,0x7d,0x29,0x2e,0x63,0x61,0x74,0x63,0x68,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x63,0x6f,0x6e,0x73,0x6f,0x6c,0x65,0x2e,0x6c,0x6f,0x67,0x28,0x73,0x2e,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x29,0x2c,0x65,0x3d,0x35,0x65,0x33,0x2c,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x2c,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x30,0x29,0x7d,0x29,0x2c,0x6f,0x3d,0x31,0x29,0x7d,0x2c,0x65,0x29,0x7d,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x31,0x65,0x33,0x2c,0x30,0x29,0x3b, 0}; diff --git a/tools/pio/generate-compiletime-defines.py b/tools/pio/generate-compiletime-defines.py index bcfc89ad0..1e07c0fc6 100644 --- a/tools/pio/generate-compiletime-defines.py +++ b/tools/pio/generate-compiletime-defines.py @@ -4,7 +4,6 @@ import os import platform import shutil from datetime import date -from pygit2 import Repository import json @@ -15,7 +14,23 @@ def create_binary_filename(): def get_git_description(): - return Repository('.').head.shorthand + try: + from pygit2 import Repository + try: + return Repository('.').head.shorthand + except: + return 'No_.git_dir' + except ImportError: + return 'pygit2_not_installed' + + +def deduct_flags_from_pioenv(): + fs_str = "SPIFFS" + if "LittleFS" in env["PIOENV"]: + fs_str = "LittleFS" + env.Append(CPPDEFINES=[ + "USE_LITTLEFS"]) + print("\u001b[33m File System: \u001b[0m {}".format(fs_str)) # needed to wrap in a number of double quotes. @@ -53,11 +68,11 @@ def gen_compiletime_defines(node): CCFLAGS=env["CCFLAGS"] ) - #return node +print("\u001b[32m Compile time defines \u001b[0m") +deduct_flags_from_pioenv() # Set the binary filename in the environment to be used in other build steps env.Replace(PROGNAME=create_binary_filename()) -print("\u001b[32m Compile time defines \u001b[0m") print("\u001b[33m PROGNAME: \u001b[0m {}".format(env['PROGNAME'])) print("\u001b[33m BUILD_PLATFORM: \u001b[0m {}".format(platform.platform())) print("\u001b[33m GIT_HEAD: \u001b[0m {}".format(get_git_description())) diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 52f93239e..7f6b4ed02 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -25,17 +25,21 @@ else: "USES_P001", # Switch "USES_P002", # ADC "USES_P004", # Dallas DS18b20 + "USES_P027", # INA219 "USES_P028", # BME280 "USES_P036", # FrameOLED + "USES_P045", # MPU6050 "USES_P049", # MHZ19 "USES_P052", # SenseAir "USES_P056", # SDS011-Dust "USES_P059", # Encoder + "USES_P081", # Cron "USES_P082", # GPS "USES_P087", # Serial Proxy "USES_P097", # Touch (ESP32) - "USE_SETTINGS_ARCHIVE" + "USE_SETTINGS_ARCHIVE", + "FEATURE_ARDUINO_OTA" ]) print(env['CPPDEFINES']) diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index bebeda382..6e5ca9290 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -26,15 +26,17 @@ else: "USES_P001", # Switch "USES_P002", # ADC "USES_P004", # Dallas DS18b20 + "USES_P027", # INA219 "USES_P028", # BME280 "USES_P036", # FrameOLED + "USES_P045", # MPU6050 "USES_P049", # MHZ19 "USES_P052", # SenseAir "USES_P056", # SDS011-Dust "USES_P059", # Encoder "USES_P081", # Cron "USES_P082", # GPS -# "USES_P085", # AcuDC24x + "USES_P085", # AcuDC24x # "USES_P087", # Serial Proxy # "USES_P094", # CUL Reader # "USES_P095", # TFT ILI9341 diff --git a/tools/vagrant/Vagrantfile b/tools/vagrant/Vagrantfile index 28f97fb00..20d8b4fee 100644 --- a/tools/vagrant/Vagrantfile +++ b/tools/vagrant/Vagrantfile @@ -17,6 +17,8 @@ Vagrant.configure("2") do |config| # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = "bento/ubuntu-18.04" + # TD-er: No hyperv version for "bento/ubuntu-20.04" available yet. + #config.vm.box = "bento/ubuntu-20.04" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs @@ -69,7 +71,7 @@ Vagrant.configure("2") do |config| # documentation for more information about their specific syntax and use. config.vm.provision "shell", inline: <<-SHELL apt-get update - apt-get install -y python-minimal virtualenv build-essential zip binutils software-properties-common + apt-get install -y python3-minimal virtualenv build-essential zip binutils software-properties-common apt-get update DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade add-apt-repository ppa:deadsnakes/ppa diff --git a/tools/vagrant/bootstrap.sh b/tools/vagrant/bootstrap.sh index b60b003f2..0c545fad3 100644 --- a/tools/vagrant/bootstrap.sh +++ b/tools/vagrant/bootstrap.sh @@ -41,9 +41,9 @@ fi # Activate Python virtual environment and install/upgrade packages source ${VENV}/bin/activate -pip install -U platformio #pip install -r ${SRC}/docs/requirements.txt - +pip install -r ${SRC}/requirements.txt +pip install -U platformio # Update platformio cd ${SRC}