{{announcement.body}}
{{announcement.title}}

OpenHab: Notify Rule

DZone 's Guide to

OpenHab: Notify Rule

See what does and doesn't work for notification with OpenHab, a home automation solution.

· IoT Zone ·
Free Resource

Dear Reader,

For the past six months, I've been playing with different home automation solutions. I tried HomeAssistant and VeraPlus, but I kept coming back to OpenHab. OpenHab is not perfect — its docs are lacking and if you are not a programmer, it is NOT your solution (yet).

All that having been said, I AM a programmer and OpenHab gives me a lot of flexibility in how things are done because I can write code in the rules. I am the first to admit that I am an OpenHab noob. The solution I present here might be laughable to those who have been doing it a while. I'm posting it here for two reasons:

  1. As a straw man. If I have it wrong, comment below and help me make it better.
  2. In case it is a good idea and others are wanting to implement it in their OpenHab installation.

For those interested, my setup contains:

Today's Problem: Notifying People

One of the problems I've had to solve recently is that there are times when I want a group of people to be notified when something happens. For different types of events, I want different groups of people notified. The people that need to know a door was opened (mainly just me) is very different from the people I want to be notified if a door is open and my alarm is set (EVERYBODY in my family.)

What Didn't Work

var contacts = newArrayList()
contacts.add(newLinkedHashMap('name'->'Cal Evans', 'address'->'cal@example.com'))
contacts.add(newLinkedHashMap('name'->'Bob Evans','address'->'bob@example'))

The OpenHab documentation alludes to the fact that you can define variables outside of rules and that any rule in the same file can access those variables. This by itself is true. However, while you can define variables, you cannot manipulate them or execute code outside of a rule.

