Files
ESPEasy/docs/source/Rules/Rules.rst
T

1263 lines
34 KiB
ReStructuredText

Rules
*****
Introduction
============
Along with ESP Easy R108, a new feature was enabled, named Rules.
Rules can be used to create very simple flows to control devices on your ESP.
Enable Rules
------------
To enable rules, :menuselection:`Tools --> Advanced` and check the Rules checkbox.
After clicking Submit, you will find a new page added. Here you can start
experimenting with Rules:
[ADD_GUI_PICTURE]
The example above shows an experiment with a LED, connected via a resistor of
1k to GPIO12 and to ground.
A virtual switch needs to be created in the "Devices" section to allow the
reading the state of the LED (on or off). The Device needs to be "Switch Input"
with the following settings:
* Device Name - E1SW1
* Enabled - Ticked
* Internal Pull-Up - Ticked
* 1st GPIO - GPIO-12(D6)
* Switch Type - Switch
* Switch Button Type - Normal Switch
After rebooting the ESP, the LED will start blinking 10 seconds on then 10 seconds off.
Enjoy.
Special Notations
-----------------
* ``[...#...]`` Referring to task variable
* ``%...%`` Referring to system variable
* ``{...:...}`` Referring to String conversions
* Quotes (single, double or back quotes) Marking begin and end of a command parameter
Syntax
------
The syntax of a rule can be single line:
.. code-block:: none
on <trigger> do <action> endon
or multi-line (need to be closed with an "endon"):
.. code-block:: none
on <trigger> do
<action>
<action>
<action>
endon
IF/ELSE - IF/ELSEIF/ELSE
------------------------
Also simple if ... else ... statements are possible:
.. code-block:: none
on <trigger> do
if <test>
<action>
<action>
else
<action>
endif
endon
If the "else" part is not needed it can be removed:
.. code-block:: none
on <trigger> do
if <test>
<action>
<action>
endif
endon
Also more complex if ... elseif ... else statements are possible (multiple elseif's can be used)
.. code-block:: none
on <trigger> do
if <test1>
<action>
<action>
elseif <test2>
<action>
<action>
else
<action>
endif
endon
Again, if the "else" part is not needed it can be removed:
.. code-block:: none
on <trigger> do
if <test1>
<action>
<action>
elseif <test2>
<action>
<action>
elseif <test3>
<action>
<action>
endif
endon
AND/OR
------
Only simple if/else was possible in older versions, there was this workaround
for the limitation of not being able to nest. An "event" can be called from a
"trigger". This possibility of nesting events is also limited , due to its
consumption of stack space (IRAM). Depending on plug-ins in use this might
lead to unpredictable, unreliable behavior, advice is not to exceed 3 levels
of nesting.
.. code-block:: none
on <trigger> do
if <test1>
event,<EventName1>
endif
endon
on <EventName1> do
if <test2>
<action>
endif
endon
As of mega-201803.. we have the possibility to use AND/OR:
.. code-block:: none
on test do
if [test#a]=0 or [test#b]=0 or [test#c]=0
event,ok
else
event,not_ok
endif
endon
on test2 do
if [test#a]=1 and [test#b]=1 and [test#c]=1
event,ok
else
event,not_ok
endif
endon
on test3 do
if [test#a]=1 and [test#b]=1 or [test#c]=0
event,ok
else
event,not_ok
endif
endon
on test4 do
if [test#a]=0
event,ok
else
event,not_ok
endif
endon
Up to two AND/OR can be used per if statement, that means that you can test
three float values and if the statement is true/false corresponding action will take place.
Trigger
-------
.. code-block:: none
<trigger>
The trigger can be an device value being changed:
.. code-block:: none
DeviceName#ValueName
Operator (inequality function)
------------------------------
Or a inequality function:
.. code-block:: none
DeviceName#ValueName<inequality function><value>
Where the "inequality function" is a simple check:
.. code-block:: none
equal (=) to
less (<) than
greater (>) than
less or equal (<=) to
greater or equal (>=) to
not equal (!= or <>) to
DeviceName#ValueName<<value>
DeviceName#ValueName=<value>
DeviceName#ValueName><value>
DeviceName#ValueName>=<value>
DeviceName#ValueName<=<value>
DeviceName#ValueName!=<value>
DeviceName#ValueName<><value>
(System) events
---------------
Some special cases are these system triggers which is triggered upon
boot/reboot/time/sleep etc. of the unit:
.. include:: ../Plugin/P000_events.repl
Test
----
.. code-block:: none
<test>
As described in the trigger section the test is a check done by checking
if the DeviceName#ValueName is meeting a criteria:
.. code-block:: none
[DeviceName#ValueName]<inequality function><value>
Where the value must be a float value with a dot as decimal sign. The
DeviceName#ValueName is closed by (square) brackets "[" and "]".
Action
------
.. code-block:: none
<action>
The action can be any system command found in the [ADD_LINK].
Also plugin specific command are available as long as the plugin is in use.
In the case mentioned earlier we use a action to trigger multiple logics
tests (the "event" command).
Comment
-------
If you want you can add comments to any row in your rules code. Just
remember to add them after the code and always begin with "//":
.. code-block:: none
on <trigger> do //If this happens then do that...
if <test>
<action>
<action>
else
<action>
endif //this is another comment
endon
Referring values
----------------
Rules and some plugins can use references to other (dynamic) values within ESPeasy.
The syntax for referring other values is: ``[...#...]``
Sometimes it can be useful to have some extra options, each separated using a '#' like this: ``[...#...#...]``
Reference to a value of a specific task: ``[TaskName#ValueName]``
Referring a value using some pre-defined format: ``[TaskName#ValueName#transformation#justification]``
For example, there is a task named "bme280" which has a value named "temperature".
Its value can be referenced like this: ``[bme280#temperature]``.
This can be used in some plugins like the "OLED Framed" plugin to populate some lines on the display.
It can also be used in rules. Every occurance of this text will then be replaced by its value.
N.B. these references to task values only yield a value when the task is enabled and its value is valid.
Special task names
------------------
You must not use the task names ``Plugin``, ``var`` ``int`` as these have special meaning.
``Plugin`` can be used in a so called ``PLUGIN_REQUEST``, for example:
``[Plugin#GPIO#Pinstate#N]`` to get the pin state of a GPIO pin.
``Var`` and ``int`` are used for internal variables.
The variables set with the ``Let`` command will be available in rules
as ``var#N`` or ``int#N`` where ``N`` is 1..16.
For example: ``Let,10,[var#9]``
N.B. ``int`` and ``var`` use the same variable, only ``int`` does round them to 0 decimals.
N.B.2 ``int`` is added in build 20190916.
``Clock``, ``Rules`` and ``System`` etc. are not recommended either since they are used in
event names.
Please observe that task names are case insensitive meaning that VAR, var, and Var etc.
are all treated the same.
Parameter parsing
-----------------
A command used in rules can have several parameters.
A parameter is typically separated by a comma, but for convenience the separator can also
be accompanied by a space or be a single space.
So these can be used to separate a parameter:
* comma
* comma space
* space comma
* space
* space space
This does impose some restrictions on the use of a comma or a space in a parameter.
Especially sending JSON to a MQTT controller can become next to impossible with these limitations.
In order to allow the comma or space in a parameter, you can wrap the parameter in quotes.
* Single quote (')
* Double quote (")
* Back quote (added to builds after 2019/11/10)
There are multiple quotes available for this, to be able to use "the other quote" in your parameter.
For example in JSON, you need the double quote for string like values or keys.
.. code-block:: none
Publish domoticz/in,{"idx":26,"nvalue":0,"svalue":"[AQ#TVOC]"}
This can be fixed by wrapping the last parameter with single quotes like this:
.. code-block:: none
Publish domoticz/in,'{"idx":26,"nvalue":0,"svalue":"[AQ#TVOC]"}'
Just make sure to use the same quote as start and end of your parameter and don't use that character in the parameter itself.
N.B. these extra quotes are removed from the parameter when used, as well as trailing or leading spaces.
The reason this behavior was changed from before 2019/11 was that the old implementation could lead to unpredictable results.
Formatting refered values
-------------------------
When referring another value, some basic formatting can be used.
Referring a value using some pre-defined format: ``[TaskName#ValueName#transformation#justification]``
Transformation
^^^^^^^^^^^^^^
* Transformations are case sensitive. (``M`` differs from ``m``, capital is more verbose)
* Transformations can not be used on "Plugin" calls, like ``[Plugin#GPIO#Pinstate#N]``, since these already use multiple occurences of ``#``.
* Most transformations work on "binary" values (logic values 0 or 1)
* A "binary" transformation can be "inverted" by adding a leading ``!``.
* A "binary" value is considered 0 when its string value is "0" or empty, otherwise it is an 1. (float values are rounded)
* A "binary" value can also be used to detect presence of a string, as it is 0 on an empty string or 1 otherwise.
* If the transformation contains ``R``, under certain circumstances, the value will be right-aligned.
Binary transformations:
* ``C``: 0 => "CLOSE" 1 => " OPEN"
* ``c``: 0 => "CLOSED" 1 => " OPEN"
* ``H``: 0 => "COLD" 1 => " HOT"
* ``I``: 0 => "OUT" 1 => " IN"
* ``L``: 0 => " LEFT" 1 => "RIGHT"
* ``l``: 0 => "L" 1 => "R"
* ``M``: 0 => "AUTO" 1 => " MAN"
* ``m``: 0 => "A" 1 => "M"
* ``O``: 0 => "OFF" 1 => " ON"
* ``U``: 0 => "DOWN" 1 => " UP"
* ``u``: 0 => "D" 1 => "U"
* ``V``: value = value without transformations
* ``X``: 0 => "O" 1 => "X"
* ``Y``: 0 => " NO" 1 => "YES"
* ``y``: 0 => "N" 1 => "Y"
* ``Z``: 0 => "0" 1 => "1"
Floating point transformations:
* ``Dx.y``: Minimal 'x' digits zero filled & 'y' decimal fixed digits. E.g. ``[bme#T#D2.1]``
* ``Dx``: Minimal 'x' digits zero filled in front of the decimal point, no decimal digits. Same as ``Dx.0``
* ``D.y``: Same as ``D0.y``
* ``d``: Same as ``D`` but spaces insted zeros
* ``F``: Floor (round down)
* ``E``: cEiling (round up)
Other transformations:
* ``p``: Password display, replacing all value characters by asterisks ``*``. If the value is "0", nothing will be displayed.
* ``pc``: Password display with custom character ``c``. For example p- will display value "123" as "---". If the value is "0", nothing will be displayed.
Justification
^^^^^^^^^^^^^
To apply a justification, a transformation must also be used. If no transformation is needed, use the ``V`` (value) transformation.
* ``Pn``: Prefix Fill with n spaces.
* ``Sn``: Suffix Fill with n spaces.
* ``Ln``: Left part of the string, n characters.
* ``Rn``: Right part of the string, n characters.
* ``Ux.y``: Substring Ux.y where x=firstChar and y=number of characters.
* ``C``: Capitalize first character of each word (space/period separated).
* ``u``: Uppercase entire value.
* ``l``: Lowercase entire value.
String Formatting and Interpreting
----------------------------------
(added 2020/02/24)
String operator commands described here can be recognized by their wrapping curly braces.
This helps recognize task values (``[taskname#varname]``) in these commands.
Substring
^^^^^^^^^
It is possible to process sub strings, for example when working with ``%eventvalue%`` in rules.
Usage: ``{substring:<startpos>:<endpos>:<string>}``
The position arguments are the same as in Arduino ``String::substring`` , meaning the endpos is 1 position further than the last character you need.
For example:
.. code-block:: none
on DS-1#Temperature do
logentry,{substring:0:1:%eventvalue%}
logentry,{substring:1:2:%eventvalue%}
logentry,{substring:2:3:%eventvalue%}
endon
The ``%eventvalue%`` may contain the value "23.06"
The output in the log will then be:
.. code-block:: none
1512372 : Info : EVENT: DS-1#Temperature=23.06
1512404 : Info : ACT : logentry,2
1512405 : Info : Command: logentry
1512406 : Info : 2
1512409 : Info : ACT : logentry,3
1512410 : Info : Command: logentry
1512410 : Info : 3
1512413 : Info : ACT : logentry,.
1512414 : Info : Command: logentry
1512415 : Info : .
N.B. it is also possible to concatenate these and refer to ``{taskname#varname}``.
For example (bit useless example, just for illustrative purposes):
.. code-block:: none
on DS-1#Temperature do
logentry,{substring:0:2:{strtol:16:{substring:0:2:[DS-1#Temperature]}{substring:3:5:[DS-1#Temperature]}}}
endon
.. code-block:: none
221313 : Info : EVENT: DS-1#Temperature=22.13
221346 : Info : parse_string_commands cmd: substring:0:2:22.13 -> 22
221347 : Info : parse_string_commands cmd: substring:3:5:22.13 -> 13
221348 : Info : parse_string_commands cmd: strtol:16:2213 -> 8723
221349 : Info : parse_string_commands cmd: substring:0:2:8723 -> 87
221350 : Info : ACT : logentry,87
221351 : Info : Command: logentry
221353 : Info : 87
strtol
^^^^^^
Strings or substrings can be converted from just about any base value (binary, octal, hexadecimal) into an integer value.
Usage: ``{strtol:16:<string>}`` to convert HEX (base 16) into an integer value.
Example of extracting sub strings from a value and interpreting as if they were HEX values:
.. code-block:: none
on DS-1#Temperature do
logentry,{strtol:16:%eventvalue%}
logentry,{strtol:16:{substring:3:5:%eventvalue%}}
endon
.. code-block:: none
1987550 : Info : EVENT: DS-1#Temperature=24.12
1987586 : Info : ACT : logentry,36
1987587 : Info : Command: logentry
1987588 : Info : 36
1987591 : Info : ACT : logentry,18
1987592 : Info : Command: logentry
1987593 : Info : 18
What we see here is the interpretation of "24.12":
* 0x24 = 36
* 0x12 = 18
Example use case:
As a use case, imagine the output of ser2net (P020) from an OpenTherm gateway.
* Message coming from the serial interface: **T101813C0**
* The B denotes that the message is from the
* The next 4 bytes (actually 2bytes hex encoded) denote the status and type of the message.
* the last 4 bytes (actually 2bytes hex encoded) denote the payload.
* Message that ends up in rules when using ser2net (P020) and Generic handling: ``!Serial#BT101813C0``
The room temperature in this sample is 19.75 C
Get the last four bytes in packs of two bytes:
* ``{substring:13:15:%eventvalue%}``
* ``{substring:15:17:%eventvalue%}``
Parsing them to decimal representation each (using a base 16 call to strtol):
* ``{strtol:16:{substring:13:15:%eventvalue%}}``
* ``{strtol:16:{substring:15:17:%eventvalue%}}``
Last but not least the fraction is not correct, it needs to be divided by 256 (and multiplied by 100)
* ``{strtol:16:{substring:15:17:%eventvalue%}}*100/255``
Complete rule used to parse this and set a variable in a dummy device:
.. code-block:: none
// Room temperature
on !Serial#T1018* do
TaskValueSet 2,1,{strtol:16:{substring:13:15:%eventvalue%}}.{strtol:16:{substring:15:17:%eventvalue%}}*100/255
endon
ord
^^^
Give the ordinal/integer value of the first character of a string. (e.g. ASCII integer value)
Usage: ``{ord:<string>}``
For example:
.. code-block:: none
on DS-1#Temperature do
logentry,{ord:A} // ASCII value of 'A'
logentry,{ord:{substring:2:3:%eventvalue%}} // ASCII value of 3rd character of %eventvalue%
endon
.. code-block:: none
2982455 : Info : EVENT: DS-1#Temperature=23.12
2982487 : Info : ACT : logentry,65
2982488 : Info : Command: logentry
2982489 : Info : 65
2982492 : Info : ACT : logentry,46
2982493 : Info : Command: logentry
2982494 : Info : 46
System variables
----------------
There is a large number of system variables.
These do not refer to task values, but to typical system variables like system uptime, current time and date, etc.
These can all be seen on the ``<ip-address>/sysvars`` page.
N.B. These values cannot be formatted like the task value references.
Best practice
-------------
It is possible to use CAPITAL letters and lower case as you please but best
practice is to use the same types of letters that are found in the
[ADD_LINK], and plugin specific commands. For the logics (on, if, else ... )
the general idea is to use lower case.
Regarding spaces in names it is recommended to NOT use them as it makes bug
testing rules a lot harder. Spaces between chunks of code is possible to make
the code more readable:
.. code-block:: none
[DeviceName#ValueName]<<value> //These work...
[DeviceName#ValueName] < <value> //the same...
Sometimes there is limited space to use a reference, like in some plugins
or when the maximum size of a rule file has been reached.
In such cases it is adviced to use short names for tasks and values.
For example: ``[bme#T]`` instead of ``[bme280#temperature]``
Some working examples
=====================
TaskValueSet
------------
Dummy Device is a single way to store and read value on variable.
Just create Generic - Dummy Device and variables inside it.
.. code-block:: none
TaskValueSet,TASKnr,VARnr,Value
This example for two switches that toggle one device (LED and Relay on GPIO 13 and 16).
.. code-block:: none
on sw1#state do
if [dummy#var1]=0
TaskValueSet 12,1,0
else
TaskValueSet 12,1,1
endif
gpio,16,[dummy#var1]
gpio,13,[dummy#var1]
endon
on sw1a#state do
if [dummy#var1]=0
TaskValueSet 12,1,1
else
TaskValueSet 12,1,0
endif
gpio,16,[dummy#var1]
gpio,13,[dummy#var1]
endon
Please note that the values stored in a Dummy Value are of type float.
This does mean you only have about 20 bits of resolution for the value.
Storing large numbers like the unix time (31 bits of resolution needed) do need some tricks to be stored.
For the Unix time there are now 2 variables included:
- %unixday%
- %unixday_sec%
Here some example used to store the Unix time in the dummy plugin to keep track of actions.
The values stored in the Dummy variables will be kept and restored on a crash/reboot as long as the ESP remains powered.
.. code-block:: none
if [DT#YMD]=0 and %unixday%>0
taskvalueset,7,1,%unixday%-1
endif
if %unixday%>0
let,5,%unixday%-[DT#YMD]
let,4,%v5%*86400-[DT#HMS]+%unixday_sec%
else
let,4,0
endif
if %v4%>[Config#MinWateringDelay]
event,Irrigate
endif
Event value (%eventvalue%)
--------------------------
Rules engine specific:
%eventvalue% - substitutes the event value (everything that comes after
the '=' sign, up to four values are possible).
Sample rules section:
.. code-block:: none
on remoteTimerControl do
timerSet,1,%eventvalue%
endon
Now send this command to the ESP:
.. code-block:: none
http://<espeasyip>/control?cmd=event,remoteTimerControl=5
and it will set rules timer no 1 to 5 seconds. Using this technique you can
parse a value from an event to the rule engine.
It is possible to use multiple event values. Some system events generate multiple event values.
For example, the ``Rules#Timer`` event has 2 event values (since build 2020/08/12):
* ``%eventvalue1%`` has the timer number (1 ... max timer ID)
* ``%eventvalue2%`` has the loop count for loop timers (since build 2020/08/12)
.. note::
'timerSet' is a rule command and cannot be run directly from a remote command.
If you want to check the transferred value within rules on the receiving ESP
(condition in if-statement), you will need to write the transferred value into
a Dummy device using the TaskValueSet command. It is then possible to check
the value of the Dummy device as condition in if-statement within rules.
Multiple event values:
.. code-block:: none
on ToggleGPIO do
GPIO,%eventvalue1%,%eventvalue2%
endon
You could then use the command "ToggleGPIO" with dynamic GPIO numbers and state.
.. code-block:: none
http://<espeasyip>/control?cmd=event,ToggleGPIO=12,1
Internal variables
------------------
A really great feature to use is the 16 internal variables. You set them like this:
.. code-block:: none
Let,<n>,<value>
Where n can be 1 to 16 and the value an float. To use the values in strings you can
either use the ``%v7%`` syntax or ``[var#7]``. BUT for formulas you need to use the square
brackets in order for it to compute, i.e. ``[var#12]``.
Averaging filters
-----------------
You may want to clear peaks in otherwise jumpy measurements and if you cannot
remove the jumpiness with hardware you might want to add a filter in the software.
A **10 value average**:
.. code-block:: none
On Temp#Value Do
Let,10,[VAR#9]
Let,9,[VAR#8]
Let,8,[VAR#7]
Let,7,[VAR#6]
Let,6,[VAR#5]
Let,5,[VAR#4]
Let,4,[VAR#3]
Let,3,[VAR#2]
Let,2,[VAR#1]
Let,1,[Temp#Value]
TaskValueSet,12,1,([VAR#1]+[VAR#2]+[VAR#3]+[VAR#4]+[VAR#5]+[VAR#6]+[VAR#7]+[VAR#8]+[VAR#9]+[VAR#10])/10
EndOn
In the above example we use the sensor value of ``Temp#Value`` to get the trigger event,
we then add all the previous 9 values to the internal variables and the newly acquired
value to the first variable. We then summarize them and divide them by 10 and store it
as a dummy variable (example is on task 12, value 1) which we use to publish the sliding
value instead of the sensor value.
Another filter could be to just use the previous value and **dilute** the new value with that one:
.. code-block:: none
On Temp#Value Do
Let,2,[VAR#1]
Let,1,[Temp#Value]
TaskValueSet,12,1,(3*[VAR#1]+[VAR#2])/4
EndOn
Yet another filter could be to add the new value to a **summarized average**:
.. code-block:: none
On Temp#Value Do
Let,1,[Temp#Value]
TaskValueSet,12,1,([VAR#1]+3*[VAR#2])/4
Let,2,[Dummy#Value]
EndOn
What you should use? That is a case by case question. Try them all and see which
one suits your actual scenario the best.
PIR and LDR
-----------
.. code-block:: none
On PIR#State do
if [LDR#Light]<500
gpio,16,[PIR#State]
endif
endon
.. note::
In other words: If the PIR switch is set (to either 1 or 0) and if
the light value < 500, then set GPIO port 16 of the ESP.
.. code-block:: none
on PIR#State=1 do
if [LDR#Light]<500
gpio,16,[PIR#State]
endif
endon
Now the event is only triggered when the PIR switches on.
SR04 and LDR
------------
.. code-block:: none
on SR04#range<100 do
if [ldr#lux]<500
gpio,2,0
gpio,16,1
else
gpio,2,1
gpio,16,0
endif
endon
Timer
-----
Until 2020/08/12, there were 8 timers. (1-8)
Builds made after this date support 256 timers. (1-256)
.. code-block:: none
On System#Boot do //When the ESP boots, do
servo,1,12,0
timerSet,1,10 //Set Timer 1 for the next event in 10 seconds
endon
On Rules#Timer=1 do //When Timer1 expires, do
servo,1,12,30
timerSet,2,1 //Set Timer 2 for the next event in 1 second
endon
On Rules#Timer=2 do //When Timer2 expires, do
servo,1,12,0
timerSet,1,30 //Set Timer1 for the next event in 30 seconds
endon
Timers can also be paused and resumed using resp. ``timerPause`` and ``timerResume``.
Sub-second resolution and loop timers
-------------------------------------
Added on 2020/08/12:
* ``timerSet_ms`` To set the timer with msec resolution.
* ``loopTimerSet`` To create a repeating timer with constant interval.
* ``loopTimerSet_ms`` Same as ``loopTimerSet``, with msec interval.
Here a small example to show how to start/stop and pause loop timers.
This can be used to create quite complex timing schemas, especially when
using multiple timers which are set to a relative prime interval.
N.B. the 2nd eventvalue of ``Rules#Timer`` has the number of loops.
.. code-block:: html
On System#Boot do //When the ESP boots, do
looptimerset_ms,1,2000,10 // Start loop timer 1, 2000 msec interval, 10 loops
looptimerset_ms,2,2500 // Start loop timer 2, 2500 msec interval
endon
On Rules#Timer=1 do
if %eventvalue2% >= 5
timerSet,1,0 // Stop timer 1
endif
//pulse some led on pin 2 shortly
Pulse,2,0,50
logentry,%eventvalue2% // log the loop count
endon
On Rules#Timer=2 do
if %eventvalue2% = 2
loopTimerSet_ms,2,2500 // Restart loop timer 2 (thus clearing loop count)
timerResume,1
else
timerPause,1
endif
endon
Starting/stopping repeating timers with events
----------------------------------------------
To disable an existing timer, set it to 0. This is useful to make repeating
timers for things like alarms or warnings:
.. code-block:: none
//start the warning signal when we receive a start_warning event:
On start_warning do
timerSet,1,2
endon
//stop the warning signal when we receive a stop_warning event:
On stop_warning do
timerSet,1,0
endon
//create an actual warning signal, every time timer 1 expires:
On Rules#Timer=1 do
//repeat after 2 seconds
timerSet,1,2
//pulse some led on pin 4 shortly
Pulse,4,1,100
//produce a short 1000hz beep via a piezo element on pin 14
tone,14,1000,100
endon
To start or stop the warning signal use http:
.. code-block:: none
http://<espeasyip>/control?cmd=event,start_warning
http://<espeasyip>/control?cmd=event,stop_warning
HTTP call
---------
When you enter this first command with the correct IP address in the URL of your browser:
.. code-block:: none
http://<espeasyip>/control?cmd=event,startwatering
http://<espeasyip>/control?cmd=event,stopwatering
And have this rule in the addressed ESP:
.. code-block:: none
On startwatering do
gpio,12,1 //start watering (open valve)
timerSet,1,600 //timer 1 set for 10 minutes
endon
On stopwatering do
timerSet,1,0 //timer 1 set to halt, used to stop watering before the timer ends!
gpio,12,0 //stop watering (close valve)
endon
On Rules#Timer=1 do
gpio,12,0 //stop watering (close valve)
endOn
Provided that you also have the valve etc., the plants will be happy.
SendTo and Publish
------------------
With SendTo you can add a Rule to your ESP Easy, capable of sending an event to another unit.
This can be useful in cases where you want to take immediate action.
There are two flavors:
- SendTo to send remote unit control commands using the internal peer to peer UDP messaging
- Publish to send remote commands to other ESP using MQTT broker
SendTo: SendTo <unit>,<command>
Imagine you have two ESP Easy modules, ESP#1 and ESP#2
In the Rules section of ESP#1 you have this:
.. code-block:: none
on demoEvent do
sendTo,2,event,startwatering //(to use the previous example.)
endon
And ESP#2 has the rules according to the previous example (givemesomewater)
If you then enter this with the correct IP address in the URL of your browser:
.. code-block:: none
http://<ESP#1-ip >/control?cmd=event,demoEvent
Then ESP#1 shall send the event 'startwatering ' to ESP#2.
It is also possible to directly order GPIO changes, like:
.. code-block:: none
on demoEvent do
sendTo,2,GPIO,2,1
endon
Publish
.. code-block:: none
Publish,<topic>,<value>
To be created.
Time
----
With Rules you can also start or stop actions on a given day and time, or even on every day.
.. code-block:: none
On Clock#Time=All,18:25 do // every day at 18:25 hours do ...
gpio,14,0
endon
Or for a specific day:
.. code-block:: none
On Clock#Time=Sun,18:25 do // for Sunday, but All, Sun, Mon, Tue, Wed, Thu, Fri, Sat will do.
gpio,14,0
endon
It is also possible to use the system value %systime% in rules conditions
to make things happen during certain hours of the day:
.. code-block:: none
On Pir#State=1 do
If %systime% < 07:00:00
Gpio,16,0
Endif
If %systime% > 19:00:00
Gpio,16,1
Endif
Endon
This will set GPIO 16 to 1 when the PIR is triggered, if the time is
before 7 in the morning or after 19:00 in the evening
( useful if you don't have a light sensor).
SendToHTTP
----------
To send a message to another device, like a command to switch on a light to Domoticz
.. code-block:: none
On System#Boot do //When the ESP boots, do
timerSet,1,10 //Set Timer 1 for the next event in 10 seconds
endon
On Rules#Timer=1 do //When Timer1 expires, do
SendToHTTP 192.168.0.243,8080,/json.htm?type=command&param=switchlight&idx=174&switchcmd=On
endon
Many users have reported problems with commands being truncated, particularly
when trying to send commands to Domoticz. It seems to be a parsing error.
There is the following workaround:
.. code-block:: none
SendToHTTP 192.168.0.243,8080,/json.htm?type=param=switchlight&command&idx=174&switchcmd=On
Dew Point for temp/humidity sensors (BME280 for example)
--------------------------------------------------------
If you have a sensor that is monitoring the air temperature and the relative
humidity you may calculate the dew point with rules. This example use MQTT to
publish the values but you may change this to whatever you want. We also make
use of a 'dummy device' to dump values, this example use two BME280 with
different i2c addresses.
For dew point on the 'outside':
.. code-block:: none
on TempHumidityPressure_OUTSIDE#%RH do
TaskValueSet,7,1,[TempHumidityPressure_OUTSIDE#°C]-(100-[TempHumidityPressure_OUTSIDE#%RH])/5 // "7" is the number of the task that the dummy device is on, "1" is its first value where we dump our result
if [TempHumidityPressure_OUTSIDE#%RH]>49
Publish,%sysname%/DewPoint_OUTSIDE/°C,[Dew_point#°C1]
else
Publish,%sysname%/DewPoint_OUTSIDE/°C,[Dew_point#°C1]* //This asterix shows that the calculation is not correct due to the humidity being below 50%!
endif
endon
For dew point on the 'inside':
.. code-block:: none
on TempHumidityPressure_INSIDE#%RH do
TaskValueSet,7,2,[TempHumidityPressure_INSIDE#°C]-(100-[TempHumidityPressure_INSIDE#%RH])/5 // "7" is the number of the task that the dummy device is on, "2" is its second value where we dump our result
if [TempHumidityPressure_INSIDE#%RH]>49
Publish,%sysname%/DewPoint_INSIDE/°C,[Dew_point#°C2]
else
Publish,%sysname%/DewPoint_INSIDE/°C,[Dew_point#°C2]* //This asterix shows that the calculation is not correct due to the humidity being below 50%!
endif
endon
Report IP every 30 seconds using MQTT
-------------------------------------
This rule also work as a ping or heart beat of the unit. If it has not
published a IP number for 30+ seconds the unit is experiencing problems.
.. code-block:: none
On System#Boot do //When the ESP boots, do
Publish,%sysname%/IP,%ip%
timerSet,1,30 //Set Timer 1 for the next event in 30 seconds
endon
On Rules#Timer=1 do //When Timer1 expires, do
Publish,%sysname%/IP,%ip%
timerSet,1,30 //Resets the Timer 1 for another 30 seconds
endon
Custom reports to Domoticz with own IDX
---------------------------------------
This rule was presented as a workaround for a problem where a sensor had
three different values but only one IDX value. You could publish your own
Domoticz messages (MQTT or HTTP) using this method. Below we use the INA219
plugin that have 3 values which of the two second ones are Amps and Watts,
just as an example we want to publish these as custom messages with a unique IDX value.
*MQTT*
.. code-block:: none
on INA219#Amps do
Publish domoticz/in,{"idx":123456,"nvalue":0,"svalue":"[INA219#Amps]"} //Own made up IDX 123456
endon
on INA219#Watts do
Publish domoticz/in,{"idx":654321,"nvalue":0,"svalue":"[INA219#Watts]"} //Own made up IDX 654321
endon
*HTTP*
.. code-block:: none
on INA219#Amps do
SendToHTTP 192.168.1.2,8080,/json.htm?type=command&param=udevice&idx=123456&nvalue=0&svalue=[INA219#Amps] //Own made up IDX 123456
endon
on INA219#Watts do
SendToHTTP 192.168.1.2,8080,/json.htm?type=command&param=udevice&idx=654321&nvalue=0&svalue=[INA219#Watts] //Own made up IDX 654321
endon
(Given that your Domoticz server is on "192.168.1.2:8080", you should change
to your server IP and PORT number. If the HTTP publishing is not working,
please refer to this [ADD_LINK] for a workaround.)
One button, multiple actions using long press
---------------------------------------------
Using a "normal switch" device which is in this example normally set to low
(0) you can make one of two actions when pressed. If you either release the
button in less than a second or press it for more than a second:
.. code-block:: none
on Button#State=1 do
timerSet,1,1
endon
on rules#timer=1 do
if [Button#State]=0
//Action if button is short pressed
else
//Action if button is still pressed
endif
endon
Calculating water consumption
-----------------------------
Using the pulse counter you can calculate and act on waterflow and changes like this:
.. code-block:: none
On System#Boot do // When the ESP boots, do
TaskValueSet,3,1,0 // TaskValueSet TASKnr,VARnr,Value, Reset the Liters counter to 0
TaskValueSet,3,2,0 // TaskValueSet TASKnr,VARnr,Value, Reset the PreviousLiters counter to 0
TaskValueSet,3,3,0 // TaskValueSet TASKnr,VARnr,Value, Reset the Flow counter to 0
TaskValueSet,3,4,0 // TaskValueSet TASKnr,VARnr,Value, Reset the PreviousFlow counter to 0
TimerSet,1,30 // Set Timer 1 for the next event in 30 seconds
EndOn
On Watermeter#Count do // When Pulse is detected
if [Watermeter#Count] > 0
SendToHTTP,192.168.1.50,8084,/json.htm?type=command&param=udevice&idx=337&nvalue=0&svalue=1
TaskValueSet,3,3,60000/[Watermeter#Time]
SendToHTTP,192.168.1.50,8084,/json.htm?type=command&param=udevice&idx=338&nvalue=0&svalue=[Liters#Flow]
endif
EndOn
On Rules#Timer=1 do // When Timer 1 expires, do
if [Liters#Flow] > 0 or [Liters#PreviousFlow] > 0 // Only send value if amount of Liters > 0
SendToHTTP,192.168.1.50,8084,/json.htm?type=command&param=udevice&idx=338&nvalue=0&svalue=[Liters#Flow]
TaskValueSet,3,4,[Liters#Flow] // set flow to previous counter
TaskValueSet,3,3,0
endif
TimerSet,1,30 // Set Timer 1 for the next event in 30 seconds
Endon