Events Programming
The EVENTS programming environment is based on a simple language that associates one or more actions to a field event or combination of conditions.
Programming EVENTS is as simple as editing the events.txt file, located in the main directory. Compared to Java, there is no compilation process. When you save the file, it is automatically reloaded and becomes immediately effective.
Contents
Introduction
An event is an expression that refers to the persistent status or transient event of devices, to conditions applied to local variables, and to various internal events. An action is a control command sent to a device, or several other internal functions, like setting variables and program timers.
Example:
IO k.33 = 1 : IO k.34 = 1
when the light actuator with data point name k.33 is turned on, HSYCO automatically turns on the actuator with data point name k.34.
Example:
DAY : IO k.33 k.34 k.35 k.36 = 0
at sunrise, the actuators named k.33, k.34, k.35 and k.36 are turned off.
In this chapter we will describe the general format of events.txt, and all the built-in events and actions.
The events.txt file is usually modified with the text editor in HSYCO’s File Manager. When you save the file, it is automatically checked and, if errors are found, a warning icon appears in the top bar.
Touch that icon to show the list of errors. Errors are also written in the log file. Lines containing errors are ignored.
You can also enable the editor’s syntax highlighter for improved readability.
The EVENTS Language
EVENTS uses the simple format:
event : actions
Several events can be combined together to implement complex expressions which represent the combination of different conditions.
The logical operators AND, OR, NOT and the round brackets are available to define the operations precedence.
If the brackets are not used, the AND and OR operations are executed from left to right. The NOT operator has priority and is executed on the first expression after it, before AND or OR conditions.
Example:
IO k.33 OR IO K.34
this event occurs any time the actuators 33 or 34 change their status.
Example:
CAMERA "entrance" AND NOT IO K.34 = 0
is an event that occurs when the camera “entrance” starts recording, but only if the K.34 datapoint is not 0.
Example:
IO k.33 > 5 OR IO K.34 = 0 AND IO K.35 = 0
is equivalent to
(IO k.33 > 5 OR IO K.34 = 0) AND IO K.35 = 0
Example:
NOT IO k.33 = 1 AND IO k.34 = 1
is equivalent to
(NOT IO k.33 = 1) AND IO k.34 = 1
Comments
Comments are vital to describe the functions, even if the EVENTS language is very easy to understand.
A comment is identified by the # character.
All characters following # will be ignored until the end of line, unless the # character is enclosed between double quotes.
Example:
# actions executed at sunset NIGHT: IO k.33 k.34 k.35 k.36 = 1, # garden lights on IO k.43 k.44 = UP, # rise the awnings LOG = "# and this is not a comment"
Other General Rules
Keywords are case insensitive. Devices ids are also case insensitive. The EVENTS interpreter converts all ids to lower case, so it is recommended to use only lower case ids in hsyco.ini if you use EVENTS.
The built-in constant values (ON, OFF, UP, DOWN, STOP, FLIP, RECON, RECOFF, MERGE, UNMERGE, PLAY) can be written in capital letters or in lower case. All other custom values will retain the case.
Example:
IO k.43 = UP and IO k.44 = DOWN : CAMERA cam1 = 60
is equivalent to:
io k.43 = up AND io k.44 = down : camera cam1 = 60
Example:
IO k.36 = 1 : UISET message.text = "Stairs light ON"
The text “Stairs light ON” remains unchanged.
Spaces and not-relevant tabulation characters are ignored.
In some cases separation spaces are not necessary:
IO k.36=1
is a valid expression, while
IOk.36 = 1
is not valid because the keywords must be separated by their attributes.
The EVENTS interpreter tries to understand strings even when not enclosed in double quotes, but we consider a good practice to always use double quotes to delimit text strings, and this may even become mandatory in future releases.
Example:
IO k.36 = 1 : LOG = "I turn on the light: 36"
Stable and transient events
IO k.33
is a transient event. It occurs only during the status change of the actuator with data point name k.33. If it is part of a complex expression, it will be true only when the expression evaluation is triggered by that specific change event, and will be false when the expression evaluation is triggered by any other event. For example:
IO k.33 AND IO k.32
is an event that will never occur, because two transient events can never be simultaneously true.
A stable event is value based condition. For example:
IO k.33 > 40
is a stable event. It occurs when the status value of actuator k.33 is greater than 40 (more than 40% of a dimmer level).
Unlike the transient events, this expression is true anyway, even after the transient event, so:
IO k.33 > 40 AND IO k.34 > 40
is an event that may occur when both the actuators k.33 and k.34 are on with a level greater than 40%.
In some cases it would be necessary to use a transient event associated to a device, also combined with status expressions of the device itself.
Example:
IO k.33 = 1 AND IO k.34 = 1 AND NOT IO k.33
The expression NOT IO k.33 excludes the events generated from any status change of device k.33. Meanwhile IO k.33 = 1 makes the expression true only when the device status is ON.
As a result, this event occurs when the devices k.33 and k.34 are simultaneously ON, but only on the status change of device k.34, and ignoring the status change of device k.33.
Example:
IO k.33 = 1 AND IO k.34 = 1 AND NOT IO k.33 : IO k.33 = 0, WAIT = 0.5, IO k.33 = 1
If light k.33 is already ON, as soon as light k.34 is turned on, light k.33 will flash once.
By omitting the expression NOT IO k.33 the light wouldn’t stop blinking because the action would trigger the same event again and again.
One Event, More Rules
You can define several rules referencing the same event.
When HSYCO detects any status change in the system, it scans EVENTS for all event expressions that could be affected by that event. All relevant expression are then evaluated and, if true, the associated lists of actions are executed.
This process is normally performed top-down on the events.txt file, but the execution order is not guaranteed.
Example:
IO k.34 = 1 : IO k.36 = 0 IO k.34 = 1 AND DAY : IO k.37 = 0
When the actuator k.34 is turned on, these rules cause actuator k.36 to go off, while the actuator k.37 will be turned off only during the day.
Actions
You can associate multiple, comma separated actions to each event. For example:
NIGHT : IO k.33 = 1, IO k.34 = 1, IO k.88 = UP
In order to speed up the writing and make rules clearer, many commands let you specify a list of addresses as attributes of the command. The rule written above can be rewritten in a shorter form as:
NIGHT : IO k.33 k.34 = 1, IO k.88 = UP
Each event : action rule is normally written on a single line. However the readability can be improved by typing the list of actions on following lines, after adding a comma at the end of the preceding lines. It Is also possible to write only the event expression on the first line, followed by : and start the list of actions in the following line:
NIGHT : IO k.33 k.34 = 1, IO k.86 k.87 k.88 = UP
The event expression can’t be written on more than one line.
Variables
Variables are identified by any text name starting with the character $. For example:
$level
Variable names are case insensitive, so $level and $LEVEL are the same variable. Only letters and numbers are allowed, no special characters.
A variable can be assigned any value and doesn’t need to be declared before being used.
Variables and Actions
Variables can be assigned constant values or expressions results:
HSYCOSTART : $count = 0
assigns the value 0 to the variable $count as soon as HSYCO starts.
The basic arithmetic operations (+, -, * and /), the division’s reminder (%) and rounding to an arbitrary number of digits (ROUND n) are supported.
You can round a number from 0 to 9 decimal digits. Rounding to 0 decimal digits rounds to the nearest integer.
If the original value of the variable and the operator's value are both numbers ending with %, the arithmetic operation will retain the % in the result.
If only one of the vaules end with %, that number will be stripped of the trailing % and divided by 100.0 before executing the arithmetic operation.
A variable text can be appended to another text by simply using the + operator. This automatically performs a string append only if the variable original content or the operand are not numerical.
Example:
IO k.33 = 1 : $count + 1
increases by 1 the value of $count any time the actuator k.33 is turned on.
Example:
$voltage : $rv = $voltage, $rv ROUND 2
the $rv variable is set to the value of $voltage, rounded to 2 decimal digits.
Example:
IO k.33 = 1 : $count + 1, $count % 4
like the previous example, but it also computes the modulo of 4 of the variable, writing back the result in the variable itself. This way this variable will be increased up to 3, before turning into 0 again.
To delete a variable, assign an empty string to it:
IO k.33 = 0 : $status = ""
When appending strings, more than one string can be written after the equals sign or, in general, after the operator. In this case the strings will be concatenated.
This is particularly useful when assigning a complex text to a variable.
Example:
time : $body = "The daily power consumption " $date:y/m/d$ " at " $time:h:m:s$ " is " $power$ " Watt"
You can also apply a decimal number format pattern to variables, using the FORMAT “pattern” operator.
A pattern contains a positive and negative sub-pattern, for example, "#,##0.00;(#,##0.00)". Each sub-pattern has a prefix, numeric part, and suffix. The negative sub-pattern is optional; if absent, then the positive sub-pattern prefixed with the localized minus sign ('-' in most locales) is used as the negative sub-pattern. That is, "0.00" alone is equivalent to "0.00;-0.00".
The # symbol represents a digit that is not shown when that digit is zero. The 0 symbol represents a digit that is always shown.
For more information on the pattern format, see the java.text.DecimalFormat class documentation.
The pattern should always be prefixed with a two letter country or language id and a colon character, for example, “EN:#,##0.00”. In this case the pattern and the resulting format is localized based on the country or language id. If the localization id is not present, the format operator uses the localization rules of the Language parameter in hsyco.ini.
Example:
$voltage : $rf = $voltage, $rf FORMAT "EN:#.00"
the $rf variable is set to the value of $voltage, always showing the two most significant decimals, even if the number is integer.
Example:
$voltage : $rf = $voltage, $rf FORMAT "IT:#,00"
the $rf variable is set to the value of $voltage, always showing the two most significant decimals, and using the Italian localization rules, with the comma character as decimal separator.
Variables and Events
Variables can be part of event expressions, so you can compare the content with constant values or another variable, or compare a device status with the value of a variable.
The comparison operators are:
= > < >= <= *=
*= is a contains operator, matching any left-side string that contains the right-side string.
The comparison is based on numeric values if both operands are numerical, otherwise it is text based, ignoring the difference between upper and lower case letters. If one of the two operands is a number and the other is "off", the number is compared with 0. For example:
HSYCOSTART : $count = 0 IO k.33 = 1 : $count + 1 $count : LOG="Increase the count to value: " $count $count = 10 : LOG="Tenth turning on of light 33"
An event defined just with the variable name, thus omitting the comparison operator, is a transient event which will occur when the variable status changes, regardless of its value.
It is possible to verify if a variable is defined. The event condition:
$varname = ""
is true if the variable is not defined or if has been explicitly set to "".
Persistent and Volatile Variables
Every time HSYCO is restarted, all values previously set in the variables are normally lost. By simply adding the character ! at the end of the variable name, a variable becomes persistent:
$count!
is a persistent variable whose value is retained when HSYCO is restarted. Persistent variables are extremely useful, but a variable doesn’t need to be always persistent. We recommend to avoid using persistent variable if not necessary. Also, because the ! is part of the name, $count and $count! are totally different variables.
Predefined Variables
The EVENTS built-in variables are:
$TIME$ $TIME:HMS$ $DATE:YMD$ $DATE:DOW$ $SUNAZIMUTH$ $SUNELEVATION$ $SUNSET$ $SUNRISE$ $HAMASTER$ $POWER$
Predefined variables names always end with the $ character.
For example, the following line will never execute the LOG action because, while the $TIME:M$ > 30 rule will indeed become true during the second half of each hour, there will be no trigger to evaluate the rule:
$TIME:M$ > 30 : LOG = "Second half of the hour"
Starting from this example, in order to create a rule that actually matches every minute of the second half on the hour, you should add the TIME keyword to the rule, like this:
TIME and $TIME:M$ > 30 : LOG = "Second half of the hour"
$TIME$, $SUNSET$ and $SUNRISE$ are particularly useful for events related to the present time, and to sunrise and sunset time. The internal representation of these variables is a positive integer number representing the time in seconds since a reference time.
$TIME$ and $DATE$ also accept special modifiers, like:
$TIME:HMS$ $DATE:YMD$
They return the current hour, minute and second, as well as day, month and year. You can reference individual date/time fields or combine them, also defining custom separation characters.
$DATE:DOW$
returns the day of week as a number, with 1 for Monday and 7 for Sunday.
$SUNAZIMUTH$
is the Sun’s current azimuth in integer degrees, between 0 and 359.
$SUNELEVATION$
is the Sun’s current elevation over the horizon in integer degrees, between -90 and 90.
$HAMASTER$
is set to 1 when the HSYCO Server is defined as the master unit in a high availability configuration or when high availability is not used, or 0 when defined as the slave unit.
$POWER$
is translated to the current power load - an integer value in Watt. This is the same number that appears in the Web interface.
Time and date examples:
$TIME:H$
returns the hour, in two-digit format; $TIME:M$ the minutes; $TIME:S$ the seconds
$TIME:H:M:S$
returns the text 09:15:30
$DATE:Y$
returns the year; $DATE:M$ the month; $DATE:D$ the day
$DATE:D/M/Y$
returns the text 14/07/2011.
Sunset example:
DAY OR HSYCOSTART: $sunset1h=$sunset$, $sunset1h - 3600, IO k.33 k.34 = 0, $lights = off
The variable $sunset1h now contains the time in seconds of one hour before the next sunset, and the following event will cause the turning on of lights at that time:
TIME > $sunset1h AND NOT $lights = on: IO k.33 k.34 = 1, $lights = on