mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
107
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d894d7c83 | ||
|
|
024ec7b727 | ||
|
|
1ff0141e38 | ||
|
|
125db8046b | ||
|
|
720317c829 | ||
|
|
bbe9005a32 | ||
|
|
afa16e80b6 | ||
|
|
37f5c92aa7 | ||
|
|
684b89ae4c | ||
|
|
8c4612c300 | ||
|
|
0afab53659 | ||
|
|
e6e98345fe | ||
|
|
2394e4a75f | ||
|
|
e1c4691325 | ||
|
|
3f84c35014 | ||
|
|
bc0bafa96b | ||
|
|
4e7e66822d | ||
|
|
6f226e6d65 | ||
|
|
a50a035238 | ||
|
|
d560c635f5 | ||
|
|
f8db0c0a05 | ||
|
|
79616022df | ||
|
|
559d294607 | ||
|
|
d2588c5e01 | ||
|
|
ba45a51576 | ||
|
|
8321caaeed | ||
|
|
b35ed7d809 | ||
|
|
a4583d150e | ||
|
|
cadc0a885d | ||
|
|
061eb20ae5 | ||
|
|
9a9799eee7 | ||
|
|
f4615bb76b | ||
|
|
ecc498c359 | ||
|
|
e0e10fa6c8 | ||
|
|
228f09f394 | ||
|
|
19ac19778b | ||
|
|
5e2d517ba2 | ||
|
|
7a4b17983e | ||
|
|
6eba74ccc1 | ||
|
|
27a05b674c | ||
|
|
4a66bbf081 | ||
|
|
109bddb5c3 | ||
|
|
8158a919d8 | ||
|
|
706b91168b | ||
|
|
d047999c5e | ||
|
|
42f361aacd | ||
|
|
3dd076cf25 | ||
|
|
c0d155dd99 | ||
|
|
c433174d71 | ||
|
|
b805b59baf | ||
|
|
9fae0477d8 | ||
|
|
f7ac04dc96 | ||
|
|
d50e661efb | ||
|
|
57b5338af6 | ||
|
|
bd035c8f81 | ||
|
|
ac63d93e1a | ||
|
|
4cff0d0e02 | ||
|
|
ca83983fd2 | ||
|
|
d808f7e79b | ||
|
|
e469350ad9 | ||
|
|
60536b1a93 | ||
|
|
b9e45bd515 | ||
|
|
a0992b8383 | ||
|
|
9315581858 | ||
|
|
9a763303ca | ||
|
|
7df9379f47 | ||
|
|
c32fe50521 | ||
|
|
e4569b26f7 | ||
|
|
48998886fe | ||
|
|
36f97d7909 | ||
|
|
0e3b9c9e47 | ||
|
|
acecff4108 | ||
|
|
3322b954a7 | ||
|
|
4c4b844a4d | ||
|
|
cf4d28eb4f | ||
|
|
555b5386ae | ||
|
|
1903fdc7f2 | ||
|
|
918353461e | ||
|
|
e648a20fd0 | ||
|
|
1d7ea5e129 | ||
|
|
6ce5240dd7 | ||
|
|
692fb248ce | ||
|
|
5a87397ee0 | ||
|
|
99ba09b024 | ||
|
|
3dea091d21 | ||
|
|
ca13317cbd | ||
|
|
f68516d5bb | ||
|
|
8102a0096d | ||
|
|
73cec59bd5 | ||
|
|
96ecf9bf29 | ||
|
|
ef1e371514 | ||
|
|
45d67292a3 | ||
|
|
b5662baad4 | ||
|
|
12c3e5f81f | ||
|
|
dececf24ee | ||
|
|
3fb6dec382 | ||
|
|
cef962c5f1 | ||
|
|
cca2335070 | ||
|
|
ffd0d26ed3 | ||
|
|
9b457ed77b | ||
|
|
f787a9a9a6 | ||
|
|
a0ae104794 | ||
|
|
2b78810457 | ||
|
|
43081c3ac8 | ||
|
|
d3c86b9824 | ||
|
|
9621a91d90 | ||
|
|
0b9c550fd7 |
@@ -1,3 +1,25 @@
|
||||
### Checklist
|
||||
- [ ] The title of this issue is "to the point" and descriptive.
|
||||
- [ ] This issue describes what is happening.
|
||||
- [ ] This issue describes what components are affected (e.g. name of plugin/controller)
|
||||
- [ ] This issue describes how to reproduce it.
|
||||
- [ ] This issue describes when it was introduced (when known) and what version is now showing the problem.
|
||||
|
||||
### I have...
|
||||
- [ ] searched the [issue tracker](https://github.com/letscontrolit/ESPEasy/issues) or the [forum](https://www.letscontrolit.com/forum/viewforum.php?f=1) for a similar issue. (include links when applicable)
|
||||
- [ ] entered a system description using "Copy info to clipboard" on the sysinfo page. (when possible)
|
||||
- [ ] entered the full filename of the used version (e.g. `ESP_Easy_mega-20181001_test_ESP8266_4096_VCC.bin` )
|
||||
- [ ] given a list of active plugins or controllers when applicable.
|
||||
- [ ] filled out all applicable fields below.
|
||||
|
||||
### Steps already tried...
|
||||
- [ ] Tried a clean install (empty `.bin` files are included in the ZIP)
|
||||
- [ ] Tested previous/other build (mention which one already tested)
|
||||
- [ ] Tested on other node to make sure hardware isn't defective.
|
||||
- [ ] Verified if the problem is limited to a single plugin/controller
|
||||
|
||||
|
||||
|
||||
### If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! ###
|
||||
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
|
||||
<!--- NOTE: This is not a support forum! For questions and support go here: --->
|
||||
@@ -5,6 +27,7 @@
|
||||
<!--- Remove topics that are not applicable to your feature request of issue --->
|
||||
<!--- Remember to have a "to the point" TITLE --->
|
||||
|
||||
|
||||
### Summarize of the problem/feature request
|
||||
<!--- Describe the problem or feature request --->
|
||||
YOUR TEXT GOES HERE
|
||||
|
||||
@@ -22,3 +22,5 @@ test/output_export.cpp
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
docs/build/
|
||||
|
||||
+2
-1
@@ -22,9 +22,10 @@ addons:
|
||||
|
||||
|
||||
install:
|
||||
- pip install -U platformio
|
||||
- pip install -U platformio sphinx recommonmark sphinx_bootstrap_theme
|
||||
|
||||
script:
|
||||
# - bash ./preflight.sh # make sure input files are OK before wasting time with prereqs
|
||||
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
|
||||
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
|
||||
@@ -41,4 +41,6 @@ ESPEasy_mega-20180102_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stabl
|
||||
|
||||
Details and discussion are on the Experimental forum: https://www.letscontrolit.com/forum/viewforum.php?f=18
|
||||
|
||||
Automated builds of the (new) documentation can be found at [ESPEasy.readthedocs.io](https://espeasy.readthedocs.io/en/latest/)
|
||||
|
||||
We're also on IRC: #ESPEasy @freenode
|
||||
|
||||
+6
-2
@@ -35,10 +35,14 @@ done
|
||||
|
||||
|
||||
#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
|
||||
mkdir dist/Source
|
||||
#rm -rf dist/Source 2>/dev/null
|
||||
rm -rf dist/Docs 2>/dev/null
|
||||
|
||||
mkdir -p dist/Source
|
||||
#mkdir -p dist/Docs
|
||||
cp -r lib dist/Source/
|
||||
cp -r src dist/Source/
|
||||
#cp -r docs/build/ dist/Docs/
|
||||
cp platformio.ini dist/Source/
|
||||
|
||||
cd dist
|
||||
|
||||
Vendored
+181
@@ -1,3 +1,184 @@
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181022 (since mega-20181021)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 22 04:00:15 CEST 2018
|
||||
|
||||
TD-er (2):
|
||||
[Webserver] Generate copyText id names
|
||||
[Webserver] Uniform row labels to reduce flash string size
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181021 (since mega-20181020)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 21 04:00:16 CEST 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
fix for #1920 fix for out of sync, check both header bytes proper check for abnormal state
|
||||
Revert "fix for #1920"
|
||||
|
||||
TD-er (6):
|
||||
[stack usage] Allocate temp char array on heap for parsing arguments
|
||||
Proper look for connection.
|
||||
[Rules] Early exit on rules processing when rules not enabled
|
||||
[#1910] Notification settings extra strings on stack
|
||||
[#1891] Send all values for Generic UDP controller
|
||||
[#1870] Feature request build date as system info
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181020 (since mega-20181017)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Oct 20 04:00:16 CEST 2018
|
||||
|
||||
Plebs (22):
|
||||
Added [plugin#pcfgpio#pinstate#xx]
|
||||
added [plugin#mcpgpio#pinstate#xx]
|
||||
code optimization
|
||||
some code optimizations
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
small fixes
|
||||
few changes
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
some fixes
|
||||
added global variables for rules
|
||||
some fixes
|
||||
fixes
|
||||
fixed length check
|
||||
some optimizations
|
||||
modified command and variable name
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
optimizations
|
||||
Update src/StringConverter.ino
|
||||
added 4 variables to verify the system status
|
||||
|
||||
kpalczewski (1):
|
||||
add support for 64bit IR codes.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181017 (since mega-20181016)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 17 04:00:18 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Added checklist to the Issue_template
|
||||
|
||||
TD-er (3):
|
||||
[#1906] Allocate NotificationSettings on the heap
|
||||
[#1906] Allocate ControllerSettings on the heap
|
||||
[Stack] Add Free Stack to System Info plugin
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181016 (since mega-20181015)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 16 04:00:06 CEST 2018
|
||||
|
||||
Plebs (1):
|
||||
Fix for togglegpio without gpio initialization
|
||||
|
||||
TD-er (1):
|
||||
[Revert] Safe_strncpy cannot be used as generic strncpy replacement
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181015 (since mega-20181014)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 15 04:00:10 CEST 2018
|
||||
|
||||
Plebs (2):
|
||||
fix for bug #1864
|
||||
Update src/_P023_OLED.ino
|
||||
|
||||
TD-er (1):
|
||||
[safe strncpy] Add warning when entered string is too large
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181014 (since mega-20181011)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 14 04:00:13 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[#1799] Add SSID to main page
|
||||
|
||||
TD-er (5):
|
||||
[#1891] Generic UPD controller - send only first value from sensor
|
||||
[Controller] Fix send only first value
|
||||
Time#Initialized event in rules before %syshour% is set
|
||||
[UX] Warn user for incomplete network IP settings
|
||||
[#1895] Incorrect number bytes read I2C_read32_reg
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181011 (since mega-20181010)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Oct 11 04:00:24 CEST 2018
|
||||
|
||||
TD-er (5):
|
||||
[C009] Reduce memory usage of FHEM HTTP delay queue
|
||||
[Controller] Set default timeout to 300 msec (was 100 msec)
|
||||
Make sure to load ExtraTaskSettings when needed
|
||||
[Travis Doc] Remove building documentation by Travis
|
||||
[WebLog] Disable weblog when it is not being read
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181010 (since mega-20181009)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 10 04:00:09 CEST 2018
|
||||
|
||||
Plebs (1):
|
||||
Update src/_P019_PCF8574.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181009 (since mega-20181008)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 9 04:00:18 CEST 2018
|
||||
|
||||
TD-er (7):
|
||||
[Docs] Add favicon to documentation
|
||||
[Docs] Add Travis check for documentation and stop build for docs only
|
||||
[Docs] Run Travic documentation check before compiling project
|
||||
[Docs] Disable travis_terminate for now
|
||||
[JSON] Replace \n and \r in text fields
|
||||
[LWIP1.4] Move back to LWIP1.4
|
||||
[StringConverter] Some optimisations to reduce memory allocation
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181008 (since mega-20181007)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 8 04:00:09 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Added link to ReadTheDocs
|
||||
|
||||
Grovkillen (1):
|
||||
[Sphinx] added extension "sphinx.ext.imgconverter"
|
||||
|
||||
TD-er (3):
|
||||
[Sphinx] Initial setup for Sphinx documentation
|
||||
[Docs] First ESPEasy documentation (Controllers)
|
||||
[Docs] Added some directory structure and template
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181007 (since mega-20181006)
|
||||
-------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -0,0 +1,3 @@
|
||||
recommonmark
|
||||
Sphinx
|
||||
sphinx-bootstrap-theme
|
||||
@@ -0,0 +1,66 @@
|
||||
Controller
|
||||
**********
|
||||
|
||||
A controller is a component to enable a plugin to send data elsewhere.
|
||||
|
||||
- Up-to 3 controllers can be active in ESPEasy.
|
||||
- Per plugin up-to 3 active controllers can be selected.
|
||||
- For some controllers an additional parameter can be given.
|
||||
|
||||
For example, Domoticz needs an 'IDX' value to identify the configured entry in
|
||||
Domoticz for which new data is sent.
|
||||
|
||||
Controller Parameters
|
||||
=====================
|
||||
|
||||
Generic fields
|
||||
--------------
|
||||
|
||||
- **Protocol** - The type of controller (e.g. ThingSpeak/OpenHAB MQTT/etc.)
|
||||
- **Locate Controller** - Selection between hostname/IP
|
||||
- **Controller Hostname/IP** - The address to reach the selected service
|
||||
- **Controller Port** - TCP/UDP Port number (0...65536)
|
||||
- **Enabled** - Whether or not the controller is active.
|
||||
|
||||
Send queue parameters
|
||||
---------------------
|
||||
|
||||
Controllers have a queue to keep unsent messages.
|
||||
This queue is used to handle message bursts and also store messages which are recorded
|
||||
before WiFi connection is made or during lost connection.
|
||||
|
||||
- **Minimum Send Interval** - Minimum time between two messages in msec.
|
||||
- **Max Queue Depth** - Maximum length of the buffer queue to keep unsent messages.
|
||||
- **Max Retries** - Maximum number of retries to send a message.
|
||||
- **Full Queue Action** - How to handle when queue is full, ignore new or delete oldest message.
|
||||
- **Client Timeout** - Timeout in msec for an network connection used by the controller.
|
||||
- **Check Reply** - When set to false, a sent message is considered always successful.
|
||||
|
||||
|
||||
Sample ThingSpeak configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some controllers, like ThingSpeak, need a specific configuration.
|
||||
ThingSpeak only allows a message every 15 seconds for the free accounts.
|
||||
|
||||
- **Minimum Send Interval** - 15000 msec
|
||||
- **Max Queue Depth** - 1 (only report the last value)
|
||||
- **Max Retries** - 2
|
||||
- **Full Queue Action** - Delete Oldest
|
||||
- **Client Timeout** - 500 msec (server is online, so timeout must be a bit longer)
|
||||
|
||||
|
||||
Controller user credentials
|
||||
---------------------------
|
||||
|
||||
- **Controller User** - User name (optional)
|
||||
- **Controller Password** - Password (optional)
|
||||
|
||||
MQTT related settings
|
||||
---------------------
|
||||
|
||||
- **Controller Subscribe** - Subscribe to the given topic.
|
||||
- **Controller Publish** - Publish to the given topic.
|
||||
- **Controller lwl topic** - Topic to which LWT (Last Will Testament) messages should be sent.
|
||||
- **LWT Connect Message** - Connection established message.
|
||||
- **LWT Disconnect Message** - Connection lost message (sent to broker during connect and published by broker when connection is lost)
|
||||
@@ -0,0 +1,2 @@
|
||||
About Us
|
||||
********
|
||||
@@ -0,0 +1,2 @@
|
||||
ESPEasy Function Blocks
|
||||
***********************
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,35 @@
|
||||
Documentation
|
||||
*************
|
||||
|
||||
For documentation we use Sphinx and this will be read by ReadTheDocs.
|
||||
We use the `Sphinx Bootstrap Theme <https://github.com/ryan-roemer/sphinx-bootstrap-theme>`_
|
||||
|
||||
This documentation is included in the GitHub repository.
|
||||
It allows us to create documentation per version of ESPEasy.
|
||||
|
||||
See also the `ESPEasy wiki <https://www.letscontrolit.com/wiki/index.php/ESPEasy>`_
|
||||
for more documentation which has not been moved here.
|
||||
|
||||
Needed Python packages::
|
||||
|
||||
pip install sphinx recommonmark sphinx_bootstrap_theme
|
||||
|
||||
PlatformIO with Atom
|
||||
====================
|
||||
|
||||
With the ESPEasy project open in Atom, open the PIO terminal in Atom.
|
||||
|
||||
Install dependencies::
|
||||
|
||||
cd docs
|
||||
pip install ... (see needed Python packages above)
|
||||
|
||||
Build on Windows::
|
||||
|
||||
cd docs
|
||||
.\make.bat html
|
||||
|
||||
Build on Linux/Mac::
|
||||
|
||||
cd docs
|
||||
./make html
|
||||
@@ -0,0 +1,2 @@
|
||||
Plugins
|
||||
*******
|
||||
@@ -0,0 +1,2 @@
|
||||
Command Reference
|
||||
*****************
|
||||
@@ -0,0 +1,2 @@
|
||||
System Variables
|
||||
****************
|
||||
@@ -0,0 +1,2 @@
|
||||
Rules
|
||||
*****
|
||||
@@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
import sphinx_bootstrap_theme
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u'ESPEasy'
|
||||
copyright = u'2018, ESPEasy'
|
||||
author = u'Many'
|
||||
|
||||
# The short X.Y version
|
||||
version = u''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'2.1b1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.imgmath',
|
||||
'sphinx.ext.imgconverter',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
source_parsers = {
|
||||
'.md': CommonMarkParser,
|
||||
}
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
source_suffix = ['.rst', '.md']
|
||||
#source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
html_logo = 'ESPEasy/espeasy_logo.png'
|
||||
html_favicon = 'ESPEasy/favicon.ico'
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme = 'sphinx_rtd_theme'
|
||||
html_theme = 'bootstrap'
|
||||
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
#html_theme_options = {
|
||||
# 'canonical_url': '',
|
||||
# 'analytics_id': '',
|
||||
# 'logo_only': False,
|
||||
# 'display_version': True,
|
||||
# 'prev_next_buttons_location': 'bottom',
|
||||
# 'style_external_links': False,
|
||||
# # Toc options
|
||||
# 'collapse_navigation': True,
|
||||
# 'sticky_navigation': True,
|
||||
# 'navigation_depth': 4,
|
||||
# 'includehidden': True,
|
||||
# 'titles_only': False
|
||||
#}
|
||||
|
||||
html_theme_options = {
|
||||
# Navigation bar title. (Default: ``project`` value)
|
||||
'navbar_title': "ESPEasy",
|
||||
|
||||
# Tab name for entire site. (Default: "Site")
|
||||
'navbar_site_name': "Site",
|
||||
|
||||
# A list of tuples containing pages or urls to link to.
|
||||
# Valid tuples should be in the following forms:
|
||||
# (name, page) # a link to a page
|
||||
# (name, "/aa/bb", 1) # a link to an arbitrary relative url
|
||||
# (name, "http://example.com", True) # arbitrary absolute url
|
||||
# Note the "1" or "True" value above as the third argument to indicate
|
||||
# an arbitrary url.
|
||||
'navbar_links': [
|
||||
("Rules", "rules"),
|
||||
("Forum", "https://www.letscontrolit.com/forum/viewforum.php?f=1", True),
|
||||
],
|
||||
|
||||
# Render the next and previous page links in navbar. (Default: true)
|
||||
'navbar_sidebarrel': True,
|
||||
|
||||
# Render the current pages TOC in the navbar. (Default: true)
|
||||
'navbar_pagenav': True,
|
||||
|
||||
# Tab name for the current pages TOC. (Default: "Page")
|
||||
'navbar_pagenav_name': "Page",
|
||||
|
||||
# Global TOC depth for "site" navbar tab. (Default: 1)
|
||||
# Switching to -1 shows all levels.
|
||||
'globaltoc_depth': 2,
|
||||
|
||||
# Include hidden TOCs in Site navbar?
|
||||
#
|
||||
# Note: If this is "false", you cannot have mixed ``:hidden:`` and
|
||||
# non-hidden ``toctree`` directives in the same page, or else the build
|
||||
# will break.
|
||||
#
|
||||
# Values: "true" (default) or "false"
|
||||
'globaltoc_includehidden': "true",
|
||||
|
||||
# HTML navbar class (Default: "navbar") to attach to <div> element.
|
||||
# For black navbar, do "navbar navbar-inverse"
|
||||
'navbar_class': "navbar navbar-inverse",
|
||||
|
||||
# Fix navigation bar to top of page?
|
||||
# Values: "true" (default) or "false"
|
||||
'navbar_fixed_top': "true",
|
||||
|
||||
# Location of link to source.
|
||||
# Options are "nav" (default), "footer" or anything else to exclude.
|
||||
'source_link_position': "none",
|
||||
|
||||
# Bootswatch (http://bootswatch.com/) theme.
|
||||
#
|
||||
# Options are nothing (default) or the name of a valid theme
|
||||
# such as "cosmo" or "sandstone".
|
||||
#
|
||||
# The set of valid themes depend on the version of Bootstrap
|
||||
# that's used (the next config option).
|
||||
#
|
||||
# Currently, the supported themes are:
|
||||
# - Bootstrap 2: https://bootswatch.com/2
|
||||
# - Bootstrap 3: https://bootswatch.com/3
|
||||
'bootswatch_theme': "cerulean",
|
||||
|
||||
# Choose Bootstrap version.
|
||||
# Values: "3" (default) or "2" (in quotes)
|
||||
'bootstrap_version': "3",
|
||||
}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'ESPEasydoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'ESPEasy.tex', u'ESPEasy Documentation',
|
||||
u'Many', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'espeasy', u'ESPEasy Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'ESPEasy', u'ESPEasy Documentation',
|
||||
author, 'ESPEasy', 'ESP82xx/ESP32 firmware to connect people with any level of experience to system automation.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
@@ -0,0 +1,38 @@
|
||||
.. ESPEasy documentation master file, created by
|
||||
sphinx-quickstart on Sat Oct 06 22:34:34 2018.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to ESPEasy's documentation!
|
||||
===================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Table of Contents
|
||||
|
||||
ESPEasy/AboutUs.rst
|
||||
ESPEasy/FunctionBlocks.rst
|
||||
Controller/Controller.rst
|
||||
Plugin/Plugin.rst
|
||||
Rules/Rules.rst
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\appendix
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Appendix
|
||||
|
||||
Participate/Documentation.rst
|
||||
Reference/Command.rst
|
||||
Reference/SystemVariable.rst
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
+4
-4
@@ -117,7 +117,7 @@ build_unflags =
|
||||
build_flags = -D BUILD_GIT='"${sysenv.TRAVIS_TAG}"'
|
||||
-D NDEBUG
|
||||
-lstdc++ -lsupc++
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
-DVTABLES_IN_FLASH
|
||||
|
||||
|
||||
@@ -133,15 +133,15 @@ monitor_speed = 115200
|
||||
|
||||
[normal]
|
||||
platform = ${common.platform}
|
||||
build_flags = -DCONT_STACKSIZE=5120
|
||||
build_flags =
|
||||
|
||||
[testing]
|
||||
platform = ${core_2_4_1.platform}
|
||||
build_flags = -DCONT_STACKSIZE=5120 -DPLUGIN_BUILD_TESTING
|
||||
build_flags = -DPLUGIN_BUILD_TESTING
|
||||
|
||||
[dev]
|
||||
platform = ${core_2_4_1.platform}
|
||||
build_flags = -DCONT_STACKSIZE=5120 -DPLUGIN_BUILD_DEV
|
||||
build_flags = -DPLUGIN_BUILD_DEV
|
||||
|
||||
[ir]
|
||||
lib_ignore = ESP32_ping, ESP32WebServer
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check for documentation only changes.
|
||||
# Source: https://github.com/dev-id/Magic-Spoiler/blob/8111a06ab6682e020169991d5e2aa4fa503d787f/preflight.sh
|
||||
|
||||
set -e
|
||||
MAIN_BRANCH="mega"
|
||||
MD=".md$"
|
||||
DOCS="^docs/"
|
||||
|
||||
CHANGED_FILES=`git diff --name-only ${MAIN_BRANCH}...${TRAVIS_COMMIT}`
|
||||
ONLY_READMES=True
|
||||
DOCUMENTATION_CHANGED=False
|
||||
|
||||
for CHANGED_FILE in $CHANGED_FILES; do
|
||||
if ! [[ $CHANGED_FILE =~ $MD || $CHANGED_FILE =~ $DOCS ]]; then
|
||||
ONLY_READMES=False
|
||||
# break
|
||||
else
|
||||
DOCUMENTATION_CHANGED=True
|
||||
fi
|
||||
done
|
||||
|
||||
#if [[ $ONLY_READMES == True ]]; then
|
||||
# echo "Only documentation files found, exiting."
|
||||
# travis_terminate 0
|
||||
# exit 1
|
||||
#else
|
||||
# echo "Non-documentation files found, continuing with build."
|
||||
#fi
|
||||
|
||||
if [[ $DOCUMENTATION_CHANGED == True ]]; then
|
||||
echo "Generate documentation."
|
||||
cd docs
|
||||
make html
|
||||
fi
|
||||
@@ -79,6 +79,7 @@ String doExecuteCommand(const char * cmd, struct EventStruct *event, const char*
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
COMMAND_CASE("let" , Command_Rules_Let); // Rules.h
|
||||
COMMAND_CASE("load" , Command_Settings_Load); // Settings.h
|
||||
COMMAND_CASE("logentry" , Command_logentry); // Diagnostic.h
|
||||
COMMAND_CASE("lowmem" , Command_Lowmem); // Diagnostic.h
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ String Command_HTTP_SendToHTTP(struct EventStruct *event, const char* Line)
|
||||
}
|
||||
String request = do_create_http_request(hostportString, F("GET"), path);
|
||||
addLog(LOG_LEVEL_DEBUG, request);
|
||||
send_via_http(F("Command_HTTP_SendToHTTP"), client, request);
|
||||
send_via_http(F("Command_HTTP_SendToHTTP"), client, request, false);
|
||||
}
|
||||
}
|
||||
return return_command_success();
|
||||
|
||||
@@ -34,4 +34,15 @@ String Command_Rules_Events(struct EventStruct *event, const char* Line)
|
||||
return return_command_success();
|
||||
}
|
||||
|
||||
String Command_Rules_Let(struct EventStruct *event, const char* Line)
|
||||
{
|
||||
char TmpStr1[INPUT_COMMAND_SIZE];
|
||||
if (GetArgv(Line, TmpStr1, 3)) {
|
||||
float result = 0;
|
||||
Calculate(TmpStr1, &result);
|
||||
customFloatVar[event->Par1-1] = result;
|
||||
}
|
||||
return return_command_success();
|
||||
}
|
||||
|
||||
#endif // COMMAND_RULES_H
|
||||
|
||||
+5
-5
@@ -132,7 +132,7 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
bool MQTTConnect(int controller_idx)
|
||||
{
|
||||
++mqtt_reconnect_count;
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(controller_idx, ControllerSettings);
|
||||
if (!ControllerSettings.checkHostReachable(true))
|
||||
return false;
|
||||
@@ -293,9 +293,9 @@ void scheduleNextMQTTdelayQueue() {
|
||||
|
||||
void processMQTTdelayQueue() {
|
||||
START_TIMER;
|
||||
MQTT_queue_element element;
|
||||
if (!MQTTDelayHandler.getNext(element)) return;
|
||||
if (MQTTclient.publish(element._topic.c_str(), element._payload.c_str(), element._retained)) {
|
||||
MQTT_queue_element* element(MQTTDelayHandler.getNext());
|
||||
if (element == NULL) return;
|
||||
if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) {
|
||||
setIntervalTimerOverride(TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible.
|
||||
MQTTDelayHandler.markProcessed(true);
|
||||
} else {
|
||||
@@ -316,7 +316,7 @@ void processMQTTdelayQueue() {
|
||||
\*********************************************************************************************/
|
||||
void MQTTStatus(String& status)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
LoadControllerSettings(enabledMqttController, ControllerSettings);
|
||||
|
||||
+152
-94
@@ -79,7 +79,7 @@
|
||||
#define DEFAULT_MQTT_LWT_TOPIC "" // Default lwt topic
|
||||
#define DEFAULT_MQTT_LWT_CONNECT_MESSAGE "Connected" // Default lwt message
|
||||
#define DEFAULT_MQTT_LWT_DISCONNECT_MESSAGE "Connection Lost" // Default lwt message
|
||||
#define DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID 0
|
||||
#define DEFAULT_MQTT_USE_UNITNAME_AS_CLIENTID 0
|
||||
|
||||
#define DEFAULT_USE_NTP false // (true|false) Use NTP Server
|
||||
#define DEFAULT_NTP_HOST "" // NTP Server Hostname
|
||||
@@ -230,7 +230,7 @@
|
||||
#define CONTROLLER_DELAY_QUEUE_RETRY_DFLT 10
|
||||
// Timeout of the client in msec.
|
||||
#define CONTROLLER_CLIENTTIMEOUT_MAX 1000
|
||||
#define CONTROLLER_CLIENTTIMEOUT_DFLT 100
|
||||
#define CONTROLLER_CLIENTTIMEOUT_DFLT 300
|
||||
|
||||
|
||||
#define PLUGIN_INIT_ALL 1
|
||||
@@ -292,6 +292,7 @@
|
||||
#define NPLUGIN_NOT_FOUND 255
|
||||
|
||||
|
||||
#define LOG_LEVEL_NONE 0
|
||||
#define LOG_LEVEL_ERROR 1
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#define LOG_LEVEL_DEBUG 3
|
||||
@@ -338,6 +339,7 @@
|
||||
#define RULES_BUFFER_SIZE 64
|
||||
#define NAME_FORMULA_LENGTH_MAX 40
|
||||
#define RULES_IF_MAX_NESTING_LEVEL 4
|
||||
#define CUSTOM_VARS_MAX 16
|
||||
|
||||
#define UDP_PACKETSIZE_MAX 2048
|
||||
|
||||
@@ -599,14 +601,17 @@ bool MQTTclient_should_reconnect = true;
|
||||
bool MQTTclient_connected = false;
|
||||
int mqtt_reconnect_count = 0;
|
||||
|
||||
//NTP status
|
||||
bool statusNTPInitialized = false;
|
||||
|
||||
// mqtt import status
|
||||
bool P037_MQTTImport_connected = false;
|
||||
|
||||
// udp protocol stuff (syslog, global sync, node info list, ntp time)
|
||||
WiFiUDP portUDP;
|
||||
|
||||
class TimingStats;
|
||||
|
||||
#define LOADFILE_STATS 0
|
||||
#define LOOP_STATS 1
|
||||
|
||||
/*********************************************************************************************\
|
||||
* CRCStruct
|
||||
\*********************************************************************************************/
|
||||
@@ -674,6 +679,16 @@ struct SecurityStruct
|
||||
uint8_t md5[16];
|
||||
} SecuritySettings;
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Custom Variables for usage in rules and http.
|
||||
* Syntax: %vX%
|
||||
* usage:
|
||||
* let,1,10
|
||||
* if %v1%=10 do ...
|
||||
\*********************************************************************************************/
|
||||
float customFloatVar[CUSTOM_VARS_MAX];
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SettingsStruct
|
||||
\*********************************************************************************************/
|
||||
@@ -695,6 +710,10 @@ struct SettingsStruct
|
||||
if (VariousBits1 > (1 << 30)) VariousBits1 = 0;
|
||||
}
|
||||
|
||||
bool networkSettingsEmpty() {
|
||||
return (IP[0] == 0 && Gateway[0] == 0 && Subnet[0] == 0 && DNS[0] == 0);
|
||||
}
|
||||
|
||||
void clearNetworkSettings() {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
IP[i] = 0;
|
||||
@@ -894,13 +913,30 @@ SettingsStruct* SettingsStruct_ptr = new SettingsStruct;
|
||||
SettingsStruct& Settings = *SettingsStruct_ptr;
|
||||
*/
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ControllerSettingsStruct
|
||||
* Analyze SettingsStruct and report inconsistencies
|
||||
* Not a member function to be able to use the F-macro
|
||||
\*********************************************************************************************/
|
||||
bool SettingsCheck(String& error) {
|
||||
error = "";
|
||||
if (!Settings.networkSettingsEmpty()) {
|
||||
if (Settings.IP[0] == 0 || Settings.Gateway[0] == 0 || Settings.Subnet[0] == 0 || Settings.DNS[0] == 0) {
|
||||
error += F("Error: Either fill all IP settings fields or leave all empty");
|
||||
}
|
||||
}
|
||||
|
||||
return error.length() == 0;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ControllerSettingsStruct definition
|
||||
\*********************************************************************************************/
|
||||
struct ControllerSettingsStruct
|
||||
{
|
||||
ControllerSettingsStruct() : UseDNS(false), Port(0),
|
||||
MinimalTimeBetweenMessages(100), MaxQueueDepth(10), MaxRetry(10), DeleteOldest(false), ClientTimeout(100) {
|
||||
MinimalTimeBetweenMessages(100), MaxQueueDepth(10), MaxRetry(10),
|
||||
DeleteOldest(false), ClientTimeout(100), MustCheckReply(false) {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
IP[i] = 0;
|
||||
}
|
||||
@@ -925,6 +961,7 @@ struct ControllerSettingsStruct
|
||||
unsigned int MaxRetry;
|
||||
boolean DeleteOldest; // Action to perform when buffer full, delete oldest, or ignore newest.
|
||||
unsigned int ClientTimeout;
|
||||
boolean MustCheckReply; // When set to false, a sent message is considered always successful.
|
||||
|
||||
void validate() {
|
||||
if (Port > 65535) Port = 0;
|
||||
@@ -932,8 +969,9 @@ struct ControllerSettingsStruct
|
||||
MinimalTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT;
|
||||
if (MaxQueueDepth > CONTROLLER_DELAY_QUEUE_DEPTH_MAX) MaxQueueDepth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT;
|
||||
if (MaxRetry > CONTROLLER_DELAY_QUEUE_RETRY_MAX) MaxRetry = CONTROLLER_DELAY_QUEUE_RETRY_MAX;
|
||||
if (ClientTimeout < 10 || ClientTimeout > CONTROLLER_CLIENTTIMEOUT_MAX)
|
||||
if (ClientTimeout < 10 || ClientTimeout > CONTROLLER_CLIENTTIMEOUT_MAX) {
|
||||
ClientTimeout = CONTROLLER_CLIENTTIMEOUT_DFLT;
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress getIP() const {
|
||||
@@ -1036,6 +1074,11 @@ private:
|
||||
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ControllerSettingsStruct> ControllerSettingsStruct_ptr_type;
|
||||
#define MakeControllerSettings(T) ControllerSettingsStruct_ptr_type ControllerSettingsStruct_ptr(new ControllerSettingsStruct());\
|
||||
ControllerSettingsStruct& T = *ControllerSettingsStruct_ptr;
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* NotificationSettingsStruct
|
||||
@@ -1067,6 +1110,11 @@ struct NotificationSettingsStruct
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<NotificationSettingsStruct> NotificationSettingsStruct_ptr_type;
|
||||
#define MakeNotificationSettings(T) NotificationSettingsStruct_ptr_type NotificationSettingsStruct_ptr(new NotificationSettingsStruct());\
|
||||
NotificationSettingsStruct& T = *NotificationSettingsStruct_ptr;
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ExtraTaskSettingsStruct
|
||||
\*********************************************************************************************/
|
||||
@@ -1150,22 +1198,36 @@ struct ExtraTaskSettingsStruct
|
||||
struct EventStruct
|
||||
{
|
||||
EventStruct() :
|
||||
Data(NULL), idx(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0),
|
||||
Source(0), TaskIndex(TASKS_MAX), ControllerIndex(0), ProtocolIndex(0), NotificationIndex(0),
|
||||
BaseVarIndex(0), idx(0), sensorType(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0),
|
||||
OriginTaskIndex(0), Data(NULL) {}
|
||||
BaseVarIndex(0), sensorType(0), OriginTaskIndex(0) {}
|
||||
EventStruct(const struct EventStruct& event):
|
||||
Source(event.Source), TaskIndex(event.TaskIndex), ControllerIndex(event.ControllerIndex)
|
||||
, ProtocolIndex(event.ProtocolIndex), NotificationIndex(event.NotificationIndex)
|
||||
, BaseVarIndex(event.BaseVarIndex), idx(event.idx), sensorType(event.sensorType)
|
||||
, Par1(event.Par1), Par2(event.Par2), Par3(event.Par3), Par4(event.Par4), Par5(event.Par5)
|
||||
, OriginTaskIndex(event.OriginTaskIndex)
|
||||
, String1(event.String1)
|
||||
String1(event.String1)
|
||||
, String2(event.String2)
|
||||
, String3(event.String3)
|
||||
, String4(event.String4)
|
||||
, String5(event.String5)
|
||||
, Data(event.Data) {}
|
||||
, Data(event.Data)
|
||||
, idx(event.idx)
|
||||
, Par1(event.Par1), Par2(event.Par2), Par3(event.Par3), Par4(event.Par4), Par5(event.Par5)
|
||||
, Source(event.Source), TaskIndex(event.TaskIndex), ControllerIndex(event.ControllerIndex)
|
||||
, ProtocolIndex(event.ProtocolIndex), NotificationIndex(event.NotificationIndex)
|
||||
, BaseVarIndex(event.BaseVarIndex), sensorType(event.sensorType)
|
||||
, OriginTaskIndex(event.OriginTaskIndex)
|
||||
{}
|
||||
|
||||
String String1;
|
||||
String String2;
|
||||
String String3;
|
||||
String String4;
|
||||
String String5;
|
||||
byte *Data;
|
||||
int idx;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
int Par4;
|
||||
int Par5;
|
||||
byte Source;
|
||||
byte TaskIndex; // index position in TaskSettings array, 0-11
|
||||
byte ControllerIndex; // index position in Settings.Controller, 0-3
|
||||
@@ -1174,20 +1236,8 @@ struct EventStruct
|
||||
//Edwin: Not needed, and wasnt used. We can determine the protocol index with getNotificationProtocolIndex(NotificationIndex)
|
||||
// byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
|
||||
byte BaseVarIndex;
|
||||
int idx;
|
||||
byte sensorType;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
int Par4;
|
||||
int Par5;
|
||||
byte OriginTaskIndex;
|
||||
String String1;
|
||||
String String2;
|
||||
String String3;
|
||||
String String4;
|
||||
String String5;
|
||||
byte *Data;
|
||||
};
|
||||
|
||||
|
||||
@@ -1197,18 +1247,19 @@ struct EventStruct
|
||||
#define LOG_STRUCT_MESSAGE_SIZE 128
|
||||
#ifdef ESP32
|
||||
#define LOG_STRUCT_MESSAGE_LINES 30
|
||||
#define LOG_BUFFER_EXPIRE 30000 // Time after which a buffered log item is considered expired.
|
||||
#else
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define LOG_STRUCT_MESSAGE_LINES 10
|
||||
#else
|
||||
#define LOG_STRUCT_MESSAGE_LINES 15
|
||||
#endif
|
||||
#define LOG_BUFFER_EXPIRE 5000 // Time after which a buffered log item is considered expired.
|
||||
#endif
|
||||
|
||||
struct LogStruct {
|
||||
LogStruct() : write_idx(0), read_idx(0) {
|
||||
LogStruct() : write_idx(0), read_idx(0), lastReadTimeStamp(0) {
|
||||
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
|
||||
Message[i].reserve(LOG_STRUCT_MESSAGE_SIZE);
|
||||
timeStamp[i] = 0;
|
||||
log_level[i] = 0;
|
||||
}
|
||||
@@ -1226,6 +1277,7 @@ struct LogStruct {
|
||||
if (linelength > LOG_STRUCT_MESSAGE_SIZE-1)
|
||||
linelength = LOG_STRUCT_MESSAGE_SIZE-1;
|
||||
Message[write_idx] = "";
|
||||
Message[write_idx].reserve(linelength);
|
||||
for (unsigned i = 0; i < linelength; ++i) {
|
||||
Message[write_idx] += *(line + i);
|
||||
}
|
||||
@@ -1234,6 +1286,7 @@ struct LogStruct {
|
||||
// Read the next item and append it to the given string.
|
||||
// Returns whether new lines are available.
|
||||
bool get(String& output, const String& lineEnd) {
|
||||
lastReadTimeStamp = millis();
|
||||
if (!isEmpty()) {
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
output += formatLine(read_idx, lineEnd);
|
||||
@@ -1242,6 +1295,7 @@ struct LogStruct {
|
||||
}
|
||||
|
||||
String get_logjson_formatted(bool& logLinesAvailable, unsigned long& timestamp) {
|
||||
lastReadTimeStamp = millis();
|
||||
logLinesAvailable = false;
|
||||
if (isEmpty()) {
|
||||
return "";
|
||||
@@ -1255,31 +1309,15 @@ struct LogStruct {
|
||||
return output;
|
||||
}
|
||||
|
||||
bool get(String& output, const String& lineEnd, int line) {
|
||||
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
}
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
bool getAll(String& output, const String& lineEnd) {
|
||||
int tmpread((write_idx + 1) % LOG_STRUCT_MESSAGE_LINES);
|
||||
bool someAdded = false;
|
||||
while (tmpread != write_idx) {
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
someAdded = true;
|
||||
}
|
||||
tmpread = (tmpread + 1)% LOG_STRUCT_MESSAGE_LINES;
|
||||
}
|
||||
return someAdded;
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return (write_idx == read_idx);
|
||||
}
|
||||
|
||||
bool logActiveRead() {
|
||||
clearExpiredEntries();
|
||||
return timePassedSince(lastReadTimeStamp) < LOG_BUFFER_EXPIRE;
|
||||
}
|
||||
|
||||
private:
|
||||
String formatLine(int index, const String& lineEnd) {
|
||||
String output;
|
||||
@@ -1303,20 +1341,38 @@ struct LogStruct {
|
||||
return output;
|
||||
}
|
||||
|
||||
void clearExpiredEntries() {
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (timePassedSince(lastReadTimeStamp) > LOG_BUFFER_EXPIRE) {
|
||||
// Clear the entire log.
|
||||
// If web log is the only log active, it will not be checked again until it is read.
|
||||
for (read_idx = 0; read_idx < LOG_STRUCT_MESSAGE_LINES; ++read_idx) {
|
||||
Message[read_idx] = String(); // Free also the reserved memory.
|
||||
timeStamp[read_idx] = 0;
|
||||
log_level[read_idx] = 0;
|
||||
}
|
||||
read_idx = 0;
|
||||
write_idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int write_idx;
|
||||
int read_idx;
|
||||
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
|
||||
unsigned long lastReadTimeStamp;
|
||||
byte log_level[LOG_STRUCT_MESSAGE_LINES];
|
||||
String Message[LOG_STRUCT_MESSAGE_LINES];
|
||||
|
||||
} Logging;
|
||||
|
||||
std::deque<char> serialLogBuffer;
|
||||
unsigned long last_serial_log_emptied = 0;
|
||||
unsigned long last_serial_log_read = 0;
|
||||
|
||||
byte highest_active_log_level = 0;
|
||||
bool log_to_serial_disabled = false;
|
||||
bool log_to_serial_disabled_temporary = false;
|
||||
// Do this in a template to prevent casting to String when not needed.
|
||||
#define addLog(L,S) if (loglevelActiveFor(L)) { addToLog(L,S); }
|
||||
|
||||
@@ -1340,16 +1396,16 @@ struct DeviceStruct
|
||||
byte Type; // How the device is connected. e.g. DEVICE_TYPE_SINGLE => connected through 1 datapin
|
||||
byte VType; // Type of value the plugin will return, used only for Domoticz
|
||||
byte Ports; // Port to use when device has multiple I/O pins (N.B. not used much)
|
||||
byte ValueCount; // The number of output values of a plugin. The value should match the number of keys PLUGIN_VALUENAME1_xxx
|
||||
boolean PullUpOption; // Allow to set internal pull-up resistors.
|
||||
boolean InverseLogicOption; // Allow to invert the boolean state (e.g. a switch)
|
||||
boolean FormulaOption; // Allow to enter a formula to convert values during read. (not possible with Custom enabled)
|
||||
boolean Custom;
|
||||
boolean SendDataOption; // Allow to send data to a controller.
|
||||
boolean GlobalSyncOption; // No longer used. Was used for ESPeasy values sync between nodes
|
||||
boolean TimerOption; // Allow to set the "Interval" timer for the plugin.
|
||||
boolean TimerOptional; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay)
|
||||
boolean DecimalsOnly; // Allow to set the number of decimals (otherwise treated a 0 decimals)
|
||||
byte ValueCount; // The number of output values of a plugin. The value should match the number of keys PLUGIN_VALUENAME1_xxx
|
||||
bool PullUpOption : 1; // Allow to set internal pull-up resistors.
|
||||
bool InverseLogicOption : 1; // Allow to invert the boolean state (e.g. a switch)
|
||||
bool FormulaOption : 1; // Allow to enter a formula to convert values during read. (not possible with Custom enabled)
|
||||
bool Custom : 1;
|
||||
bool SendDataOption : 1; // Allow to send data to a controller.
|
||||
bool GlobalSyncOption : 1; // No longer used. Was used for ESPeasy values sync between nodes
|
||||
bool TimerOption : 1; // Allow to set the "Interval" timer for the plugin.
|
||||
bool TimerOptional : 1; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay)
|
||||
bool DecimalsOnly; // Allow to set the number of decimals (otherwise treated a 0 decimals)
|
||||
};
|
||||
typedef std::vector<DeviceStruct> DeviceVector;
|
||||
DeviceVector Device;
|
||||
@@ -1414,16 +1470,16 @@ NodesMap Nodes;
|
||||
struct systemTimerStruct
|
||||
{
|
||||
systemTimerStruct() :
|
||||
timer(0), plugin(0), TaskIndex(-1), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0) {}
|
||||
timer(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0), TaskIndex(-1), plugin(0) {}
|
||||
|
||||
unsigned long timer;
|
||||
byte plugin;
|
||||
int16_t TaskIndex;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
int Par4;
|
||||
int Par5;
|
||||
int16_t TaskIndex;
|
||||
byte plugin;
|
||||
};
|
||||
std::map<unsigned long, systemTimerStruct> systemTimers;
|
||||
|
||||
@@ -1432,11 +1488,11 @@ std::map<unsigned long, systemTimerStruct> systemTimers;
|
||||
\*********************************************************************************************/
|
||||
struct pinStatesStruct
|
||||
{
|
||||
pinStatesStruct() : plugin(0), index(0), mode(0), value(0) {}
|
||||
pinStatesStruct() : value(0), plugin(0), index(0), mode(0) {}
|
||||
uint16_t value;
|
||||
byte plugin;
|
||||
byte index;
|
||||
byte mode;
|
||||
uint16_t value;
|
||||
} pinStates[PINSTATE_TABLE_MAX];
|
||||
|
||||
|
||||
@@ -1793,31 +1849,32 @@ unsigned long timediff_calls = 0;
|
||||
unsigned long timediff_cpu_cycles_total = 0;
|
||||
|
||||
#define LOADFILE_STATS 0
|
||||
#define LOOP_STATS 1
|
||||
#define PLUGIN_CALL_50PS 2
|
||||
#define PLUGIN_CALL_10PS 3
|
||||
#define PLUGIN_CALL_10PSU 4
|
||||
#define PLUGIN_CALL_1PS 5
|
||||
#define SENSOR_SEND_TASK 6
|
||||
#define SEND_DATA_STATS 7
|
||||
#define COMPUTE_FORMULA_STATS 8
|
||||
#define PROC_SYS_TIMER 9
|
||||
#define SET_NEW_TIMER 10
|
||||
#define TIME_DIFF_COMPUTE 11
|
||||
#define MQTT_DELAY_QUEUE 12
|
||||
#define C001_DELAY_QUEUE 13
|
||||
#define C002_DELAY_QUEUE 14
|
||||
#define C003_DELAY_QUEUE 15
|
||||
#define C004_DELAY_QUEUE 16
|
||||
#define C005_DELAY_QUEUE 17
|
||||
#define C006_DELAY_QUEUE 18
|
||||
#define C007_DELAY_QUEUE 19
|
||||
#define C008_DELAY_QUEUE 20
|
||||
#define C009_DELAY_QUEUE 21
|
||||
#define C010_DELAY_QUEUE 22
|
||||
#define C011_DELAY_QUEUE 23
|
||||
#define C012_DELAY_QUEUE 24
|
||||
#define C013_DELAY_QUEUE 25
|
||||
#define SAVEFILE_STATS 1
|
||||
#define LOOP_STATS 2
|
||||
#define PLUGIN_CALL_50PS 3
|
||||
#define PLUGIN_CALL_10PS 4
|
||||
#define PLUGIN_CALL_10PSU 5
|
||||
#define PLUGIN_CALL_1PS 6
|
||||
#define SENSOR_SEND_TASK 7
|
||||
#define SEND_DATA_STATS 8
|
||||
#define COMPUTE_FORMULA_STATS 9
|
||||
#define PROC_SYS_TIMER 10
|
||||
#define SET_NEW_TIMER 11
|
||||
#define TIME_DIFF_COMPUTE 12
|
||||
#define MQTT_DELAY_QUEUE 13
|
||||
#define C001_DELAY_QUEUE 14
|
||||
#define C002_DELAY_QUEUE 15
|
||||
#define C003_DELAY_QUEUE 16
|
||||
#define C004_DELAY_QUEUE 17
|
||||
#define C005_DELAY_QUEUE 18
|
||||
#define C006_DELAY_QUEUE 19
|
||||
#define C007_DELAY_QUEUE 20
|
||||
#define C008_DELAY_QUEUE 21
|
||||
#define C009_DELAY_QUEUE 22
|
||||
#define C010_DELAY_QUEUE 23
|
||||
#define C011_DELAY_QUEUE 24
|
||||
#define C012_DELAY_QUEUE 25
|
||||
#define C013_DELAY_QUEUE 26
|
||||
|
||||
|
||||
|
||||
@@ -1826,13 +1883,14 @@ unsigned long timediff_cpu_cycles_total = 0;
|
||||
|
||||
#define START_TIMER const unsigned statisticsTimerStart(micros());
|
||||
#define STOP_TIMER_TASK(T,F) if (mustLogFunction(F)) pluginStats[T*32 + F].add(usecPassedSince(statisticsTimerStart));
|
||||
#define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart));
|
||||
//#define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart));
|
||||
#define STOP_TIMER(L) miscStats[L].add(usecPassedSince(statisticsTimerStart));
|
||||
|
||||
|
||||
String getMiscStatsName(int stat) {
|
||||
switch (stat) {
|
||||
case LOADFILE_STATS: return F("Load File");
|
||||
case SAVEFILE_STATS: return F("Save File");
|
||||
case LOOP_STATS: return F("Loop");
|
||||
case PLUGIN_CALL_50PS: return F("Plugin call 50 p/s ");
|
||||
case PLUGIN_CALL_10PS: return F("Plugin call 10 p/s ");
|
||||
|
||||
+2
-5
@@ -839,13 +839,10 @@ void SensorSendTask(byte TaskIndex)
|
||||
{
|
||||
if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0)
|
||||
{
|
||||
String spreValue = String(preValue[varNr]);
|
||||
String formula = ExtraTaskSettings.TaskDeviceFormula[varNr];
|
||||
float value = UserVar[varIndex + varNr];
|
||||
formula.replace(F("%pvalue%"), String(preValue[varNr]));
|
||||
formula.replace(F("%value%"), String(UserVar[varIndex + varNr]));
|
||||
float result = 0;
|
||||
String svalue = String(value);
|
||||
formula.replace(F("%pvalue%"), spreValue);
|
||||
formula.replace(F("%value%"), svalue);
|
||||
byte error = Calculate(formula.c_str(), &result);
|
||||
if (error == 0)
|
||||
UserVar[varIndex + varNr] = result;
|
||||
|
||||
+33
-6
@@ -77,7 +77,7 @@ String BuildFixes()
|
||||
Settings.UseRTOSMultitasking = false;
|
||||
Settings.Pin_Reset = -1;
|
||||
Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY;
|
||||
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID;
|
||||
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNAME_AS_CLIENTID;
|
||||
Settings.StructSize = sizeof(Settings);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,11 @@ String SaveSettings(void)
|
||||
Settings.validate();
|
||||
err=SaveToFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof(Settings));
|
||||
if (err.length())
|
||||
return(err);
|
||||
return(err);
|
||||
// Must check this after saving, or else it is not possible to fix multiple
|
||||
// issues which can only corrected on different pages.
|
||||
if (!SettingsCheck(err)) return err;
|
||||
|
||||
// }
|
||||
|
||||
memcpy( SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
|
||||
@@ -413,6 +417,13 @@ String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
|
||||
return(SaveToFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, memAddress, datasize));
|
||||
}
|
||||
|
||||
String getCustomTaskSettingsError(byte varNr) {
|
||||
String error = F("Error: Text too long for line ");
|
||||
error += varNr + 1;
|
||||
error += '\n';
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Clear custom task settings
|
||||
@@ -553,20 +564,29 @@ String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return log;
|
||||
}
|
||||
|
||||
START_TIMER;
|
||||
checkRAM(F("SaveToFile"));
|
||||
FLASH_GUARD();
|
||||
|
||||
{
|
||||
String log = F("SaveToFile: free stack: ");
|
||||
log += getCurrentFreeStack();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
delay(1);
|
||||
unsigned long timer = millis() + 50;
|
||||
fs::File f = SPIFFS.open(fname, "r+");
|
||||
if (f) {
|
||||
SPIFFS_CHECK(f, fname);
|
||||
|
||||
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
|
||||
byte *pointerToByteToSave = memAddress;
|
||||
for (int x = 0; x < datasize ; x++)
|
||||
{
|
||||
SPIFFS_CHECK(f.write(*pointerToByteToSave), fname);
|
||||
pointerToByteToSave++;
|
||||
if (timeOutReached(timer)) {
|
||||
timer += 50;
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
String log = F("FILE : Saved ");
|
||||
@@ -579,6 +599,12 @@ String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return log;
|
||||
}
|
||||
STOP_TIMER(SAVEFILE_STATS);
|
||||
{
|
||||
String log = F("SaveToFile: free stack after: ");
|
||||
log += getCurrentFreeStack();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
//OK
|
||||
return String();
|
||||
@@ -635,10 +661,10 @@ String LoadFromFile(char* fname, int offset, byte* memAddress, int datasize)
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return log;
|
||||
}
|
||||
delay(1);
|
||||
START_TIMER;
|
||||
|
||||
checkRAM(F("LoadFromFile"));
|
||||
|
||||
fs::File f = SPIFFS.open(fname, "r+");
|
||||
SPIFFS_CHECK(f, fname);
|
||||
SPIFFS_CHECK(f.seek(offset, fs::SeekSet), fname);
|
||||
@@ -646,6 +672,7 @@ String LoadFromFile(char* fname, int offset, byte* memAddress, int datasize)
|
||||
f.close();
|
||||
|
||||
STOP_TIMER(LOADFILE_STATS);
|
||||
delay(1);
|
||||
|
||||
return(String());
|
||||
}
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ int32_t I2C_read32_reg(uint8_t i2caddr, byte reg) {
|
||||
Wire.beginTransmission(i2caddr);
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.endTransmission(END_TRANSMISSION_FLAG);
|
||||
Wire.requestFrom(i2caddr, (byte)3);
|
||||
Wire.requestFrom(i2caddr, (byte)4);
|
||||
value = (((int32_t)Wire.read()) <<24) | (((uint32_t)Wire.read()) << 16) | (Wire.read() << 8) | Wire.read();
|
||||
|
||||
return value;
|
||||
|
||||
+124
-37
@@ -445,8 +445,7 @@ void delayBackground(unsigned long delay)
|
||||
void parseCommandString(struct EventStruct *event, const String& string)
|
||||
{
|
||||
checkRAM(F("parseCommandString"));
|
||||
char TmpStr1[INPUT_COMMAND_SIZE];
|
||||
TmpStr1[0] = 0;
|
||||
char *TmpStr1 = new char[INPUT_COMMAND_SIZE]();
|
||||
event->Par1 = 0;
|
||||
event->Par2 = 0;
|
||||
event->Par3 = 0;
|
||||
@@ -458,6 +457,7 @@ void parseCommandString(struct EventStruct *event, const String& string)
|
||||
if (GetArgv(string.c_str(), TmpStr1, 4)) { event->Par3 = CalculateParam(TmpStr1); }
|
||||
if (GetArgv(string.c_str(), TmpStr1, 5)) { event->Par4 = CalculateParam(TmpStr1); }
|
||||
if (GetArgv(string.c_str(), TmpStr1, 6)) { event->Par5 = CalculateParam(TmpStr1); }
|
||||
delete[] TmpStr1;
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
@@ -568,6 +568,7 @@ boolean GetArgv(const char *string, char *argv, unsigned int argc) {
|
||||
|
||||
boolean GetArgv(const char *string, char *argv, unsigned int argv_size, unsigned int argc)
|
||||
{
|
||||
memset(argv, 0, argv_size);
|
||||
size_t string_len = strlen(string);
|
||||
unsigned int string_pos = 0, argv_pos = 0, argc_pos = 0;
|
||||
char c, d;
|
||||
@@ -812,7 +813,7 @@ void ResetFactory(void)
|
||||
|
||||
Settings.MQTTRetainFlag = DEFAULT_MQTT_RETAIN;
|
||||
Settings.MessageDelay = DEFAULT_MQTT_DELAY;
|
||||
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID;
|
||||
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNAME_AS_CLIENTID;
|
||||
|
||||
Settings.UseNTP = DEFAULT_USE_NTP;
|
||||
strcpy_P(Settings.NTPHost, PSTR(DEFAULT_NTP_HOST));
|
||||
@@ -850,7 +851,7 @@ void ResetFactory(void)
|
||||
SaveSettings();
|
||||
|
||||
#if DEFAULT_CONTROLLER
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
strcpy_P(ControllerSettings.Subscribe, PSTR(DEFAULT_SUB));
|
||||
strcpy_P(ControllerSettings.Publish, PSTR(DEFAULT_PUB));
|
||||
strcpy_P(ControllerSettings.MQTTLwtTopic, PSTR(DEFAULT_MQTT_LWT_TOPIC));
|
||||
@@ -1154,16 +1155,31 @@ void initLog()
|
||||
/********************************************************************************************\
|
||||
Logging
|
||||
\*********************************************************************************************/
|
||||
String getLogLevelDisplayString(byte index, int& logLevel) {
|
||||
String getLogLevelDisplayString(int logLevel) {
|
||||
switch (logLevel) {
|
||||
case LOG_LEVEL_NONE: return F("None");
|
||||
case LOG_LEVEL_ERROR: return F("Error");
|
||||
case LOG_LEVEL_INFO: return F("Info");
|
||||
case LOG_LEVEL_DEBUG: return F("Debug");
|
||||
case LOG_LEVEL_DEBUG_MORE: return F("Debug More");
|
||||
case LOG_LEVEL_DEBUG_DEV: return F("Debug dev");
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
String getLogLevelDisplayStringFromIndex(byte index, int& logLevel) {
|
||||
switch (index) {
|
||||
case 0: logLevel = LOG_LEVEL_ERROR; return F("Error");
|
||||
case 1: logLevel = LOG_LEVEL_INFO; return F("Info");
|
||||
case 2: logLevel = LOG_LEVEL_DEBUG; return F("Debug");
|
||||
case 3: logLevel = LOG_LEVEL_DEBUG_MORE; return F("Debug More");
|
||||
case 4: logLevel = LOG_LEVEL_DEBUG_DEV; return F("Debug dev");
|
||||
case 0: logLevel = LOG_LEVEL_ERROR; break;
|
||||
case 1: logLevel = LOG_LEVEL_INFO; break;
|
||||
case 2: logLevel = LOG_LEVEL_DEBUG; break;
|
||||
case 3: logLevel = LOG_LEVEL_DEBUG_MORE; break;
|
||||
case 4: logLevel = LOG_LEVEL_DEBUG_DEV; break;
|
||||
|
||||
default: logLevel = -1; return "";
|
||||
}
|
||||
return getLogLevelDisplayString(logLevel);
|
||||
}
|
||||
|
||||
void addToLog(byte loglevel, const String& string)
|
||||
@@ -1178,14 +1194,6 @@ void addToLog(byte logLevel, const __FlashStringHelper* flashString)
|
||||
addToLog(logLevel, s.c_str());
|
||||
}
|
||||
|
||||
bool SerialAvailableForWrite() {
|
||||
if (!Settings.UseSerial) return false;
|
||||
#if defined(ESP8266)
|
||||
if (!Serial.availableForWrite()) return false; // UART FIFO overflow or TX disabled.
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void disableSerialLog() {
|
||||
log_to_serial_disabled = true;
|
||||
setLogLevelFor(LOG_TO_SERIAL, 0);
|
||||
@@ -1207,10 +1215,20 @@ void setLogLevelFor(byte destination, byte logLevel) {
|
||||
|
||||
void updateLogLevelCache() {
|
||||
byte max_lvl = 0;
|
||||
max_lvl = _max(max_lvl, Settings.SerialLogLevel);
|
||||
if (!log_to_serial_disabled && serialLogActiveRead()) {
|
||||
max_lvl = _max(max_lvl, Settings.SerialLogLevel);
|
||||
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
|
||||
Serial.setDebugOutput(true);
|
||||
} else {
|
||||
Serial.setDebugOutput(false);
|
||||
}
|
||||
max_lvl = _max(max_lvl, Settings.SyslogLevel);
|
||||
max_lvl = _max(max_lvl, Settings.WebLogLevel);
|
||||
if (Logging.logActiveRead()) {
|
||||
max_lvl = _max(max_lvl, Settings.WebLogLevel);
|
||||
}
|
||||
#ifdef FEATURE_SD
|
||||
max_lvl = _max(max_lvl, Settings.SDLogLevel);
|
||||
#endif
|
||||
highest_active_log_level = max_lvl;
|
||||
}
|
||||
|
||||
@@ -1218,14 +1236,42 @@ bool loglevelActiveFor(byte logLevel) {
|
||||
return loglevelActive(logLevel, highest_active_log_level);
|
||||
}
|
||||
|
||||
byte getSerialLogLevel() {
|
||||
byte logLevelSettings = 0;
|
||||
if (!Settings.UseSerial) return 0;
|
||||
if (log_to_serial_disabled || log_to_serial_disabled_temporary) return 0;
|
||||
logLevelSettings = Settings.SerialLogLevel;
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED){
|
||||
logLevelSettings = 2;
|
||||
}
|
||||
/*
|
||||
if (!serialLogActiveRead()) {
|
||||
if (logLevelSettings != 0) {
|
||||
updateLogLevelCache();
|
||||
}
|
||||
logLevelSettings = 0;
|
||||
}
|
||||
*/
|
||||
return logLevelSettings;
|
||||
}
|
||||
|
||||
byte getWebLogLevel() {
|
||||
byte logLevelSettings = 0;
|
||||
if (Logging.logActiveRead()) {
|
||||
logLevelSettings = Settings.WebLogLevel;
|
||||
} else {
|
||||
if (Settings.WebLogLevel != 0) {
|
||||
updateLogLevelCache();
|
||||
}
|
||||
}
|
||||
return logLevelSettings;
|
||||
}
|
||||
|
||||
boolean loglevelActiveFor(byte destination, byte logLevel) {
|
||||
byte logLevelSettings = 0;
|
||||
switch (destination) {
|
||||
case LOG_TO_SERIAL: {
|
||||
if (!SerialAvailableForWrite()) return false;
|
||||
logLevelSettings = Settings.SerialLogLevel;
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED)
|
||||
logLevelSettings = 2;
|
||||
logLevelSettings = getSerialLogLevel();
|
||||
break;
|
||||
}
|
||||
case LOG_TO_SYSLOG: {
|
||||
@@ -1233,11 +1279,13 @@ boolean loglevelActiveFor(byte destination, byte logLevel) {
|
||||
break;
|
||||
}
|
||||
case LOG_TO_WEBLOG: {
|
||||
logLevelSettings = Settings.WebLogLevel;
|
||||
logLevelSettings = getWebLogLevel();
|
||||
break;
|
||||
}
|
||||
case LOG_TO_SDCARD: {
|
||||
#ifdef FEATURE_SD
|
||||
logLevelSettings = Settings.SDLogLevel;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1290,24 +1338,58 @@ void addToLog(byte logLevel, const char *line)
|
||||
|
||||
void process_serialLogBuffer() {
|
||||
if (serialLogBuffer.size() == 0) return;
|
||||
if (timePassedSince(last_serial_log_emptied) > 10000) {
|
||||
last_serial_log_emptied = millis();
|
||||
serialLogBuffer.clear();
|
||||
return;
|
||||
}
|
||||
size_t snip = 128; // Some default, ESP32 doesn't have the availableForWrite function yet.
|
||||
#if defined(ESP8266)
|
||||
snip = Serial.availableForWrite();
|
||||
#endif
|
||||
if (snip > 0) last_serial_log_emptied = millis();
|
||||
size_t bytes_to_write = serialLogBuffer.size();
|
||||
if (snip < bytes_to_write) bytes_to_write = snip;
|
||||
for (size_t i = 0; i < bytes_to_write; ++i) {
|
||||
Serial.write(serialLogBuffer.front());
|
||||
serialLogBuffer.pop_front();
|
||||
if (snip > 0) {
|
||||
last_serial_log_read = millis();
|
||||
size_t bytes_to_write = serialLogBuffer.size();
|
||||
if (snip < bytes_to_write) bytes_to_write = snip;
|
||||
for (size_t i = 0; i < bytes_to_write; ++i) {
|
||||
Serial.write(serialLogBuffer.front());
|
||||
serialLogBuffer.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tempDisableSerialLog(bool setToDisabled) {
|
||||
if (log_to_serial_disabled_temporary == setToDisabled) return;
|
||||
|
||||
// FIXME TD-er: For some reason disabling serial log will not enable it again.
|
||||
// log_to_serial_disabled_temporary = setToDisabled;
|
||||
// updateLogLevelCache();
|
||||
}
|
||||
|
||||
bool serialLogActiveRead() {
|
||||
if (!Settings.UseSerial) return false;
|
||||
// Some default, ESP32 doesn't have the availableForWrite function yet.
|
||||
// Not sure how to detect read activity on an ESP32.
|
||||
size_t tx_free = 128;
|
||||
#if defined(ESP8266)
|
||||
tx_free = Serial.availableForWrite();
|
||||
#endif
|
||||
static size_t prev_tx_free = 0;
|
||||
if (tx_free < prev_tx_free) {
|
||||
prev_tx_free = tx_free;
|
||||
tempDisableSerialLog(false);
|
||||
return true;
|
||||
}
|
||||
// Must always set it or else it will never recover from prev_tx_free == 0
|
||||
prev_tx_free = tx_free;
|
||||
if (timePassedSince(last_serial_log_read) > LOG_BUFFER_EXPIRE) {
|
||||
serialLogBuffer.clear();
|
||||
// Just add some marker to get it going again when the serial buffer is
|
||||
// read again and the serial log level was temporary set to 0 since nothing was read.
|
||||
if (Settings.SerialLogLevel > 0) {
|
||||
serialLogBuffer.push_back('\n');
|
||||
}
|
||||
tempDisableSerialLog(true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Delayed reboot, in case of issues, do not reboot with high frequency as it might not help...
|
||||
\*********************************************************************************************/
|
||||
@@ -2170,6 +2252,7 @@ for (byte x=0; x < RULESETS_MAX; x++){
|
||||
\*********************************************************************************************/
|
||||
void rulesProcessing(String& event)
|
||||
{
|
||||
if (!Settings.UseRules) return;
|
||||
checkRAM(F("rulesProcessing"));
|
||||
unsigned long timer = millis();
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
@@ -2209,6 +2292,7 @@ void rulesProcessing(String& event)
|
||||
\*********************************************************************************************/
|
||||
String rulesProcessingFile(const String& fileName, String& event)
|
||||
{
|
||||
if (!Settings.UseRules) return "";
|
||||
checkRAM(F("rulesProcessingFile"));
|
||||
if (Settings.SerialLogLevel == LOG_LEVEL_DEBUG_DEV){
|
||||
Serial.print(F("RuleDebug Processing:"));
|
||||
@@ -2504,7 +2588,7 @@ void processMatchedRule(
|
||||
{
|
||||
String tmpString = event.substring(equalsPos + 1);
|
||||
|
||||
char tmpParam[INPUT_COMMAND_SIZE];
|
||||
char* tmpParam = new char[INPUT_COMMAND_SIZE];
|
||||
tmpParam[0] = 0;
|
||||
|
||||
if (GetArgv(tmpString.c_str(),tmpParam,1)) {
|
||||
@@ -2514,6 +2598,7 @@ void processMatchedRule(
|
||||
if (GetArgv(tmpString.c_str(),tmpParam,2)) action.replace(F("%eventvalue2%"), tmpParam); // substitute %eventvalue2% in actions with the actual value from the event
|
||||
if (GetArgv(tmpString.c_str(),tmpParam,3)) action.replace(F("%eventvalue3%"), tmpParam); // substitute %eventvalue3% in actions with the actual value from the event
|
||||
if (GetArgv(tmpString.c_str(),tmpParam,4)) action.replace(F("%eventvalue4%"), tmpParam); // substitute %eventvalue4% in actions with the actual value from the event
|
||||
delete[] tmpParam;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2815,6 +2900,7 @@ boolean conditionMatch(const String& check)
|
||||
\*********************************************************************************************/
|
||||
void rulesTimers()
|
||||
{
|
||||
if (!Settings.UseRules) return;
|
||||
for (byte x = 0; x < RULES_TIMER_MAX; x++)
|
||||
{
|
||||
if (!RulesTimer[x].paused && RulesTimer[x].timestamp != 0L) // timer active?
|
||||
@@ -2837,6 +2923,7 @@ void rulesTimers()
|
||||
|
||||
void createRuleEvents(byte TaskIndex)
|
||||
{
|
||||
if (!Settings.UseRules) return;
|
||||
LoadTaskSettings(TaskIndex);
|
||||
byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
|
||||
|
||||
+76
-28
@@ -131,7 +131,7 @@ String toString(float value, byte decimals)
|
||||
|
||||
String toString(WiFiMode_t mode)
|
||||
{
|
||||
String result = F("Undefinited");
|
||||
String result = F("Undefined");
|
||||
switch (mode)
|
||||
{
|
||||
case WIFI_OFF:
|
||||
@@ -165,11 +165,13 @@ String doFormatUserVar(byte TaskIndex, byte rel_index, bool mustCheck, bool& isv
|
||||
const byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
|
||||
if (Device[DeviceIndex].ValueCount <= rel_index) {
|
||||
isvalid = false;
|
||||
String log = F("No sensor value for TaskIndex: ");
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
|
||||
String log = F("No sensor value for TaskIndex: ");
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG) {
|
||||
@@ -178,11 +180,13 @@ String doFormatUserVar(byte TaskIndex, byte rel_index, bool mustCheck, bool& isv
|
||||
float f(UserVar[BaseVarIndex + rel_index]);
|
||||
if (mustCheck && !isValidFloat(f)) {
|
||||
isvalid = false;
|
||||
String log = F("Invalid float value for TaskIndex: ");
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("Invalid float value for TaskIndex: ");
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
f = 0;
|
||||
}
|
||||
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
|
||||
@@ -210,13 +214,11 @@ String formatUserVar(struct EventStruct *event, byte rel_index, bool& isvalid)
|
||||
/*********************************************************************************************\
|
||||
Wrap a string with given pre- and postfix string.
|
||||
\*********************************************************************************************/
|
||||
String wrap_String(const String& string, const String& wrap) {
|
||||
String result;
|
||||
result.reserve(string.length() + 2* wrap.length());
|
||||
result = wrap;
|
||||
|
||||
void wrap_String(const String& string, const String& wrap, String& result) {
|
||||
result += wrap;
|
||||
result += string;
|
||||
result += wrap;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
@@ -225,19 +227,25 @@ String wrap_String(const String& string, const String& wrap) {
|
||||
String to_json_object_value(const String& object, const String& value) {
|
||||
String result;
|
||||
result.reserve(object.length() + value.length() + 6);
|
||||
result = wrap_String(object, F("\""));
|
||||
wrap_String(object, F("\""), result);
|
||||
result += F(":");
|
||||
if (value.length() == 0 || !isFloat(value)) {
|
||||
if (value.indexOf('\n') == -1 && value.indexOf('"') == -1 && value.indexOf(F("Pragma")) == -1) {
|
||||
result += wrap_String(value, F("\""));
|
||||
} else {
|
||||
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('"', '\'');
|
||||
tmpValue.replace(F("Pragma"), F("Bugje!"));
|
||||
result += wrap_String(tmpValue, F("\""));
|
||||
wrap_String(tmpValue, F("\""), result);
|
||||
} else {
|
||||
wrap_String(value, F("\""), result);
|
||||
}
|
||||
} else {
|
||||
// It is a numerical
|
||||
result += value;
|
||||
}
|
||||
return result;
|
||||
@@ -280,6 +288,26 @@ String stripQuotes(const String& text) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Parse a string and get the xth command or parameter in lower case
|
||||
\*********************************************************************************************/
|
||||
@@ -379,6 +407,7 @@ void htmlEscape(String & 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'))
|
||||
@@ -531,6 +560,8 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
|
||||
SMART_REPL(F("%systime%"), getTimeString(':'))
|
||||
SMART_REPL(F("%systime_am%"), getTimeString_ampm(':'))
|
||||
SMART_REPL(F("%sysbuild_date%"), String(CRCValues.compileDate))
|
||||
SMART_REPL(F("%sysbuild_time%"), String(CRCValues.compileTime))
|
||||
repl(F("%sysname%"), Settings.Name, s, useURLencode);
|
||||
|
||||
// valueString is being used by the macro.
|
||||
@@ -563,17 +594,34 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
SMART_REPL(F("%unixtime%"), String(getUnixTime()))
|
||||
SMART_REPL_T(F("%sunset"), replSunSetTimeString)
|
||||
SMART_REPL_T(F("%sunrise"), replSunRiseTimeString)
|
||||
|
||||
if (s.indexOf(F("%is")) != -1) {
|
||||
SMART_REPL(F("%ismqtt%"), String(MQTTclient_connected));
|
||||
SMART_REPL(F("%iswifi%"), String(wifiStatus)); //0=disconnected, 1=connected, 2=got ip, 3=services initialized
|
||||
SMART_REPL(F("%isntp%"), String(statusNTPInitialized));
|
||||
#ifdef USES_P037
|
||||
SMART_REPL(F("%ismqttimp%"), String(P037_MQTTImport_connected));
|
||||
#endif // USES_P037
|
||||
}
|
||||
const int v_index = s.indexOf("%v");
|
||||
if (v_index != -1 && isDigit(s[v_index+2])) {
|
||||
for (byte i = 0; i < CUSTOM_VARS_MAX; ++i) {
|
||||
SMART_REPL("%v"+toString(i+1,0)+'%', String(customFloatVar[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getReplacementString(const String& format, String& s) {
|
||||
int startpos = s.indexOf(format);
|
||||
int endpos = s.indexOf('%', startpos + 1);
|
||||
String R = s.substring(startpos, endpos + 1);
|
||||
String log = F("ReplacementString SunTime: ");
|
||||
log += R;
|
||||
log += F(" offset: ");
|
||||
log += getSecOffset(R);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("ReplacementString SunTime: ");
|
||||
log += R;
|
||||
log += F(" offset: ");
|
||||
log += getSecOffset(R);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
+10
-15
@@ -147,20 +147,6 @@ void breakTime(unsigned long timeInput, struct timeStruct &tm) {
|
||||
tm.Day = time + 1; // day of month
|
||||
}
|
||||
|
||||
void setTime(unsigned long t) {
|
||||
sysTime = (uint32_t)t;
|
||||
applyTimeZone(t);
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
static bool firstUpdate = true;
|
||||
String event = firstUpdate ? F("Time#Initialized") : F("Time#Set");
|
||||
firstUpdate = false;
|
||||
rulesProcessing(event);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getUnixTime() {
|
||||
return sysTime;
|
||||
}
|
||||
@@ -222,13 +208,22 @@ unsigned long now() {
|
||||
unsigned long t = getNtpTime();
|
||||
if (t != 0) {
|
||||
timeSynced = true;
|
||||
setTime(t);
|
||||
sysTime = (uint32_t)t;
|
||||
applyTimeZone(t);
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
}
|
||||
}
|
||||
uint32_t localSystime = toLocal(sysTime);
|
||||
breakTime(localSystime, tm);
|
||||
if (timeSynced) {
|
||||
calcSunRiseAndSet();
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = statusNTPInitialized ? F("Time#Set") : F("Time#Initialized");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
statusNTPInitialized = true; //@giig1967g: setting system variable %isntp%
|
||||
}
|
||||
return (unsigned long)localSystime;
|
||||
}
|
||||
|
||||
+248
-219
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -33,7 +33,7 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
C001_DelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -118,7 +118,7 @@ bool do_process_c001_delay_queue(int controller_number, const C001_queue_element
|
||||
String request = create_http_request_auth(controller_number, element.controller_idx, ControllerSettings, F("GET"), element.txt);
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG, element.txt);
|
||||
return send_via_http(controller_number, client, request);
|
||||
return send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
MQTTDelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -145,7 +145,7 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (event->idx != 0)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
/*
|
||||
if (!ControllerSettings.checkHostReachable(true)) {
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
C003_DelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -78,7 +78,7 @@ bool do_process_c003_delay_queue(int controller_number, const C003_queue_element
|
||||
client.print(" \n");
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
while (!client_available(client) && !timeOutReached(timer))
|
||||
delay(1);
|
||||
|
||||
timer = millis() + 1000;
|
||||
@@ -102,7 +102,7 @@ bool do_process_c003_delay_queue(int controller_number, const C003_queue_element
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
client.println(SecuritySettings.ControllerPassword[element.controller_idx]);
|
||||
delay(100);
|
||||
while (client.available())
|
||||
while (client_available(client))
|
||||
client.read();
|
||||
|
||||
strcpy_P(log, PSTR("TELNT: Sending cmd"));
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
C004_DelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -94,6 +94,6 @@ bool do_process_c004_delay_queue(int controller_number, const C004_queue_element
|
||||
postDataStr.length());
|
||||
postStr += postDataStr;
|
||||
|
||||
return send_via_http(controller_number, client, postStr);
|
||||
return send_via_http(controller_number, client, postStr, ControllerSettings.MustCheckReply);
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -33,7 +33,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
MQTTDelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -92,7 +92,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
if (!ControllerSettings.checkHostReachable(true)) {
|
||||
success = false;
|
||||
@@ -100,7 +100,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
statusLED(true);
|
||||
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
|
||||
+3
-3
@@ -33,7 +33,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
MQTTDelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -90,12 +90,12 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
statusLED(true);
|
||||
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
|
||||
+3
-2
@@ -32,7 +32,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
C007_DelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -78,6 +78,7 @@ bool do_process_c007_delay_queue(int controller_number, const C007_queue_element
|
||||
Serial.println(url);
|
||||
|
||||
return send_via_http(controller_number, client,
|
||||
create_http_get_request(controller_number, ControllerSettings, url));
|
||||
create_http_get_request(controller_number, ControllerSettings, url),
|
||||
ControllerSettings.MustCheckReply);
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-4
@@ -34,7 +34,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
C008_DelayHandler.configureControllerSettings(ControllerSettings);
|
||||
break;
|
||||
@@ -52,10 +52,10 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
// 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.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
@@ -97,7 +97,7 @@ bool do_process_c008_delay_queue(int controller_number, const C008_queue_element
|
||||
return false;
|
||||
|
||||
String request = create_http_request_auth(controller_number, element.controller_idx, ControllerSettings, F("GET"), element.txt[element.valuesSent]);
|
||||
return element.checkDone(send_via_http(controller_number, client, request));
|
||||
return element.checkDone(send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+57
-51
@@ -57,60 +57,20 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
C009_queue_element element(event);
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
// We now create a URI for the request
|
||||
String url = F("/ESPEasy");
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
// Create json root object
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
root[F("module")] = String(F("ESPEasy"));
|
||||
root[F("version")] = String(F("1.04"));
|
||||
|
||||
// Create nested objects
|
||||
JsonObject& data = root.createNestedObject(String(F("data")));
|
||||
JsonObject& ESP = data.createNestedObject(String(F("ESP")));
|
||||
ESP[F("name")] = Settings.Name;
|
||||
ESP[F("unit")] = Settings.Unit;
|
||||
ESP[F("version")] = Settings.Version;
|
||||
ESP[F("build")] = Settings.Build;
|
||||
ESP[F("build_notes")] = String(F(BUILD_NOTES));
|
||||
ESP[F("build_git")] = String(F(BUILD_GIT));
|
||||
ESP[F("node_type_id")] = NODE_TYPE_ID;
|
||||
ESP[F("sleep")] = Settings.deepSleep;
|
||||
|
||||
// embed IP, important if there is NAT/PAT
|
||||
// char ipStr[20];
|
||||
// IPAddress ip = WiFi.localIP();
|
||||
// sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
ESP[F("ip")] = WiFi.localIP().toString();
|
||||
|
||||
// Create nested SENSOR json object
|
||||
JsonObject& SENSOR = data.createNestedObject(String(F("SENSOR")));
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
// char itemNames[valueCount][2];
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
// Each sensor value get an own object (0..n)
|
||||
// sprintf(itemNames[x],"%d",x);
|
||||
JsonObject& val = SENSOR.createNestedObject(String(x));
|
||||
val[F("deviceName")] = getTaskDeviceName(event->TaskIndex);
|
||||
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
|
||||
val[F("type")] = event->sensorType;
|
||||
val[F("value")] = formatUserVarNoCheck(event, x);
|
||||
element.txt[x] = formatUserVarNoCheck(event, x);
|
||||
element.valueNames[x] = ExtraTaskSettings.TaskDeviceValueNames[x];
|
||||
}
|
||||
|
||||
// Create json buffer
|
||||
String jsonString;
|
||||
root.printTo(jsonString);
|
||||
|
||||
success = C009_DelayHandler.addToQueue(C009_queue_element(event->ControllerIndex, url, jsonString));
|
||||
success = C009_DelayHandler.addToQueue(element);
|
||||
scheduleNextDelayQueue(TIMER_C009_DELAY_QUEUE, C009_DelayHandler.getNextScheduleTime());
|
||||
break;
|
||||
}
|
||||
@@ -126,11 +86,57 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element
|
||||
if (!try_connect_host(controller_number, client, ControllerSettings))
|
||||
return false;
|
||||
|
||||
// Create json root object
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
root[F("module")] = String(F("ESPEasy"));
|
||||
root[F("version")] = String(F("1.04"));
|
||||
|
||||
// Create nested objects
|
||||
JsonObject& data = root.createNestedObject(String(F("data")));
|
||||
JsonObject& ESP = data.createNestedObject(String(F("ESP")));
|
||||
ESP[F("name")] = Settings.Name;
|
||||
ESP[F("unit")] = Settings.Unit;
|
||||
ESP[F("version")] = Settings.Version;
|
||||
ESP[F("build")] = Settings.Build;
|
||||
ESP[F("build_notes")] = String(F(BUILD_NOTES));
|
||||
ESP[F("build_git")] = String(F(BUILD_GIT));
|
||||
ESP[F("node_type_id")] = NODE_TYPE_ID;
|
||||
ESP[F("sleep")] = Settings.deepSleep;
|
||||
|
||||
// embed IP, important if there is NAT/PAT
|
||||
// char ipStr[20];
|
||||
// IPAddress ip = WiFi.localIP();
|
||||
// sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
ESP[F("ip")] = WiFi.localIP().toString();
|
||||
|
||||
// Create nested SENSOR json object
|
||||
JsonObject& SENSOR = data.createNestedObject(String(F("SENSOR")));
|
||||
byte valueCount = getValueCountFromSensorType(element.sensorType);
|
||||
// char itemNames[valueCount][2];
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
// Each sensor value get an own object (0..n)
|
||||
// sprintf(itemNames[x],"%d",x);
|
||||
JsonObject& val = SENSOR.createNestedObject(String(x));
|
||||
val[F("deviceName")] = getTaskDeviceName(element.TaskIndex);
|
||||
val[F("valueName")] = element.valueNames[x];
|
||||
val[F("type")] = element.sensorType;
|
||||
val[F("value")] = element.txt[x];
|
||||
}
|
||||
|
||||
// Create json buffer
|
||||
String jsonString;
|
||||
root.printTo(jsonString);
|
||||
|
||||
// We now create a URI for the request
|
||||
String url = F("/ESPEasy");
|
||||
|
||||
String request = create_http_request_auth(
|
||||
controller_number, element.controller_idx, ControllerSettings,
|
||||
F("POST"), element.url, element.json.length());
|
||||
request += element.json;
|
||||
F("POST"), url, jsonString.length());
|
||||
request += jsonString;
|
||||
|
||||
return send_via_http(controller_number, client, request);
|
||||
return send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply);
|
||||
}
|
||||
#endif
|
||||
|
||||
+11
-6
@@ -42,10 +42,10 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
C010_queue_element element(event, valueCount);
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
@@ -85,13 +85,18 @@ bool do_process_c010_delay_queue(int controller_number, const C010_queue_element
|
||||
if (element.checkDone(true))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!try_connect_host(controller_number, portUDP, ControllerSettings))
|
||||
WiFiUDP C010_portUDP;
|
||||
if (!beginWiFiUDP_randomPort(C010_portUDP)) return false;
|
||||
if (!try_connect_host(controller_number, C010_portUDP, ControllerSettings))
|
||||
return false;
|
||||
|
||||
portUDP.write(
|
||||
C010_portUDP.write(
|
||||
(uint8_t*)element.txt[element.valuesSent].c_str(),
|
||||
element.txt[element.valuesSent].length());
|
||||
return element.checkDone(portUDP.endPacket() != 0);
|
||||
bool reply = C010_portUDP.endPacket();
|
||||
C010_portUDP.stop();
|
||||
if (ControllerSettings.MustCheckReply)
|
||||
return element.checkDone(reply);
|
||||
return element.checkDone(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -133,7 +133,7 @@ bool do_process_c011_delay_queue(int controller_number, const C011_queue_element
|
||||
if (!try_connect_host(controller_number, client, ControllerSettings))
|
||||
return false;
|
||||
|
||||
return send_via_http(controller_number, client, element.txt);
|
||||
return send_via_http(controller_number, client, element.txt, ControllerSettings.MustCheckReply);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event)
|
||||
if (!WiFiConnected(100)) {
|
||||
return false;
|
||||
}
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
C011_ConfigStruct customConfig;
|
||||
@@ -158,7 +158,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event)
|
||||
if (!try_connect_host(controller_number, client, ControllerSettings))
|
||||
return false;
|
||||
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String payload = create_http_request_auth(
|
||||
|
||||
+48
-49
@@ -37,10 +37,10 @@ boolean CPlugin_012(byte function, struct EventStruct *event, String& string)
|
||||
// Collect the values at the same run, to make sure all are from the same sample
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
C012_queue_element element(event, valueCount);
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(event->ControllerIndex, ControllerSettings);
|
||||
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
@@ -73,16 +73,15 @@ bool do_process_c012_delay_queue(int controller_number, const C012_queue_element
|
||||
if (element.checkDone(true))
|
||||
return true;
|
||||
}
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
return element.checkDone(Blynk_get(element.txt[element.valuesSent], element.controller_idx));
|
||||
}
|
||||
|
||||
boolean Blynk_get(const String& command, byte controllerIndex, float *data )
|
||||
{
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(controllerIndex, ControllerSettings);
|
||||
|
||||
if ((SecuritySettings.ControllerPassword[controllerIndex][0] == 0)) {
|
||||
@@ -104,58 +103,58 @@ boolean Blynk_get(const String& command, byte controllerIndex, float *data )
|
||||
ControllerSettings.getHost().c_str());
|
||||
addLog(LOG_LEVEL_DEBUG, request);
|
||||
client.print(request);
|
||||
boolean success = !ControllerSettings.MustCheckReply;
|
||||
if (ControllerSettings.MustCheckReply || data) {
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client_available(client) && !timeOutReached(timer))
|
||||
delay(1);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
yield();
|
||||
char log[80] = {0};
|
||||
|
||||
boolean success = false;
|
||||
char log[80] = {0};
|
||||
|
||||
// Read all the lines of the reply from server and log them
|
||||
while (client_available(client)) {
|
||||
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"));
|
||||
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 );
|
||||
// Read all the lines of the reply from server and log them
|
||||
while (client_available(client)) {
|
||||
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"));
|
||||
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);
|
||||
}
|
||||
yield();
|
||||
}
|
||||
yield();
|
||||
}
|
||||
strcpy_P(log, PSTR("HTTP : closing connection (012)"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
addLog(LOG_LEVEL_DEBUG, F("HTTP : closing connection (012)"));
|
||||
|
||||
client.flush();
|
||||
client.stop();
|
||||
|
||||
// important - backgroundtasks - free mem
|
||||
timer = millis() + Settings.MessageDelay;
|
||||
unsigned long timer = millis() + Settings.MessageDelay;
|
||||
while (!timeOutReached(timer))
|
||||
backgroundtasks();
|
||||
|
||||
|
||||
+103
-78
@@ -126,10 +126,10 @@ public:
|
||||
return total;
|
||||
}
|
||||
|
||||
String txt[VARS_PER_TASK];
|
||||
int controller_idx;
|
||||
byte TaskIndex;
|
||||
int idx;
|
||||
String txt[VARS_PER_TASK];
|
||||
mutable byte valuesSent; // Value must be set by const function checkDone()
|
||||
byte valueCount;
|
||||
};
|
||||
@@ -146,19 +146,31 @@ public:
|
||||
\*********************************************************************************************/
|
||||
class C009_queue_element {
|
||||
public:
|
||||
C009_queue_element() : controller_idx(0) {}
|
||||
C009_queue_element(int ctrl_idx, const String& URI, const String& JSON) :
|
||||
controller_idx(ctrl_idx), url(URI), json(JSON) {}
|
||||
C009_queue_element() : controller_idx(0), TaskIndex(0), idx(0), sensorType(0) {}
|
||||
C009_queue_element(const struct EventStruct* event) :
|
||||
controller_idx(event->ControllerIndex),
|
||||
TaskIndex(event->TaskIndex),
|
||||
idx(event->idx),
|
||||
sensorType(event->sensorType) {}
|
||||
|
||||
size_t getSize() const {
|
||||
return sizeof(this) + url.length() + json.length();
|
||||
size_t total = sizeof(this);
|
||||
for (int i = 0; i < VARS_PER_TASK; ++i) {
|
||||
total += txt[i].length();
|
||||
total += valueNames[i].length();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
String txt[VARS_PER_TASK];
|
||||
String valueNames[VARS_PER_TASK];
|
||||
int controller_idx;
|
||||
String url;
|
||||
String json;
|
||||
byte TaskIndex;
|
||||
int idx;
|
||||
byte sensorType;
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* C010_queue_element for queueing requests for 010: Generic UDP
|
||||
* Using queue_element_single_value_base
|
||||
@@ -189,13 +201,15 @@ struct ControllerDelayHandlerStruct {
|
||||
max_queue_depth(CONTROLLER_DELAY_QUEUE_DEPTH_DFLT),
|
||||
attempt(0),
|
||||
max_retries(CONTROLLER_DELAY_QUEUE_RETRY_DFLT),
|
||||
delete_oldest(false) {}
|
||||
delete_oldest(false),
|
||||
must_check_reply(false) {}
|
||||
|
||||
void configureControllerSettings(const ControllerSettingsStruct& settings) {
|
||||
minTimeBetweenMessages = settings.MinimalTimeBetweenMessages;
|
||||
max_queue_depth = settings.MaxQueueDepth;
|
||||
max_retries = settings.MaxRetry;
|
||||
delete_oldest = settings.DeleteOldest;
|
||||
must_check_reply = settings.MustCheckReply;
|
||||
// Set some sound limits when not configured
|
||||
if (max_queue_depth == 0) max_queue_depth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT;
|
||||
if (max_retries == 0) max_retries = CONTROLLER_DELAY_QUEUE_RETRY_DFLT;
|
||||
@@ -251,15 +265,14 @@ struct ControllerDelayHandlerStruct {
|
||||
|
||||
// Get the next element.
|
||||
// Remove front element when max_retries is reached.
|
||||
bool getNext(T& element) {
|
||||
if (sendQueue.empty()) return false;
|
||||
T* getNext() {
|
||||
if (sendQueue.empty()) return NULL;
|
||||
if (attempt > max_retries) {
|
||||
sendQueue.pop_front();
|
||||
attempt = 0;
|
||||
if (sendQueue.empty()) return false;
|
||||
if (sendQueue.empty()) return NULL;
|
||||
}
|
||||
element = sendQueue.front();
|
||||
return true;
|
||||
return &sendQueue.front();
|
||||
}
|
||||
|
||||
// Mark as processed and return time to schedule for next process.
|
||||
@@ -302,6 +315,7 @@ struct ControllerDelayHandlerStruct {
|
||||
byte attempt;
|
||||
byte max_retries;
|
||||
bool delete_oldest;
|
||||
bool must_check_reply;
|
||||
};
|
||||
|
||||
ControllerDelayHandlerStruct<MQTT_queue_element> MQTTDelayHandler;
|
||||
@@ -321,17 +335,17 @@ ControllerDelayHandlerStruct<MQTT_queue_element> MQTTDelayHandler;
|
||||
ControllerDelayHandlerStruct<C##NNN##_queue_element> C##NNN##_DelayHandler; \
|
||||
bool do_process_c##NNN##_delay_queue(int controller_number, const C##NNN##_queue_element& element, ControllerSettingsStruct& ControllerSettings); \
|
||||
void process_c##NNN##_delay_queue() { \
|
||||
C##NNN##_queue_element element; \
|
||||
if (!C##NNN##_DelayHandler.getNext(element)) return; \
|
||||
ControllerSettingsStruct ControllerSettings; \
|
||||
LoadControllerSettings(element.controller_idx, ControllerSettings); \
|
||||
C##NNN##_queue_element* element(C##NNN##_DelayHandler.getNext()); \
|
||||
if (element == NULL) return; \
|
||||
MakeControllerSettings(ControllerSettings); \
|
||||
LoadControllerSettings(element->controller_idx, ControllerSettings); \
|
||||
C##NNN##_DelayHandler.configureControllerSettings(ControllerSettings); \
|
||||
if (!WiFiConnected(100)) { \
|
||||
scheduleNextDelayQueue(TIMER_C##NNN##_DELAY_QUEUE, C##NNN##_DelayHandler.getNextScheduleTime()); \
|
||||
return; \
|
||||
} \
|
||||
START_TIMER; \
|
||||
C##NNN##_DelayHandler.markProcessed(do_process_c##NNN##_delay_queue(M, element, ControllerSettings)); \
|
||||
C##NNN##_DelayHandler.markProcessed(do_process_c##NNN##_delay_queue(M, *element, ControllerSettings)); \
|
||||
STOP_TIMER(C##NNN##_DELAY_QUEUE); \
|
||||
scheduleNextDelayQueue(TIMER_C##NNN##_DELAY_QUEUE, C##NNN##_DelayHandler.getNextScheduleTime()); \
|
||||
}
|
||||
@@ -387,26 +401,30 @@ bool safeReadStringUntil(Stream &input, String &str, char terminator, unsigned i
|
||||
|
||||
do {
|
||||
//read character
|
||||
c = input.read();
|
||||
if (c >= 0) {
|
||||
//found terminator, we're ok
|
||||
if (c == terminator) {
|
||||
return(true);
|
||||
}
|
||||
//found character, add to string
|
||||
else{
|
||||
str += char(c);
|
||||
//string at max size?
|
||||
if (str.length() >= maxSize) {
|
||||
addLog(LOG_LEVEL_ERROR, F("Not enough bufferspace to read all input data!"));
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We must run the backgroundtasks every now and then.
|
||||
if (timeOutReached(backgroundtasks_timer)) {
|
||||
backgroundtasks_timer += 10;
|
||||
backgroundtasks();
|
||||
if (input.available()) {
|
||||
c = input.read();
|
||||
if (c >= 0) {
|
||||
//found terminator, we're ok
|
||||
if (c == terminator) {
|
||||
return(true);
|
||||
}
|
||||
//found character, add to string
|
||||
else{
|
||||
str += char(c);
|
||||
//string at max size?
|
||||
if (str.length() >= maxSize) {
|
||||
addLog(LOG_LEVEL_ERROR, F("Not enough bufferspace to read all input data!"));
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We must run the backgroundtasks every now and then.
|
||||
if (timeOutReached(backgroundtasks_timer)) {
|
||||
backgroundtasks_timer += 10;
|
||||
backgroundtasks();
|
||||
} else {
|
||||
yield();
|
||||
}
|
||||
} else {
|
||||
yield();
|
||||
}
|
||||
@@ -606,54 +624,61 @@ bool try_connect_host(int controller_number, WiFiClient& client, ControllerSetti
|
||||
// See: https://github.com/esp8266/Arduino/pull/5113
|
||||
// https://github.com/esp8266/Arduino/pull/1829
|
||||
bool client_available(WiFiClient& client) {
|
||||
#ifdef ESP32
|
||||
yield();
|
||||
#else
|
||||
esp_yield(); // Could be called from events
|
||||
#endif
|
||||
return client.available() || client.connected();
|
||||
}
|
||||
|
||||
bool send_via_http(const String& logIdentifier, WiFiClient& client, const String& postStr) {
|
||||
bool success = false;
|
||||
bool send_via_http(const String& logIdentifier, WiFiClient& client, const String& postStr, bool must_check_reply) {
|
||||
bool success = !must_check_reply;
|
||||
// This will send the request to the server
|
||||
client.print(postStr);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available()) {
|
||||
if (timeOutReached(timer)) return false;
|
||||
delay(1);
|
||||
}
|
||||
|
||||
// Read all the lines of the reply from server and print them to Serial
|
||||
while (client_available(client) && !success) {
|
||||
// String line = client.readStringUntil('\n');
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
|
||||
if (line.length() > 80) {
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line.substring(0, 80));
|
||||
} else {
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line);
|
||||
}
|
||||
if (must_check_reply) {
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client_available(client)) {
|
||||
if (timeOutReached(timer)) return false;
|
||||
delay(1);
|
||||
}
|
||||
if (line.startsWith(F("HTTP/1.1 2")))
|
||||
{
|
||||
success = true;
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("HTTP : ");
|
||||
log += logIdentifier;
|
||||
log += F(" Success! ");
|
||||
log += line;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// Read all the lines of the reply from server and print them to Serial
|
||||
while (client_available(client) && !success) {
|
||||
// String line = client.readStringUntil('\n');
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
|
||||
if (line.length() > 80) {
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line.substring(0, 80));
|
||||
} else {
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line);
|
||||
}
|
||||
}
|
||||
} else if (line.startsWith(F("HTTP/1.1 4"))) {
|
||||
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
|
||||
String log = F("HTTP : ");
|
||||
log += logIdentifier;
|
||||
log += F(" Error: ");
|
||||
log += line;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
if (line.startsWith(F("HTTP/1.1 2")))
|
||||
{
|
||||
success = true;
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("HTTP : ");
|
||||
log += logIdentifier;
|
||||
log += F(" Success! ");
|
||||
log += line;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
} else if (line.startsWith(F("HTTP/1.1 4"))) {
|
||||
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
|
||||
String log = F("HTTP : ");
|
||||
log += logIdentifier;
|
||||
log += F(" Error: ");
|
||||
log += line;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, postStr);
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, postStr);
|
||||
yield();
|
||||
}
|
||||
yield();
|
||||
}
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("HTTP : ");
|
||||
@@ -667,8 +692,8 @@ bool send_via_http(const String& logIdentifier, WiFiClient& client, const String
|
||||
return success;
|
||||
}
|
||||
|
||||
bool send_via_http(int controller_number, WiFiClient& client, const String& postStr) {
|
||||
return send_via_http(get_formatted_Controller_number(controller_number), client, postStr);
|
||||
bool send_via_http(int controller_number, WiFiClient& client, const String& postStr, bool must_check_reply) {
|
||||
return send_via_http(get_formatted_Controller_number(controller_number), client, postStr, must_check_reply);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -38,8 +38,8 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
//
|
||||
// if (command == F("email"))
|
||||
// {
|
||||
// NotificationSettingsStruct NotificationSettings;
|
||||
// LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
// MakeNotificationSettings(NotificationSettings);
|
||||
// LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettingsStruct));
|
||||
// NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, NotificationSettings.Subject, NotificationSettings.Body, NotificationSettings.Server, NotificationSettings.Port);
|
||||
// success = true;
|
||||
// }
|
||||
@@ -48,8 +48,8 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case NPLUGIN_NOTIFY:
|
||||
{
|
||||
NotificationSettingsStruct NotificationSettings;
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
MakeNotificationSettings(NotificationSettings);
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettingsStruct));
|
||||
String subject = NotificationSettings.Subject;
|
||||
String body = "";
|
||||
if (event->String1.length() > 0)
|
||||
|
||||
@@ -35,8 +35,8 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
//
|
||||
// if (command == F("buzzer"))
|
||||
// {
|
||||
// NotificationSettingsStruct NotificationSettings;
|
||||
// LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
// MakeNotificationSettings(NotificationSettings);
|
||||
// LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettingsStruct));
|
||||
// success = true;
|
||||
// }
|
||||
// break;
|
||||
@@ -44,8 +44,8 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case NPLUGIN_NOTIFY:
|
||||
{
|
||||
NotificationSettingsStruct NotificationSettings;
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
MakeNotificationSettings(NotificationSettings);
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettingsStruct));
|
||||
//this reserves IRAM and uninitialized RAM
|
||||
#ifndef ESP32
|
||||
// Buzzer not compatible with ESP32 due to lack of tone command.
|
||||
|
||||
+250
-51
@@ -3,6 +3,31 @@
|
||||
//#################################### Plugin 001: Input Switch #########################################
|
||||
//#######################################################################################################
|
||||
|
||||
/**************************************************\
|
||||
CONFIG
|
||||
TaskDevicePluginConfig settings:
|
||||
0: button type (switch or dimmer)
|
||||
1: dim value
|
||||
2: button option (normal, push high, push low)
|
||||
3: send boot state (true,false)
|
||||
4: use doubleclick (true,false)
|
||||
5: use longpress (true,false)
|
||||
6: LP fired (true,false)
|
||||
7: doubleclick counter (=0,1,2,3)
|
||||
|
||||
TaskDevicePluginConfigFloat settings:
|
||||
0: debounce interval ms
|
||||
1: doubleclick interval ms
|
||||
2: longpress interval ms
|
||||
3:
|
||||
|
||||
TaskDevicePluginConfigLong settings:
|
||||
0: clickTime debounce ms
|
||||
1: clickTime doubleclick ms
|
||||
2: clickTime longpress ms
|
||||
3:
|
||||
\**************************************************/
|
||||
|
||||
#define PLUGIN_001
|
||||
#define PLUGIN_ID_001 1
|
||||
#define PLUGIN_NAME_001 "Switch input - Switch"
|
||||
@@ -18,6 +43,10 @@
|
||||
#define PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH 0
|
||||
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW 1
|
||||
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH 2
|
||||
#define PLUGIN_001_DOUBLECLICK_MIN_INTERVAL 1000
|
||||
#define PLUGIN_001_DOUBLECLICK_MAX_INTERVAL 3000
|
||||
#define PLUGIN_001_LONGPRESS_MIN_INTERVAL 1000
|
||||
#define PLUGIN_001_LONGPRESS_MAX_INTERVAL 5000
|
||||
|
||||
boolean Plugin_001_read_switch_state(struct EventStruct *event) {
|
||||
return digitalRead(Settings.TaskDevicePin1[event->TaskIndex]) == HIGH;
|
||||
@@ -89,6 +118,28 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
addFormCheckBox(F("Send Boot state"),F("plugin_001_boot"),
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
|
||||
|
||||
addFormSubHeader(F("Advanced event management"));
|
||||
|
||||
addFormNumericBox(F("De-bounce (ms)"), F("plugin_001_debounce"), round(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]), 0, 250);
|
||||
|
||||
//set minimum value for doubleclick MIN max speed
|
||||
if (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] < PLUGIN_001_DOUBLECLICK_MIN_INTERVAL)
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = PLUGIN_001_DOUBLECLICK_MIN_INTERVAL;
|
||||
|
||||
addFormCheckBox(F("Doubleclick event (3)"), F("plugin_001_dc"), Settings.TaskDevicePluginConfig[event->TaskIndex][4]);
|
||||
addFormNumericBox(F("Doubleclick max. interval (ms)"), F("plugin_001_dcmaxinterval"), round(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]), PLUGIN_001_DOUBLECLICK_MIN_INTERVAL, PLUGIN_001_DOUBLECLICK_MAX_INTERVAL);
|
||||
|
||||
//set minimum value for longpress MIN max speed
|
||||
if (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2] < PLUGIN_001_LONGPRESS_MIN_INTERVAL)
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2] = PLUGIN_001_LONGPRESS_MIN_INTERVAL;
|
||||
|
||||
addFormCheckBox(F("Longpress event (10 & 11)"), F("plugin_001_lp"), Settings.TaskDevicePluginConfig[event->TaskIndex][5]);
|
||||
addFormNumericBox(F("Longpress min. interval (ms)"), F("plugin_001_lpmininterval"), round(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2]), PLUGIN_001_LONGPRESS_MIN_INTERVAL, PLUGIN_001_LONGPRESS_MAX_INTERVAL);
|
||||
|
||||
//TO-DO: add Extra-Long Press event
|
||||
//addFormCheckBox(F("Extra-Longpress event (20 & 21)"), F("plugin_001_elp"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1]);
|
||||
//addFormNumericBox(F("Extra-Longpress min. interval (ms)"), F("plugin_001_elpmininterval"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][2], 500, 2000);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -105,6 +156,18 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = isFormItemChecked(F("plugin_001_boot"));
|
||||
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = getFormItemInt(F("plugin_001_debounce"));
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = isFormItemChecked(F("plugin_001_dc"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = getFormItemInt(F("plugin_001_dcmaxinterval"));
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][5] = isFormItemChecked(F("plugin_001_lp"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2] = getFormItemInt(F("plugin_001_lpmininterval"));
|
||||
|
||||
//TO-DO: add Extra-Long Press event
|
||||
//Settings.TaskDevicePluginConfigLong[event->TaskIndex][1] = isFormItemChecked(F("plugin_001_elp"));
|
||||
//Settings.TaskDevicePluginConfigLong[event->TaskIndex][2] = getFormItemInt(F("plugin_001_elpmininterval"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -132,19 +195,48 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
switchstate[event->TaskIndex] = !switchstate[event->TaskIndex];
|
||||
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
|
||||
}
|
||||
|
||||
// set initial UserVar of the switch
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex]){
|
||||
UserVar[event->BaseVarIndex] = !switchstate[event->TaskIndex];
|
||||
} else {
|
||||
UserVar[event->BaseVarIndex] = switchstate[event->TaskIndex];
|
||||
}
|
||||
|
||||
// counter = 0
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][7]=0;
|
||||
|
||||
//used to track if LP has fired
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][6]=false;
|
||||
|
||||
//store millis for debounce, doubleclick and long press
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][0]=millis(); //debounce timer
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][1]=millis(); //doubleclick timer
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][2]=millis(); //longpress timer
|
||||
|
||||
//set minimum value for doubleclick MIN max speed
|
||||
if (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] < PLUGIN_001_DOUBLECLICK_MIN_INTERVAL)
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = PLUGIN_001_DOUBLECLICK_MIN_INTERVAL;
|
||||
|
||||
//set minimum value for longpress MIN max speed
|
||||
if (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2] < PLUGIN_001_LONGPRESS_MIN_INTERVAL)
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2] = PLUGIN_001_LONGPRESS_MIN_INTERVAL;
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_REQUEST:
|
||||
{
|
||||
String device = parseString(string, 1);
|
||||
String command = parseString(string, 2);
|
||||
String strPar1 = parseString(string, 3);
|
||||
if (device == F("gpio") && command == F("pinstate"))
|
||||
//String device = parseString(string, 1);
|
||||
//String command = parseString(string, 2);
|
||||
//String strPar1 = parseString(string, 3);
|
||||
|
||||
// returns pin value using syntax: [plugin#gpio#pinstate#xx]
|
||||
if (string.length()>=13 && string.substring(0,13).equalsIgnoreCase(F("gpio,pinstate")))
|
||||
{
|
||||
int par1;
|
||||
if (validIntFromString(strPar1, par1)) {
|
||||
if (validIntFromString(parseString(string, 3), par1)) {
|
||||
string = digitalRead(par1);
|
||||
}
|
||||
success = true;
|
||||
@@ -161,7 +253,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (PinMonitorState[x] != state){
|
||||
String eventString = F("GPIO#");
|
||||
eventString += x;
|
||||
eventString += F("=");
|
||||
eventString += '=';
|
||||
eventString += state;
|
||||
rulesProcessing(eventString);
|
||||
PinMonitorState[x] = state;
|
||||
@@ -173,51 +265,148 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
const boolean state = Plugin_001_read_switch_state(event);
|
||||
|
||||
/**************************************************************************\
|
||||
20181009 - @giig1967g: new doubleclick logic is:
|
||||
if there is a 'state' change, check debounce period.
|
||||
Then if doubleclick interval exceeded, reset Plugin_001_clickCounterDC to 0
|
||||
Plugin_001_clickCounterDC contains the current status for doubleclick:
|
||||
0: start counting
|
||||
1: 1st click
|
||||
2: 2nd click
|
||||
3: 3rd click = doubleclick event if inside interval (calculated as: '3rd click time' minus '1st click time')
|
||||
|
||||
Returned EVENT value is = 3 always for doubleclick
|
||||
In rules this can be checked:
|
||||
on Button#Switch=3 do //will fire if doubleclick
|
||||
\**************************************************************************/
|
||||
|
||||
if (state != switchstate[event->TaskIndex])
|
||||
{
|
||||
switchstate[event->TaskIndex] = state;
|
||||
const boolean currentOutputState = outputstate[event->TaskIndex];
|
||||
boolean new_outputState = currentOutputState;
|
||||
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][2]) {
|
||||
case PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH:
|
||||
new_outputState = state;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW:
|
||||
if (!state)
|
||||
new_outputState = !currentOutputState;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH:
|
||||
if (state)
|
||||
new_outputState = !currentOutputState;
|
||||
break;
|
||||
}
|
||||
//reset timer for long press
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][2]=millis();
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = false;
|
||||
|
||||
// send if output needs to be changed
|
||||
if (currentOutputState != new_outputState)
|
||||
const unsigned long debounceTime = timePassedSince(Settings.TaskDevicePluginConfigLong[event->TaskIndex][0]);
|
||||
if (debounceTime >= (unsigned long)lround(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0])) //de-bounce check
|
||||
{
|
||||
outputstate[event->TaskIndex] = new_outputState;
|
||||
boolean sendState = new_outputState;
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex])
|
||||
sendState = !sendState;
|
||||
|
||||
byte output_value = sendState ? 1 : 0;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
if (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) {
|
||||
if (sendState) {
|
||||
output_value = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
// Only set type to being dimmer when setting a value else it is "switched off".
|
||||
event->sensorType = SENSOR_TYPE_DIMMER;
|
||||
}
|
||||
const unsigned long deltaDC = timePassedSince(Settings.TaskDevicePluginConfigLong[event->TaskIndex][1]);
|
||||
if (deltaDC >= (unsigned long)lround(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]))
|
||||
{
|
||||
//reset timer for doubleclick
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][7]=0;
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][1]=millis();
|
||||
}
|
||||
UserVar[event->BaseVarIndex] = output_value;
|
||||
String log = F("SW : Switch state ");
|
||||
log += state ? F("1") : F("0");
|
||||
log += F(" Output value ");
|
||||
log += output_value;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendData(event);
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][7]++;
|
||||
|
||||
switchstate[event->TaskIndex] = state;
|
||||
const boolean currentOutputState = outputstate[event->TaskIndex];
|
||||
boolean new_outputState = currentOutputState;
|
||||
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][2])
|
||||
{
|
||||
case PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH:
|
||||
new_outputState = state;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW:
|
||||
if (!state)
|
||||
new_outputState = !currentOutputState;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH:
|
||||
if (state)
|
||||
new_outputState = !currentOutputState;
|
||||
break;
|
||||
}
|
||||
|
||||
// send if output needs to be changed
|
||||
if (currentOutputState != new_outputState)
|
||||
{
|
||||
byte output_value;
|
||||
outputstate[event->TaskIndex] = new_outputState;
|
||||
boolean sendState = new_outputState;
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex])
|
||||
sendState = !sendState;
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][7]==3 && Settings.TaskDevicePluginConfig[event->TaskIndex][4])
|
||||
{
|
||||
output_value = 3; //double click
|
||||
} else {
|
||||
output_value = sendState ? 1 : 0; //single click
|
||||
}
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
if (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) {
|
||||
if (sendState) {
|
||||
output_value = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
// Only set type to being dimmer when setting a value else it is "switched off".
|
||||
event->sensorType = SENSOR_TYPE_DIMMER;
|
||||
}
|
||||
}
|
||||
UserVar[event->BaseVarIndex] = output_value;
|
||||
String log = F("SW : Switch state ");
|
||||
log += state ? '1' : '0';
|
||||
log += F(" Output value ");
|
||||
log += output_value;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendData(event);
|
||||
}
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][0] = millis();
|
||||
}
|
||||
}
|
||||
//check if LP is enabled and if LP has not fired yet
|
||||
else if (Settings.TaskDevicePluginConfig[event->TaskIndex][5] && !Settings.TaskDevicePluginConfig[event->TaskIndex][6]) {
|
||||
/**************************************************************************\
|
||||
20181009 - @giig1967g: new longpress logic is:
|
||||
if there is no 'state' change, check if longpress interval reached
|
||||
When reached send longpress event.
|
||||
Returned Event value = state + 10
|
||||
So if state = 0 => EVENT longpress = 10
|
||||
if state = 1 => EVENT longpress = 11
|
||||
So we can trigger longpress for high or low contact
|
||||
|
||||
In rules this can be checked:
|
||||
on Button#Switch=10 do //will fire if longpress when state = 0
|
||||
on Button#Switch=11 do //will fire if longpress when state = 1
|
||||
\**************************************************************************/
|
||||
const unsigned long deltaLP = timePassedSince(Settings.TaskDevicePluginConfigLong[event->TaskIndex][2]);
|
||||
if (deltaLP >= (unsigned long)lround(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][2]))
|
||||
{
|
||||
byte output_value;
|
||||
byte needToSendEvent = false;
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = true;
|
||||
|
||||
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][2])
|
||||
{
|
||||
case PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH:
|
||||
needToSendEvent = true;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW:
|
||||
if (!state)
|
||||
needToSendEvent = true;
|
||||
break;
|
||||
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH:
|
||||
if (state)
|
||||
needToSendEvent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (needToSendEvent) {
|
||||
boolean sendState = state;
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex])
|
||||
sendState = !sendState;
|
||||
output_value = sendState ? 1 : 0;
|
||||
output_value = output_value + 10;
|
||||
|
||||
UserVar[event->BaseVarIndex] = output_value;
|
||||
String log = F("SW : LongPress: Switch state ");
|
||||
log += state ? '1' : '0';
|
||||
log += F(" Output value ");
|
||||
log += output_value;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendData(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -263,13 +452,23 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
byte mode;
|
||||
uint16_t currentState;
|
||||
|
||||
getPinState(PLUGIN_ID_001, event->Par1, &mode, ¤tState);
|
||||
if (mode == PIN_MODE_OUTPUT || mode == PIN_MODE_UNDEFINED) { //toggle only output pins
|
||||
digitalWrite(event->Par1, !currentState);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, !currentState);
|
||||
log = String(F("SW : Toggle GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(!currentState);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
if (hasPinState(PLUGIN_ID_001,event->Par1)) {
|
||||
getPinState(PLUGIN_ID_001, event->Par1, &mode, ¤tState);
|
||||
} else {
|
||||
currentState = (digitalRead(event->Par1) == HIGH);
|
||||
mode = PIN_MODE_OUTPUT;
|
||||
}
|
||||
|
||||
if (mode != PIN_MODE_INPUT) { //toggle only output pins
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, !currentState);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, !currentState);
|
||||
log = String(F("SW : Toggle GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(!currentState);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
-2
@@ -109,6 +109,24 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_REQUEST:
|
||||
{
|
||||
//parseString(string, 1) = device
|
||||
//parseString(string, 2) = command
|
||||
//parseString(string, 3) = gpio number
|
||||
|
||||
// returns pin value using syntax: [plugin#mcpgpio#pinstate#xx]
|
||||
if (string.length()>=16 && string.substring(0,16).equalsIgnoreCase(F("mcpgpio,pinstate")))
|
||||
{
|
||||
int par1;
|
||||
if (validIntFromString(parseString(string, 3), par1)) {
|
||||
string = Plugin_009_Read(par1);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
String log = "";
|
||||
@@ -130,8 +148,14 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
|
||||
byte mode;
|
||||
uint16_t currentState;
|
||||
|
||||
getPinState(PLUGIN_ID_009, event->Par1, &mode, ¤tState);
|
||||
if (mode == PIN_MODE_OUTPUT || mode == PIN_MODE_UNDEFINED) {
|
||||
if (hasPinState(PLUGIN_ID_009,event->Par1)) {
|
||||
getPinState(PLUGIN_ID_009, event->Par1, &mode, ¤tState);
|
||||
} else {
|
||||
currentState = Plugin_009_Read(event->Par1);
|
||||
mode = PIN_MODE_OUTPUT;
|
||||
}
|
||||
|
||||
if (mode != PIN_MODE_INPUT) {
|
||||
setPinState(PLUGIN_ID_009, event->Par1, PIN_MODE_OUTPUT, !currentState);
|
||||
Plugin_009_Write(event->Par1, !currentState);
|
||||
log = String(F("MCP : Toggle GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(!currentState);
|
||||
|
||||
+17
-12
@@ -21,6 +21,9 @@ int Plugin_012_mode = 1;
|
||||
#define PLUGIN_NAME_012 "Display - LCD2004"
|
||||
#define PLUGIN_VALUENAME1_012 "LCD"
|
||||
|
||||
#define P12_Nlines 4 // The number of different lines which can be displayed
|
||||
#define P12_Nchars 80
|
||||
|
||||
boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
@@ -81,9 +84,9 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
addFormSelector(F("Display Size"), F("plugin_012_size"), 2, options2, optionValues2, choice2);
|
||||
|
||||
|
||||
char deviceTemplate[4][80];
|
||||
char deviceTemplate[P12_Nlines][P12_Nchars];
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
for (byte varNr = 0; varNr < 4; varNr++)
|
||||
for (byte varNr = 0; varNr < P12_Nlines; varNr++)
|
||||
{
|
||||
addHtml(F("<TR><TD>Line "));
|
||||
addHtml(String(varNr + 1));
|
||||
@@ -122,17 +125,19 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_12_timer"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_012_mode"));
|
||||
|
||||
char deviceTemplate[4][80];
|
||||
for (byte varNr = 0; varNr < 4; varNr++)
|
||||
char deviceTemplate[P12_Nlines][P12_Nchars];
|
||||
String error;
|
||||
for (byte varNr = 0; varNr < P12_Nlines; varNr++)
|
||||
{
|
||||
char argc[25];
|
||||
String arg = F("Plugin_012_template");
|
||||
arg += varNr + 1;
|
||||
arg.toCharArray(argc, 25);
|
||||
String tmpString = WebServer.arg(argc);
|
||||
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr]));
|
||||
String argName = F("Plugin_012_template");
|
||||
argName += varNr + 1;
|
||||
if (!safe_strncpy(deviceTemplate[varNr], WebServer.arg(argName), P12_Nchars)) {
|
||||
error += getCustomTaskSettingsError(varNr);
|
||||
}
|
||||
}
|
||||
if (error.length() > 0) {
|
||||
addHtmlError(error);
|
||||
}
|
||||
|
||||
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
success = true;
|
||||
break;
|
||||
@@ -194,7 +199,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
char deviceTemplate[4][80];
|
||||
char deviceTemplate[P12_Nlines][P12_Nchars];
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
|
||||
for (byte x = 0; x < Plugin_012_rows; x++)
|
||||
|
||||
+45
-8
@@ -11,7 +11,7 @@
|
||||
boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
static byte switchstate[TASKS_MAX];
|
||||
static boolean switchstate[TASKS_MAX];
|
||||
|
||||
switch (function)
|
||||
{
|
||||
@@ -23,7 +23,7 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].Ports = 8;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].InverseLogicOption = true;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
@@ -66,10 +66,17 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
// read and store current state to prevent switching at boot time
|
||||
switchstate[event->TaskIndex] = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]);
|
||||
|
||||
// if boot state must be send, inverse default state
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
switchstate[event->TaskIndex] = !switchstate[event->TaskIndex];
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex]){
|
||||
UserVar[event->BaseVarIndex] = !switchstate[event->TaskIndex];
|
||||
} else {
|
||||
UserVar[event->BaseVarIndex] = switchstate[event->TaskIndex];
|
||||
}
|
||||
|
||||
// if boot state must be send, inverse default state
|
||||
// this is done to force the trigger in PLUGIN_TEN_PER_SECOND
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) {
|
||||
switchstate[event->TaskIndex] = !switchstate[event->TaskIndex];
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -85,7 +92,13 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
log += state;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
switchstate[event->TaskIndex] = state;
|
||||
UserVar[event->BaseVarIndex] = state;
|
||||
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex]){
|
||||
UserVar[event->BaseVarIndex] = !switchstate[event->TaskIndex];
|
||||
} else {
|
||||
UserVar[event->BaseVarIndex] = switchstate[event->TaskIndex];
|
||||
}
|
||||
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
sendData(event);
|
||||
}
|
||||
@@ -105,6 +118,24 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_REQUEST:
|
||||
{
|
||||
//parseString(string, 1) = device
|
||||
//parseString(string, 2) = command
|
||||
//parseString(string, 3) = gpio number
|
||||
|
||||
// returns pin value using syntax: [plugin#pcfgpio#pinstate#xx]
|
||||
if (string.length()>=16 && string.substring(0,16).equalsIgnoreCase(F("pcfgpio,pinstate")))
|
||||
{
|
||||
int par1;
|
||||
if (validIntFromString(parseString(string, 3), par1)) {
|
||||
string = Plugin_019_Read(par1);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
String log = "";
|
||||
@@ -134,8 +165,14 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
|
||||
byte mode;
|
||||
uint16_t currentState;
|
||||
|
||||
getPinState(PLUGIN_ID_019, event->Par1, &mode, ¤tState);
|
||||
if (mode == PIN_MODE_OUTPUT || mode == PIN_MODE_UNDEFINED) {
|
||||
if (hasPinState(PLUGIN_ID_019,event->Par1)) {
|
||||
getPinState(PLUGIN_ID_019, event->Par1, &mode, ¤tState);
|
||||
} else {
|
||||
currentState = Plugin_019_Read(event->Par1);
|
||||
mode = PIN_MODE_OUTPUT;
|
||||
}
|
||||
|
||||
if (mode != PIN_MODE_INPUT) {
|
||||
setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, !currentState);
|
||||
Plugin_019_Write(event->Par1, !currentState);
|
||||
log = String(F("PCF : Toggle GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(!currentState);
|
||||
|
||||
+20
-11
@@ -15,6 +15,9 @@
|
||||
#define PLUGIN_VALUENAME1_023 "OLED"
|
||||
#define PLUGIN_023_MAX_DYSPALY 2
|
||||
|
||||
#define P23_Nlines 8 // The number of different lines which can be displayed
|
||||
#define P23_Nchars 64
|
||||
|
||||
struct Plugin_023_OLED_SettingStruct
|
||||
{
|
||||
Plugin_023_OLED_SettingStruct(): address(0)
|
||||
@@ -94,7 +97,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
int optionValues4[2] = { 1, 2 };
|
||||
addFormSelector(F("Font Width"), F("plugin_023_font_width"), 2, options4, optionValues4, choice4);
|
||||
|
||||
char deviceTemplate[8][64];
|
||||
char deviceTemplate[P23_Nlines][P23_Nchars];
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
for (byte varNr = 0; varNr < 8; varNr++)
|
||||
{
|
||||
@@ -117,16 +120,19 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_023_size"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = getFormItemInt(F("plugin_023_font_width"));
|
||||
|
||||
char deviceTemplate[8][64];
|
||||
for (byte varNr = 0; varNr < 8; varNr++)
|
||||
char deviceTemplate[P23_Nlines][P23_Nchars];
|
||||
String error;
|
||||
for (byte varNr = 0; varNr < P23_Nlines; varNr++)
|
||||
{
|
||||
String arg = F("Plugin_023_template");
|
||||
arg += varNr + 1;
|
||||
String tmpString = WebServer.arg(arg);
|
||||
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])-1);
|
||||
deviceTemplate[varNr][63]=0;
|
||||
String argName = F("Plugin_023_template");
|
||||
argName += varNr + 1;
|
||||
if (!safe_strncpy(deviceTemplate[varNr], WebServer.arg(argName), P23_Nchars)) {
|
||||
error += getCustomTaskSettingsError(varNr);
|
||||
}
|
||||
}
|
||||
if (error.length() > 0) {
|
||||
addHtmlError(error);
|
||||
}
|
||||
|
||||
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
success = true;
|
||||
break;
|
||||
@@ -203,7 +209,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
char deviceTemplate[8][64];
|
||||
char deviceTemplate[P23_Nlines][P23_Nchars];
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
int index = Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0x3C
|
||||
? 0
|
||||
@@ -228,8 +234,10 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
? 0
|
||||
: 1;
|
||||
String arguments = String(string);
|
||||
|
||||
//Fixed bug #1864
|
||||
int dotPos = arguments.indexOf('.');
|
||||
if(dotPos > -1)
|
||||
if(dotPos > -1 && arguments.substring(dotPos,dotPos+4).equalsIgnoreCase(F("oled")))
|
||||
{
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
String name = arguments.substring(0,dotPos);
|
||||
@@ -245,6 +253,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int argIndex = arguments.indexOf(',');
|
||||
if (argIndex)
|
||||
arguments = arguments.substring(0, argIndex);
|
||||
|
||||
@@ -41,7 +41,7 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[10];
|
||||
String options[11];
|
||||
options[0] = F("Uptime");
|
||||
options[1] = F("Free RAM");
|
||||
options[2] = F("Wifi RSSI");
|
||||
@@ -52,7 +52,8 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
|
||||
options[7] = F("IP 3.Octet");
|
||||
options[8] = F("IP 4.Octet");
|
||||
options[9] = F("Web activity");
|
||||
addFormSelector(F("Indicator"), F("plugin_026"), 10, options, NULL, choice);
|
||||
options[10] = F("Free Stack");
|
||||
addFormSelector(F("Indicator"), F("plugin_026"), 11, options, NULL, choice);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -124,6 +125,11 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
|
||||
value = (millis()-lastWeb)/1000; // respond in seconds
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
value = getCurrentFreeStack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
UserVar[event->BaseVarIndex] = value;
|
||||
String log = F("SYS : ");
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
|
||||
// unsigned long IrSecondCode=0UL;
|
||||
char ircodestr[100];
|
||||
if (GetArgv(command, TmpStr1,100, 2)) IrType = TmpStr1;
|
||||
if (GetArgv(command, TmpStr1, 100, 3)){ IrCode = strtoul(TmpStr1, NULL, 16);
|
||||
if (GetArgv(command, TmpStr1, 100, 3)){ IrCode = strtoull(TmpStr1, NULL, 16);
|
||||
memcpy(ircodestr, TmpStr1, sizeof(TmpStr1[0])*100);
|
||||
}
|
||||
//if (GetArgv(command, TmpStr1, 100, 4)) IrBits = str2int(TmpStr1); //not needed any more... leave it for reverce compatibility or remove it and break existing instalations?
|
||||
|
||||
@@ -180,15 +180,18 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][5] = getFormItemInt(F("plugin_036_controler"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = getFormItemInt(F("plugin_036_contrast"));
|
||||
|
||||
String argName;
|
||||
|
||||
String error;
|
||||
for (byte varNr = 0; varNr < P36_Nlines; varNr++)
|
||||
{
|
||||
argName = F("Plugin_036_template");
|
||||
String argName = F("Plugin_036_template");
|
||||
argName += varNr + 1;
|
||||
strncpy(P036_deviceTemplate[varNr], WebServer.arg(argName).c_str(), sizeof(P036_deviceTemplate[varNr]));
|
||||
if (!safe_strncpy(P036_deviceTemplate[varNr], WebServer.arg(argName), P36_Nchars)) {
|
||||
error += getCustomTaskSettingsError(varNr);
|
||||
}
|
||||
}
|
||||
if (error.length() > 0) {
|
||||
addHtmlError(error);
|
||||
}
|
||||
|
||||
SaveCustomTaskSettings(event->TaskIndex, (byte*)&P036_deviceTemplate, sizeof(P036_deviceTemplate));
|
||||
|
||||
success = true;
|
||||
|
||||
@@ -63,6 +63,8 @@ void Plugin_037_update_connect_status() {
|
||||
}
|
||||
if (MQTTclient_037_connected != connected) {
|
||||
MQTTclient_037_connected = !MQTTclient_037_connected;
|
||||
P037_MQTTImport_connected = MQTTclient_037_connected;
|
||||
|
||||
if (Settings.UseRules) {
|
||||
String event = connected ? F("MQTTimport#Connected") : F("MQTTimport#Disconnected");
|
||||
rulesProcessing(event);
|
||||
@@ -392,7 +394,7 @@ boolean MQTTConnect_037()
|
||||
Plugin_037_update_connect_status();
|
||||
return false; // Not connected, so no use in wasting time to connect to a host.
|
||||
}
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
MakeControllerSettings(ControllerSettings);
|
||||
LoadControllerSettings(enabledMqttController, ControllerSettings);
|
||||
if (ControllerSettings.UseDNS) {
|
||||
MQTTclient_037->setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
|
||||
|
||||
+55
-54
@@ -2,7 +2,7 @@
|
||||
//#######################################################################################################
|
||||
//################################### Plugin 075: Nextion <info@sensorio.cz> ###########################
|
||||
//################################### Created on the work of majklovec ###########################
|
||||
//################################### Revisions by BertB and ThomasB ###########################
|
||||
//################################### Revisions by BertB and ThomasB ###########################
|
||||
//################################### Last Revision: Oct-03-2018 (TB) ###########################
|
||||
//#######################################################################################################
|
||||
//
|
||||
@@ -36,18 +36,18 @@
|
||||
#define PLUGIN_VALUENAME2_075 "value"
|
||||
|
||||
// Configuration Settings. Custom Configuration Memory must be less than 1024 Bytes (per TD'er findings).
|
||||
//#define Nlines 12 // Custom Config, Number of user entered Command Statment Lines. DO NOT USE!
|
||||
//#define Lenlines 64 // Custom Config, Length of user entered Command Statment Lines. DO NOT USE!
|
||||
#define Nlines 10 // Custom Config, Number of user entered Command Statments.
|
||||
#define Lenlines 51 // Custom Config, Length of user entered Command Statments.
|
||||
//#define P75_Nlines 12 // Custom Config, Number of user entered Command Statment Lines. DO NOT USE!
|
||||
//#define P75_Nchars 64 // Custom Config, Length of user entered Command Statment Lines. DO NOT USE!
|
||||
#define P75_Nlines 10 // Custom Config, Number of user entered Command Statments.
|
||||
#define P75_Nchars 51 // Custom Config, Length of user entered Command Statments.
|
||||
|
||||
// Nextion defines
|
||||
#define RXBUFFSZ 64 // Serial RxD buffer (Local staging buffer and ESPeasySoftwareSerial).
|
||||
#define RXBUFFSZ 64 // Serial RxD buffer (Local staging buffer and ESPeasySoftwareSerial).
|
||||
#define RXBUFFWARN RXBUFFSZ-16 // Warning, Rx buffer close to being full.
|
||||
#define TOUCH_BASE 500 // Base offset for 0X65 Touch Event Send Component ID.
|
||||
|
||||
// Serial defines
|
||||
#define B9600 0
|
||||
#define B9600 0
|
||||
#define B38400 1
|
||||
#define B57600 2
|
||||
#define B115200 3
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
// Global vars
|
||||
ESPeasySoftwareSerial *SoftSerial = NULL;
|
||||
char deviceTemplate[Nlines][Lenlines];
|
||||
char deviceTemplate[P75_Nlines][P75_Nchars];
|
||||
int rxPin = -1;
|
||||
int txPin = -1;
|
||||
|
||||
@@ -67,10 +67,10 @@ int txPin = -1;
|
||||
// PlugIn starts here
|
||||
// *****************************************************************************************************
|
||||
|
||||
boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
static uint8_t BaudCode = 0; // Web GUI baud rate drop down. 9600 if 0, See array for other rates.
|
||||
static uint8_t BaudCode = 0; // Web GUI baud rate drop down. 9600 if 0, See array for other rates.
|
||||
static boolean HwSerial = SOFTSERIAL; // Serial mode, hardware uart or softserial.
|
||||
static boolean AdvHwSerial = false; // Web GUI checkbox flag; false = softserial mode, true = hardware UART serial.
|
||||
static boolean IncludeValues = false; // Web GUI checkbox flag; false = don't send idx & value data at interval.
|
||||
@@ -134,7 +134,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
if (!((rxPin == 3 && txPin == 1) || (rxPin == 13 && txPin == 15))) { // Hardware Serial Compatible?
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = false; // Not HW serial compatible, Reset Check Box.
|
||||
}
|
||||
|
||||
|
||||
if (rxPin == 3 && txPin == 1) { // UART USB Port?
|
||||
if(Settings.TaskDevicePluginConfig[event->TaskIndex][0]==false && // Hardware serial currently disabled.
|
||||
Settings.TaskDeviceEnabled[event->TaskIndex] == true) { // Plugin is enabled.
|
||||
@@ -142,10 +142,10 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == false) { // SoftSerial mode.
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == false) { // SoftSerial mode.
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = B9600; // Reset to 9600 baud.
|
||||
}
|
||||
|
||||
|
||||
if(rxPin <0 || txPin <0) { // Missing serial I/O pins!
|
||||
addFormNote(F("Please configure the RX and TX sensor pins before enabling this plugin."));
|
||||
addFormSubHeader(F("")); // Blank line, vertical space.
|
||||
@@ -161,13 +161,13 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
options[1] = F("38400");
|
||||
options[2] = F("57600");
|
||||
options[3] = F("115200");
|
||||
|
||||
addFormSelector(F("Baud Rate"), F("plugin_075_baud"), 4, options, NULL, choice);
|
||||
|
||||
addFormSelector(F("Baud Rate"), F("plugin_075_baud"), 4, options, NULL, choice);
|
||||
addFormNote(F("Un-check box for Soft Serial communication (low performance mode, 9600 Baud)."));
|
||||
addFormNote(F("Hardware Serial is available when the GPIO pins are RX=D7 and TX=D8."));
|
||||
addFormNote(F("D8 (GPIO-15) requires a Buffer Circuit (PNP transistor) or ESP boot may fail."));
|
||||
addFormNote(F("Do <b>NOT</b> enable the Serial Log file on Tools->Advanced->Serial Port."));
|
||||
|
||||
|
||||
// ** DEVELOPER DEBUG MESSAGE AREA **
|
||||
// int datax = (int)(Settings.TaskDeviceEnabled[event->TaskIndex]); // Debug value.
|
||||
// String Data = "Debug. Plugin Enable State: ";
|
||||
@@ -176,12 +176,12 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
addFormSubHeader(F("")); // Blank line, vertical space.
|
||||
addFormHeader(F("Nextion Command Statements (Optional)"));
|
||||
|
||||
char deviceTemplate[Nlines][Lenlines];
|
||||
|
||||
char deviceTemplate[P75_Nlines][P75_Nchars];
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
for (byte varNr = 0; varNr < Nlines; varNr++) {
|
||||
addFormTextBox(String(F("Line ")) + (varNr + 1), String(F("Plugin_075_template")) + (varNr + 1), deviceTemplate[varNr], Lenlines-1);
|
||||
|
||||
for (byte varNr = 0; varNr < P75_Nlines; varNr++) {
|
||||
addFormTextBox(String(F("Line ")) + (varNr + 1), String(F("Plugin_075_template")) + (varNr + 1), deviceTemplate[varNr], P75_Nchars-1);
|
||||
|
||||
}
|
||||
if( Settings.TaskDeviceTimer[event->TaskIndex]==0) { // Is interval timer disabled?
|
||||
if(IncludeValues) {
|
||||
@@ -202,17 +202,18 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE: {
|
||||
|
||||
String argName;
|
||||
|
||||
char deviceTemplate[Nlines][Lenlines];
|
||||
for (byte varNr = 0; varNr < Nlines; varNr++)
|
||||
char deviceTemplate[P75_Nlines][P75_Nchars];
|
||||
String error;
|
||||
for (byte varNr = 0; varNr < P75_Nlines; varNr++)
|
||||
{
|
||||
String arg = F("Plugin_075_template");
|
||||
arg += varNr + 1;
|
||||
String tmpString = WebServer.arg(arg);
|
||||
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])-1);
|
||||
deviceTemplate[varNr][Lenlines-1]=0;
|
||||
String argName = F("Plugin_075_template");
|
||||
argName += varNr + 1;
|
||||
if (!safe_strncpy(deviceTemplate[varNr], WebServer.arg(argName), P75_Nchars)) {
|
||||
error += getCustomTaskSettingsError(varNr);
|
||||
}
|
||||
}
|
||||
if (error.length() > 0) {
|
||||
addHtmlError(error);
|
||||
}
|
||||
if(getTaskDeviceName(event->TaskIndex) == "") { // Check to see if user entered device name.
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName,PLUGIN_DEFAULT_NAME); // Name missing, populate default name.
|
||||
@@ -244,7 +245,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
txPin = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
}
|
||||
|
||||
if (SoftSerial != NULL) {
|
||||
if (SoftSerial != NULL) {
|
||||
delete SoftSerial;
|
||||
SoftSerial = NULL;
|
||||
}
|
||||
@@ -293,7 +294,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
HwSerial = SOFTSERIAL;
|
||||
if (SoftSerial == NULL) {
|
||||
SoftSerial = new ESPeasySoftwareSerial(rxPin, txPin, false, RXBUFFSZ);
|
||||
}
|
||||
}
|
||||
SoftSerial->begin(9600);
|
||||
SoftSerial->flush();
|
||||
}
|
||||
@@ -305,8 +306,8 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
|
||||
case PLUGIN_READ: {
|
||||
char deviceTemplate[Nlines][Lenlines];
|
||||
case PLUGIN_READ: {
|
||||
char deviceTemplate[P75_Nlines][P75_Nchars];
|
||||
int RssiIndex;
|
||||
String newString;
|
||||
String tmpString;
|
||||
@@ -315,7 +316,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
|
||||
|
||||
// Get optional LINE command statements. Special RSSIBAR bargraph keyword is supported.
|
||||
for (byte x = 0; x < Nlines; x++) {
|
||||
for (byte x = 0; x < P75_Nlines; x++) {
|
||||
tmpString = deviceTemplate[x];
|
||||
if (tmpString.length()) {
|
||||
UcTmpString = deviceTemplate[x];
|
||||
@@ -323,7 +324,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
RssiIndex = UcTmpString.indexOf(F("RSSIBAR")); // RSSI bargraph Keyword found, wifi value in dBm.
|
||||
if(RssiIndex >= 0) {
|
||||
int barVal;
|
||||
newString.reserve(Lenlines+10); // Prevent re-allocation
|
||||
newString.reserve(P75_Nchars+10); // Prevent re-allocation
|
||||
newString = tmpString.substring(0, RssiIndex);
|
||||
int nbars = WiFi.RSSI();
|
||||
if (nbars < -100 || nbars >= 0)
|
||||
@@ -356,9 +357,9 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
sendCommand(newString.c_str(), HwSerial);
|
||||
#ifdef DEBUG_LOG
|
||||
#ifdef DEBUG_LOG
|
||||
String log;
|
||||
log.reserve(Lenlines+50); // Prevent re-allocation
|
||||
log.reserve(P75_Nchars+50); // Prevent re-allocation
|
||||
log = F("NEXTION075 : Cmd Statement Line-");
|
||||
log += String(x+1);
|
||||
log += F(" Sent: ");
|
||||
@@ -389,31 +390,31 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
#endif
|
||||
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Nextion commands received from events (including http) get processed here. PLUGIN_WRITE
|
||||
// Nextion commands received from events (including http) get processed here. PLUGIN_WRITE
|
||||
// does NOT process publish commands that are sent.
|
||||
case PLUGIN_WRITE: {
|
||||
|
||||
|
||||
String tmpString = string;
|
||||
int argIndex = tmpString.indexOf(',');
|
||||
if (argIndex) tmpString = tmpString.substring(0, argIndex);
|
||||
|
||||
|
||||
// Enable addLog() code below to help debug plugin write problems.
|
||||
/*
|
||||
String log;
|
||||
log.reserve(140); // Prevent re-allocation
|
||||
String log = F("Nextion arg0: ");
|
||||
log += tmpString;
|
||||
log += tmpString;
|
||||
log += F(", TaskDeviceName: ");
|
||||
log += getTaskDeviceName(event->TaskIndex);
|
||||
log += F(", event->TaskIndex: ");
|
||||
log += String(event->TaskIndex);
|
||||
log += String(event->TaskIndex);
|
||||
log += F(", cmd str: ");
|
||||
log += string;
|
||||
log += string;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
*/
|
||||
if (tmpString.equalsIgnoreCase(getTaskDeviceName(event->TaskIndex)) == true) { // If device names match we have a command to write.
|
||||
@@ -425,7 +426,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
log.reserve(110); // Prevent re-allocation
|
||||
log = F("NEXTION075 : WRITE = ");
|
||||
log += tmpString;
|
||||
#ifdef DEBUG_LOG
|
||||
#ifdef DEBUG_LOG
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
SendStatus(event->Source, log); // Reply (echo) to sender. This will print message on browser.
|
||||
@@ -457,7 +458,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND: {
|
||||
uint16_t i;
|
||||
uint8_t c;
|
||||
@@ -467,7 +468,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
String Svalue;
|
||||
String Nswitch;
|
||||
char __buffer[RXBUFFSZ+1]; // Staging buffer.
|
||||
|
||||
|
||||
if(rxPin < 0) {
|
||||
String log = F("NEXTION075 : Missing RxD Pin, aborted serial receive");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
@@ -534,7 +535,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c == '|') {
|
||||
__buffer[0] = c; // Store in staging buffer.
|
||||
@@ -545,7 +546,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
else charCount = SoftSerial->available();
|
||||
|
||||
if(HwSerial == UARTSERIAL) {
|
||||
i = 1;
|
||||
i = 1;
|
||||
while (Serial.available() > 0 && i<RXBUFFSZ) { // Copy global serial buffer to local buffer.
|
||||
__buffer[i] = Serial.read();
|
||||
if (__buffer[i]==0x0a || __buffer[i]==0x0d) break;
|
||||
@@ -553,7 +554,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = 1;
|
||||
i = 1;
|
||||
while (SoftSerial->available() > 0 && i<RXBUFFSZ) { // Copy global serial buffer to local buffer.
|
||||
__buffer[i] = SoftSerial->read();
|
||||
if (__buffer[i]==0x0a || __buffer[i]==0x0d) break;
|
||||
@@ -562,7 +563,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
__buffer[i] = 0x00;
|
||||
|
||||
|
||||
String tmpString = __buffer;
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
@@ -632,7 +633,7 @@ boolean Plugin_075(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
|
||||
void sendCommand(const char *cmd, boolean SerialMode)
|
||||
void sendCommand(const char *cmd, boolean SerialMode)
|
||||
{
|
||||
if(txPin < 0) {
|
||||
String log = F("NEXTION075 : Missing TxD Pin Number, aborted sendCommand");
|
||||
|
||||
+1
-2
@@ -1252,11 +1252,10 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
|
||||
// Schedule the plugin to be read.
|
||||
schedule_task_device_timer_at_init(event->TaskIndex);
|
||||
}
|
||||
if (Function != PLUGIN_GET_DEVICEVALUENAMES) {
|
||||
if (ExtraTaskSettings.TaskIndex != event->TaskIndex) {
|
||||
// LoadTaskSettings may call PLUGIN_GET_DEVICEVALUENAMES.
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
}
|
||||
|
||||
event->BaseVarIndex = event->TaskIndex * VARS_PER_TASK;
|
||||
checkRAM(F("PluginCall_init"),x);
|
||||
START_TIMER;
|
||||
|
||||
Reference in New Issue
Block a user