Updated rule dsl docs to openHAB 3 for datetime and implicit var changes (#1294)

Signed-off-by: Kai Kreuzer <kai@openhab.org>
pull/1301/head
Kai Kreuzer 2020-11-28 23:11:36 +01:00 committed by GitHub
parent 4b93eec8f1
commit 5219bc087f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 38 additions and 52 deletions

View File

@ -60,11 +60,11 @@ import java.net.URI
A few default imports are already done, so classes from these packages do not need to be explicitly imported: A few default imports are already done, so classes from these packages do not need to be explicitly imported:
```java ```java
org.eclipse.smarthome.core.items org.openhab.core.items
org.eclipse.smarthome.core.persistence org.openhab.core.persistence
org.eclipse.smarthome.core.library.types org.openhab.core.library.types
org.eclipse.smarthome.core.library.items org.openhab.core.library.items
org.eclipse.smarthome.model.script.actions org.openhab.model.script.actions
``` ```
The **Variable Declarations** section can be used to declare variables that should be accessible to all rules in this file. The **Variable Declarations** section can be used to declare variables that should be accessible to all rules in this file.
@ -130,9 +130,8 @@ Item <item> changed [from <state>] [to <state>]
A simplistic explanation of the differences between `command` and `update` can be found in the article about [openHAB core actions](/docs/configuration/actions.html#event-bus-actions). A simplistic explanation of the differences between `command` and `update` can be found in the article about [openHAB core actions](/docs/configuration/actions.html#event-bus-actions).
An important warning is worth mentioning here. When using the `received command` trigger, the Rule might trigger **before** the Item's state is updated.
When using the `received command` trigger, the Rule will trigger **before** the Item's state is updated. Therefore, if the Rule needs to know what the command was, use the [implicit variable]({{base}}/configuration/rules-dsl.html#implicit-variables-inside-the-execution-block) `receivedCommand` instead of `<ItemName>.state`.
Therefore, if the Rule needs to know what the command was, use the [implicit variable]({{base}}/configuration/rules-dsl.html#implicit-variables-inside-the-execution-block) `receivedCommand` instead of ItemName.state.
{: #member-of-triggers} {: #member-of-triggers}
### Member of Triggers ### Member of Triggers
@ -140,7 +139,7 @@ Therefore, if the Rule needs to know what the command was, use the [implicit var
As with Item based event-based triggers discussed above, you can listen for commands, status updates, or status changes on the members of a given Group. As with Item based event-based triggers discussed above, you can listen for commands, status updates, or status changes on the members of a given Group.
You can also decide whether you want to catch only a specific command/status or any. You can also decide whether you want to catch only a specific command/status or any.
All of the [implicit variables]({{base}}/configuration/rules-dsl.html#implicit-variables-inside-the-execution-block) get populated using the Item that caused the event. All of the [implicit variables]({{base}}/configuration/rules-dsl.html#implicit-variables-inside-the-execution-block) get populated using the Item that caused the event.
Of particular note, the implicit variable `triggeringItem` is populated with the Item that caused the Rule to trigger. The implicit variable `triggeringItem` is populated with the Item that caused the Rule to trigger.
```java ```java
Member of <group> received command [<command>] Member of <group> received command [<command>]
@ -150,7 +149,7 @@ Member of <group> changed [from <state>] [to <state>]
The `Member of` trigger only works with Items that are a direct member of the Group. The `Member of` trigger only works with Items that are a direct member of the Group.
It does not work with members of nested subgroups. It does not work with members of nested subgroups.
Also, as with Item event-based triggers, when using `received command`, the Rule will trigger before the Item's state is updated. Also, as with Item event-based triggers, when using `received command`, the Rule might trigger before the Item's state is updated.
So in Rules where the Rule needs to know what the command was, use the `receivedCommand` implicit variable instead of `triggeringItem.state`. So in Rules where the Rule needs to know what the command was, use the `receivedCommand` implicit variable instead of `triggeringItem.state`.
{: #time-based-triggers} {: #time-based-triggers}
@ -174,9 +173,7 @@ A cron expression takes the form of six or optionally seven fields:
6. Day-of-Week 6. Day-of-Week
7. Year (optional field) 7. Year (optional field)
for more information see the [Quartz documentation](http://www.quartz-scheduler.org/documentation/quartz-2.1.7/tutorials/tutorial-lesson-06.html). You may use [CronMaker](http://www.cronmaker.com/) or the generator at [FreeFormatter.com](http://www.freeformatter.com/cron-expression-generator-quartz.html) to generate cron expressions.
You may also use [CronMaker](http://www.cronmaker.com/) or the generator at [FreeFormatter.com](http://www.freeformatter.com/cron-expression-generator-quartz.html) to generate cron expressions.
{: #system-based-triggers} {: #system-based-triggers}
### System-based Triggers ### System-based Triggers
@ -186,7 +183,6 @@ Two system-based triggers are provided as described in the table below:
| Trigger | Description | | Trigger | Description |
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| System started | System started is triggered upon openHAB startup, after the rule file containing the System started trigger is modified, or after item(s) are modified in a .items file. | | System started | System started is triggered upon openHAB startup, after the rule file containing the System started trigger is modified, or after item(s) are modified in a .items file. |
| System shuts down | Rules using the 'System shuts down' trigger execute when openHAB shuts down. |
You may wish to use the 'System started' trigger to initialize values at startup if they are not already set. You may wish to use the 'System started' trigger to initialize values at startup if they are not already set.
@ -436,63 +432,52 @@ val contactNum = if (MyContactItem.state == OPEN) 1 else 0
##### DateTime Item ##### DateTime Item
A DateTime Item carries a **DateTimeType**. A DateTime Item carries a **DateTimeType**, which internally holds a Java `ZonedDateTime` object.
DateTimeType presents the biggest challenge when converting and performing calculations.
The problems stem from the fact that by default the Rules use a Joda DateTime class to represent time, most notably `now`.
However, DateTimeType is not a Joda DateTime and in fact the two are incompatible, requiring some conversion in order to use the two together.
The lowest common denominator when working with time is to get at the epoch value.
Epoch is the number of milliseconds that have passed since 1 January 1970 GMT and stored in a `long`.
With epoch, one can compare two dates together, convert a Joda DateTime to a DateTimeType and vice versa.
```java ```java
// Get epoch from DateTimeType // Get epoch from DateTimeType
val Number epoch = (MyDateTimeItem.state as DateTimeType).zonedDateTime.timeInMillis val Number epoch = (MyDateTimeItem.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
// Get epoch from Joda DateTime // Get epoch from Java ZonedDateTime
val Number nowEpoch = now.millis val Number nowEpoch = now.toInstant.toEpochMilli
// Convert DateTimeType to Joda DateTime // Convert DateTimeType to Java ZonedDateTime
val jodaVariantOne = new DateTime(MyDateTimeItem.state.toString) val javaZonedDateTime = (MyDateTimeItem.state as DateTimeType).zonedDateTime
val jodaVariantTwo = new DateTime((MyDateTimeItem.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
// Convert Joda DateTime to DateTimeType // Convert Java ZonedDateTime to DateTimeType
val calendar = java.util.Calendar::getInstance val DateTimeType date = new DateTimeType(now)
calendar.timeInMillis = now.millis
val dtt = new DateTimeType(calendar)
``` ```
In certain cases it is needed to convert an epoch timestamp to a human readable and/or store it in a DateTimeType and a DateTime Item. In certain cases it is needed to convert an epoch timestamp to a human readable and/or store it in a DateTimeType and a DateTime Item.
Here an option to do so utilizing SimpleDateFormat: Here an option to do so utilizing SimpleDateFormat:
```java ```java
import java.text.SimpleDateFormat import java.time.format.DateTimeFormatter
import java.util.Date
// Convert epoch to a human readable // Convert epoch to a human readable
val SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") val DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
val String timestampString = sdf.format(new Date(timestampEpoch)) val long epoch = now.toInstant.toEpochMilli
val ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(epoch), ZoneOffset.UTC);
val String dateTimeString = zdt.format(formatter)
// Convert human readable time stamp to DateTimeType // Convert human readable time stamp to DateTimeType
val DateTimeType timestamp = DateTimeType.valueOf(timestampString) val DateTimeType dtt = DateTimeType.valueOf(dateTimeString)
//convert state from Item of DateTimeType into a string //convert state from Item of DateTimeType into a string
val String datetime_string = DateTime_Item.state.format("%1$td.%1$tm.%1$ty %1$tH:%1$tM")) val String datetime_string = DateTime_Item.state.format("%1$td.%1$tm.%1$ty %1$tH:%1$tM"))
``` ```
Both Joda DateTime as well as DateTimeType provide a number of useful methods for comparing date times together and/or extracting parts of the date. ZonedDateTimes provide a number of useful methods for comparing date times together and/or extracting parts of the date:
For some examples:
```java ```java
// See if DateTimeType is before Joda DateTime // See if DateTimeType is before now
if(now.isBefore((MyDateTimeItem.state as DateTimeType).zonedDateTime.timeInMillis)) ... if(now.isBefore((MyDateTimeItem.state as DateTimeType).zonedDateTime)) ...
// See if DateTimeType is after Joda DateTime // See if DateTimeType is after now
if(now.isAfter((MyDateTimeItem.state as DateTimeType).zonedDateTime.timeInMillis))... if(now.isAfter((MyDateTimeItem.state as DateTimeType).zonedDateTime)) ...
// Get the hour in the day from a DateTimeType // Get the hour in the day from a DateTimeType
val hours = (MyDateTimeItem.state as DateTimeType).zonedDateTime.get(Calendar::HOUR_OF_DAY) val hour = (MyDateTimeItem.state as DateTimeType).zonedDateTime.hour
// See the Calendar javadocs for the full set of parameters available
``` ```
##### Dimmer Item ##### Dimmer Item
@ -688,11 +673,12 @@ MyItem will automatically apply the method that corresponds to the argument type
Besides the implicitly available variables for items and commands/states, rules can have additional pre-defined variables, depending on their triggers: Besides the implicitly available variables for items and commands/states, rules can have additional pre-defined variables, depending on their triggers:
- `receivedCommand` - will be implicitly available in every rule that has at least one command event trigger. - `receivedCommand` - implicitly available in every rule that has at least one command event trigger.
- `previousState` - will be implicitly available in every rule that has at least one status change event trigger. - `previousState` - implicitly available in every rule that has at least one status change event trigger.
- `newState` - will be implicitly available in every rule that has at least one status update or status change event trigger. - `newState` - implicitly available in every rule that has at least one status update or status change event trigger.
- `triggeringItem` - will be implicitly available in every rule that has at least one command, status update, or status change event trigger. - `triggeringItemName` - implicitly available in every rule that has at least one status update, status change or command event trigger.
- `receivedEvent` - will be implicitly available in every rule that has a channel-based trigger. - `triggeringItem` - implicitly available in every rule that has a "Member of" trigger.
- `receivedEvent` - implicitly available in every rule that has a channel-based trigger.
{: #return} {: #return}
### Early returns ### Early returns
@ -791,7 +777,7 @@ logWarn(String loggerName, String format, Object... args)
logError(String loggerName, String format, Object... args) logError(String loggerName, String format, Object... args)
``` ```
In each case, the `loggerName` parameter is combined with the string `org.eclipse.smarthome.model.script.` to create the log4j logger name. In each case, the `loggerName` parameter is combined with the string `org.openhab.core.model.script.` to create the log4j logger name.
For example, if your rules file contained the following log message: For example, if your rules file contained the following log message:
```java ```java
@ -801,7 +787,7 @@ logDebug("kitchen", "Kitchen light turned on")
then the logger you would have to configure to have your messages appearing in the console would be: then the logger you would have to configure to have your messages appearing in the console would be:
```text ```text
log:set DEBUG org.eclipse.smarthome.model.script.kitchen log:set DEBUG org.openhab.core.model.script.kitchen
``` ```
## Rule Examples ## Rule Examples