Notification rule: how to format message?

  • Platform information:
    • Hardware: Odroid C4
    • OS: Arch Linux
    • openHAB version: 3.3.0 Release Build, manual install

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).

The rule I have created looks like this:

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: ESPHomeattic_AtticTemperature
    type: core.ItemStateUpdateTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: ESPHomeattic_AtticTemperature
      state: 33 °C
      operator: ">="
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      icon: temperature
      severity: high
      message: Attic temperature high!
      userId: xxx@xxx.xxx
    type: notification.SendExtendedNotification
  - inputs: {}
    id: "4"
    configuration:
      message: Attic temperature high!
    type: notification.SendLogNotification

Code output: “Attic temperature high!”

The message I would like to send instead is something like this:

Code output: “Attic Temperature is 28.1 °C”

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?

As you already have figured out how to build the message, is your question about how to send this message to your iphone?

Within blockly there is also a notification block that you can use for this case. Have you seen it?

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)

1 Like

Ok thanks, this answers my question!

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:

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: ESPHomeattic_AtticTemperature
    type: core.ItemStateUpdateTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: ESPHomeattic_AtticTemperature
      state: 33 °C
      operator: ">="
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      blockSource: <xml
        xmlns="https://developers.google.com/blockly/xml"><variables><variable
        id="u-Q#Il+a/Q{bA}B.xhWu">message</variable></variables><block
        type="variables_set" id="zm37v*EhyVUfwhe7`;.$" x="259" y="214"><field
        name="VAR" id="u-Q#Il+a/Q{bA}B.xhWu">message</field><value
        name="VALUE"><block type="text_join" id=".cFWtekQ]W{{{A#6M5Ek"><mutation
        items="3"></mutation><value name="ADD0"><block
        type="oh_getitem_attribute" id="~hKyHG^yHs=*A.KnRk}8"><mutation
        attributeName="Label"></mutation><field
        name="attributeName">Label</field><value name="item"><shadow
        type="oh_getitem" id="Pfve=(0E3nEZ:6i-(fc0"><value
        name="itemName"><shadow type="oh_item" id=")sDL^h(X_eI@Sav71i)d"><field
        name="itemName">ESPHomeattic_AtticTemperature</field></shadow></value></shadow></value></block></value><value
        name="ADD1"><block type="text" id="E4yn]?FXRokiw:5*MZ[4"><field
        name="TEXT"> is </field></block></value><value name="ADD2"><block
        type="oh_getitem_attribute" id="N)BQ!`qr`aJ`rYuF[l=0"><mutation
        attributeName="State"></mutation><field
        name="attributeName">State</field><value name="item"><shadow
        type="oh_getitem" id="1q[e~Etlbff8+jA|2.24"><value
        name="itemName"><shadow type="oh_item" id="+`(d2inm=j]CL]Aw{P*8"><field
        name="itemName">ESPHomeattic_AtticTemperature</field></shadow></value></shadow></value></block></value></block></value><next><block
        type="oh_log" id="[7Jb;N,?V1h5kK9k3eEJ"><field
        name="severity">warn</field><value name="message"><shadow type="text"
        id="XFT(;+xTz-V#_lnn^zZ)"><field name="TEXT">abc</field></shadow><block
        type="variables_get" id="IssA(]|.OGDN2][Wq0@r"><field name="VAR"
        id="u-Q#Il+a/Q{bA}B.xhWu">message</field></block></value><next><block
        type="oh_sendNotification" id="`0)(Whv;.$z3ax^TJI5K"><value
        name="message"><shadow type="text" id="[*?NdNfr;J#i.FhfHuw|"><field
        name="TEXT">message</field></shadow><block type="variables_get"
        id="#,Ty)!Hoel/!Xm-mxWXN"><field name="VAR"
        id="u-Q#Il+a/Q{bA}B.xhWu">message</field></block></value><value
        name="email"><shadow type="text" id="]MShn+7hXIXqTD0{A}ZI"><field
        name="TEXT">xxx@xxx.xxx</field></shadow></value></block></next></block></next></block></xml>
      type: application/javascript
      script: >
        var message;
        var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
        var notifications = Java.type('org.openhab.io.openhabcloud.NotificationAction');
        message = [itemRegistry.getItem('ESPHomeattic_AtticTemperature').getLabel(),' is ',itemRegistry.getItem('ESPHomeattic_AtticTemperature').getState()].join('');
        logger.warn(message);
        notifications.sendNotification('xxx@xxx.xxx',message);
    type: script.ScriptAction

Here the rule:

Here the blockly script:

1 Like

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.

  1. 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)

  2. 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.

  3. 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

This will most likely save some time for you

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.

Use a dynamic threshold.

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

In addition to Matthias’s suggestion, you could use Design Pattern: Associated Items or Design Pattern: Encoding and Accessing Values in Rules to save you constants and have one rule to process all the sensors.

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.

I am not sure how to implement this in my case.

I have basically three variables:

  1. threshold value including the unit (e.g. 31 °C)
  2. item name (e.g. ESPHomeattic_AtticTemperature)
  3. item value including the unit (e.g. 24.5 °C)

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

image

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?

I have no idea how to pass the item which has changed to the script.

I tried
Screenshot 2022-09-04 at 19-12-03 openHAB
and get the following error when running the script:

Script execution of rule with UID '73e5163922' failed: TypeError: Cannot read property "triggeringItem" from undefined in <eval> at line number 4

And here the full rule definition:

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: Temperatures
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      blockSource: <xml xmlns="https://developers.google.com/blockly/xml"><block
        type="oh_log" id="G@hUz9%g_Hp}mb:E2U(s" x="456" y="316"><field
        name="severity">warn</field><value name="message"><shadow type="text"
        id="Ke)Z%Kz]Ff*+@lz_Y2]l"><field name="TEXT">abc</field></shadow><block
        type="oh_get_value" id="l#w_V|v?=V]S(z1{Ru,Z"><value name="key"><shadow
        type="text" id=",efsFky:+~]/O|0w_)D."><field
        name="TEXT">triggeringItem</field></shadow></value></block></value></block></xml>
      type: application/javascript
      script: >
        var logger =
        Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' +
        ctx.ruleUID);



        logger.warn((this.storedValues['triggeringItem']));
    type: script.ScriptAction

EDIT: I have not waited until the sensor actually changed, just pressed the play button.

Within blockly have a look at openhab → Run & Process → contextual info

This will also answer @rlkoshak question :wink:

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

Thanks for all your input!

1 Like