I am using the new rule engine to build a rule for sensor value notifications to log and the openHAB cloud and the openHAB iPhone app. The rule works ok, but I would like to format the message to include the sensor label and the sensor value (i.e. temperature or humidity).
var message;
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
message = [itemRegistry.getItem('ESPHomeattic_AtticTemperature').getLabel(),' is ',itemRegistry.getItem('ESPHomeattic_AtticTemperature').getState()].join('');
logger.info(message);
All examples I found in the documentation and on the web are mostly related to the old dsl rules engine (*.rule file) and not for the “next gen” rule engine in openhab3. I tried to format the message using the blockly javascript message variable, but it is was correct.
How can I format the message? Is it possible, or do I have to fall back to using dsl *.rules?
No, this works fine both ways with rule and via blockly script
The current solution I have is very cumbersome. It consists of two parts, one rule for the trigger and a blockly script for the notification. I would like to combine the two parts into one rule and get rid of the blockly script and have the message in the rule formatted so that it includes the actual sensor value and optionally the sensor label. I know this can be done easily with a dsl rule in openhab2.
so something like this (openhab3 next gen rule code):
message = "Attic Temperature is " + $sensor_value + "°C!"
The rule syntax is of course completely wrong as I don’t know into which language the yaml code gets translated to.
You talk about two parts, but have only posted one rule without the blockly script. Do you have a second rule where the blockly code from your screenshot is included? Maybe post both
As per my current understanding you would:
Create 1 rule that is triggered based on the temperature
Within the rule only add one script action to run a blockly script
Within the blockly script build your message string
Within the blockly script send your notification
What you cannot do is:
Using the notification action within the rule and send dynamic text.
If you want to send dynamic text with your rule, you always need a script action (a DSL rule from OH2 is also script based and can be added instead of using blockly)
No, this was just a thought and I haven’t implemented this yet.
Currently I am just using the rule with the static message as posted above and played a bit with the dynamic message in the blockly script. I wish it would be possible to trigger a blockly script without a rule. Then I could use dynamic messages within blockly and wouldn’t need the rule anymore (or the other way round, use the rule with dynamic messages without the need for a script).
In case somebody is interested in a complete solution calling a script action from the rule:
OH3 is just more flexible than OH2 and provides different options for creating a rule, but it’s hard to mix the different options within one rule.
For beginners and very simple use cases you can create a rule completely GUI -based as per your first message. E.g. I use this approach to turn off music, once the TV is turned on (where I do not need any advanced logic and just want to send an OFF command)
If you have more complex use cases you can still use the GUI but use pseudo code / blockly or even write your rule code completely by yourself within the OH3 GUI. This also includes DSL rules from previous OH versions but also other languages.
You can still create rules text based as before. This is to keep compatibility with previous versions
Ok, thanks. I now go with the execute script option in the GUI. It will take me a while to implement all the rules as I have 16 temp / humidity sensors scattered around the house and many rules to trigger notifications based on pre-defined threshold values. But at least it can be done!
If you want to have same rule for multiple temperature sensors, than put them all into a group and have a group that is triggered by any change of a member
Problem with this approach is that the pre-defined values are individual for each sensor. I have recorded temperatures/humidity values for a very long time now and know exactly how hot/humid each room will ever get.
Based on this data I set very close thresholds in each room so that even a slight increase above “normal” will trigger a notification. This might capture smoking fires and water leaks in very early stages. This is only an additional safety layer and of course each room has also traditional smoke detectors required by law.
E.g.
If (itemname = Sensor1) then threshold = 20
Elseif (itemname = sensor2) then threshold =30
Else threshold = 25 //default for any other item
…
Than you can 1) manage all temperature notifications on one rule and 2) to not need to rewrite/ copy the other parts of the rule.
3) If you want to change the rule later for any reason, you would only need to change one rule instead of 16 rules
You should never duplicate a rule with the only difference slightly different constants. That leads to a huge amount of work up front and in the long term.
Have you looked at Rules - Introduction | openHAB? I find the biggest problem most old users of OH have when adopting new OH 3 concepts is failing to read the Getting Started Tutorial.
OK, so in your rule create a Script Action and code your formatting using Blockly.
This belies some confusion. In the UI a rule has three parts: triggers, actions, and conditions. In Rules DSL, a rule has two parts, triggers (stuff between when and then) and the action (stuff between the then and end). The only thing different in the UI is it adds one new concept (conditions) and you can have more than one Action. Other than that, it’s the same as you’ve always done. You can even write your Script Actions in Rules DSL.
If what you are really after is a “simple UI rule” (see Rules - Basic | openHAB) you can’t. There simply is not that degree of capability in simple UI rules. You will have to write a Script Action in the language of your choice. Blockly is a good choice or, since your rules are already in Rules DSL, there is no harm in keeping them as Rules DSL if you want.
This also shows some confusion. A script action cannot exist without a rule. In the UI you’ll see a section called “Scripts” which consist of rules that only have a single Script Action with no triggers and no conditions. But they re still rules like any other.
However, it is possible for rules to call another rule. And when you do so using a Blockly or JS Scripting Script Action you have the option to pass it data.
So it actually is possible for you to create the one “alerting” Script and have your rules call it with the data it needs to construct and send the message.
Blockly doesn’t let me compare the threshold with the operator (>=) as a floating point number as it already contains a unit (both together is a string). The rule manages this fine and gives a warning if the value to compare against is only a number without the unit (but works regardless).
Second I don’t know how to call a script created within the script editor outside of the rule editor. It seems I can only edit the script inline with the rule. Each script created with the script editor has a unique identifier, so it should in principle be possible, but I don’t see how.
I completely agree. Maintainability is definitely poor if I copy/paste all rules and just change a few things each time. I will read the design pattern thing as you suggest, maybe I get a clue how to do it better.
There is a workaround within blockly, to first store the item state (number with unit) into a variable, than you can compare the variable with a number. This will work on blockly.
There is no need to create a second script. This should be all in the same script & the same rule.
Have a look at triggeringItem and oldState / newState, what will give you access to the item (and it’s name) and the current value.
Ok so I could have a group of all temperature sensors, and if any sensor within the group received an update (or changed to a different value), I execute the script.
Then the script needs to know which sensor triggered and compare the actual value against the pre-defined value. And if equal or greater, send the notifications.
I’ll try again using your suggestion of triggeringItem, oldState and newState.
I think there is an issue open to support that. In the mean time you can use an inline script
Assuming your Item’s state is in a variable named “test”, this will parse it using the standard ECMAScript 5.1 Math.parseFloat (I was remembering wrong, it should be just parseFloat, no Math.) and store that into a variable named “parsed” which you can use in your comparison.
Please review the Blockly reference docs: Rules Blockly | openHAB. You want the “run rule or script” block. The “with context” part is where you will tell it what to pass to the called rule.
Even better than my approach. Nice.
Agreed, but it’s helpful to know how to do it all the same which is why I’m showing how here.
These are stored in the event variable passed to the script. But I don’t see how to access that in Blockly. I’m certain there is a way. @Matze0211, do you know?
The first mistake was to not use the trigger the state of a member of an item group changes, and the second that the triggering sensor and value are stored in triggeringItem.label and triggeringItem.state, respectively.
Here is a first working rule (I went with javascript directly and didn’t use blockly anymore):
configuration: {}
triggers:
- id: "1"
configuration:
groupName: Temperatures
type: core.GroupStateChangeTrigger
conditions: []
actions:
- inputs: {}
id: "2"
configuration:
type: application/javascript
script: >-
var threshold;
if (triggeringItem.name == "ESPHomeattic_AtticTemperature")
threshold = 33.0;
else if (triggeringItem.name == "ESPHomebasement_BasementTemperature")
threshold = 26.0;
else if (triggeringItem.name == "ESPHomechamber_BedroomTemperature")
threshold = 31.0;
else if (triggeringItem.name == "ESPHomechamber_ChamberTemperature")
threshold = 32.0;
else if (triggeringItem.name == "ESPHomechamber_CharlottesTemperature")
threshold = 31.0;
else if (triggeringItem.name == "ESPHomelivingroom_KitchenTemperature")
threshold = 31.0;
else if (triggeringItem.name == "ESPHomebasement_OfficeTemperature")
threshold = 26.0;
else if (triggeringItem.name == "ESPHomelivingroom_PianoTemperature")
threshold = 30.0;
else if (triggeringItem.name == "ESPHomebasement_StairsKitchenTemperature")
threshold = 26.0;
else if (triggeringItem.name == "ESPHomeattic_SteffisTemperature")
threshold = 31.0;
else if (triggeringItem.name == "ESPHomeattic_TVRoomTemperature")
threshold = 31.0;
else
threshold = 50.0;
if (parseFloat(triggeringItem.state) >= threshold) {
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var message = [triggeringItem.label, ' is ', triggeringItem.state].join('');
logger.warn(message);
}
type: script.ScriptAction