Originally, I was using an ArrayList of LinkedHashMaps. (Yes, we've ventured into Java land) One of my requirements is that it is easy to read and convenient to add new names to the lists. An ArrayList of LinkedHashMaps could be used if I wanted to define everything in a single create statement. Strictly IMHO, this was inelegant and not easy to modify. It was pointed out to me in a thread on the OpenHab community forum titled "Arrays as Globals" that the was not inelegant and was a workable solution. I don't know enough about Java to be able to define inelegant, all I know was I didn't like how it looked. So I went looking for another solution.

What Didn't Work — Part Deux

Ok, so you can't manipulate variables outside of a rule in OpenHab. My next thought was to create a System Startup rule that added all the people to my list. the initialization would still be outside of a rule so that it would be global to all rules in that file.

This worked...kind of. Sure enough they names got added, but when I tried to access them I got a Java error:

'get' is not a member of 'java.util.LinkedHashMap'

I'm not sure why because get() IS a method of LinkedHashMap according to the documentation.

At this point, I had been working on this particular problem for a couple of hours and I had arranged things every way I could think of to no avail. I need to step back and look at the problem from a different angle because this one just wasn't doing it for me.

What Did Finally Work

Ok, time to re-think this. First, my lack of knowledge of Java and Xtend, the flavor of Java that OpenHab uses, was starting to show. Second, thinking this through I began to realize that variables localized to a given file might get in the way eventually. What I needed was lists in the global namespace that could be accessed from any rule.

So I perverted the String and Group items of OpenHab and forced them to do my bidding.

A String is OpenHab has a label, this is what I used to store my data. I will never use these particular strings to actually display a string like they are supposed to be used, but that's ok. I decided to store a comma delimited string as the label. This is hard-coded in my "Contacts.items" file so it is permanent.

Next, I needed a way to group my contacts. I have two lists of contacts, normal and emergency contacts. Normal contacts get notified about routine events. (This list is mainly me until I get tired of getting all these emails and eventually texts.) Emergency contacts is made up of everyone who I want to know that my alarm is set and something important happened to trigger that alarm. (Me, the lovely and talented Kathy, the kids, maybe my neighbors, etc.)

My Contacts.items file:

/*
* Group contact lists
*
* Format for contacts is
* name, METHOD, address
*/
Group normalContacts
Group emergencyContacts
 
String Contact_01 "Cal Evans,TEXT,615-555-1212" (normalContacts, emergencyContacts)
String Contact_02 "Cal Evans,EMAIL,cal@example" (normalContacts, emergencyContacts)
String Contact_03 "Kathy Evans,EMAIL,kathy@example.com" (emergencyContacts)
String Contact_04 "Kathy Evans,TEXT,615-555-1212" (emergencyContacts)

So now we have two globally accessible lists. If you need more info on Strings and Groups, check out the OpenHab Items Doc page. Next, I need to use them to notify people that something has happened. So I created a "Notify" rule:

import java.text.SimpleDateFormat
import java.util.Date
 
/*
* Send a message to the list of people based on the state of Alarm. If alarm
* is set, send to the ALARM list, if Alarm is not set, send to the NonAlarm
* list.
*
* This is called with a comma delimited string. first part is the name of the
* item that triggered the event, the second is the state or message.
*
* Does this need to take Alarm.state into account?
*/
rule "Notify Of Event"
when
Item Notify received command
then
/*
* Build message
*
* The second parameter on some messages will not be a simple state but a
* message. If not ON,OFF,OPEN,CLOSED then just parrot the message sent.
*/
 
/*
* Pick the list to send to
*
* If this is ever used for anything other than notifying people that things
* have opened, list needs to be passed in as a parameter.
*/
var list = switch Security.state.toString {
case "ON" : emergencyContacts
default : normalContacts
}
 
/*
* Build the message
*/
var String subject = receivedCommand.toString.split(",").get(0) + " was " + receivedCommand.toString.split(",").get(1)
var SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
var Date eventTime = new Date()
var String message = "At " + dateFormat.format(eventTime) + " " + receivedCommand.toString.split(",").get(0) + " was " + receivedCommand.toString.split(",").get(1)
 
/*
* Send the texts
*/
list.members.filter[ i | i.label.toString.split(",").get(1) == 'EMAIL'].forEach[i | logInfo("TEXT", message) ]
 
/*
* Send the emails
*/
list.members.filter[ i | i.label.toString.split(",").get(1) == 'EMAIL'].forEach[i | sendMail(i.label.toString.split(",").get(2), subject, message) ]
 
end

This code is pretty well documented so I'm not going to walk through it. If you need more info on OpenHab rules syntax, check out the OpenHab Rules doc page. Once you get used to them, they are really powerful.

Now, anytime I need to notify a group of people that something happened, I send a command to Notify:

Notify.sendCommand(receivedCommand.toString.split(',').get(0) + "," + receivedCommand.toString.split(',').get(1))

receivedCommand is an implicit variable in any OpenHab rule. If received command is part of the when clause of the rule, then receivedCommand is the command received. In the case of the rule above, the first part is the name of the item that triggered the notify and the second part is that item's state.

If you are paying attention you probably notices that sending TEXT messages is stubbed out. I need to work out the details but I'm pretty sure it will involve a 3G add-on for my Raspberry Pi and a Twilio SIM card. Stay tuned.

fClose()

This solution works. Trust me, it's been sending me emails every time we open a door to let the dog out. :) It is not perfect though. I think the next iteration, the suggested list will be passed in as a third parameter. This list will be used unless the Alarm is set and has been triggered. At that point, the emergencyContacts list is always used.

If you use OpenHab, I would appreciate comments. How can I make this better? What assumptions did I get wrong, etc.

Oh, I also posted my first post on the OpenHab Community Forums, "Arrays as Globals." I'm very pleased to say that within minutes I started receiving replies and that they were helpful and courteous. I think I'm going to like the OpenHab community.

As much fun as Xtend is however, I am missing PHP for writing rules. The more I work with other languages, the more I miss the simplicity and elegance of PHP.

Topics:
openhab ,raspberry pi ,tutorial ,iot ,smart homes ,home automation

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}