Overwiew
A bridge between ROS and open Home Automation Bus (openHAB), which is an open source home automation software written in Java. More precisely, the Item Events of the Event Bus of openHAB are mirrored via ROS. For this purpose, the REST API of openHAB is accessed. There are two approaches for this. Once via HABApp and once a direct access without HABApp. It offers a more versatile and better alternative to the iot_bridge.
What is openHAB?
A Quick Overview
The open Home Automation Bus (openHAB) is an open source, technology agnostic home automation platform which runs as the center of your smart home!
openHAB communicates electronically with smart and not-so-smart devices, performs user-defined actions and provides web-pages with user-defined information as well as user-defined tools to interact with all devices. To achieve this, openHAB segments and compartmentalizes certain functions and operations. The following table gives a top-level description of the most important concepts as well as a link to more information:
Concepts |
Meaning |
More informations |
Bindings |
are the openHAB component that provides the interface to interact electronically with devices |
see below |
Things |
are the first openHAB (software) generated representation of your devices |
|
Channels |
are the openHAB (software) connection between “Things” and “Items” (see below) |
see below |
Items |
are the openHAB (software) generated representation of information about the devices |
|
Rules |
that perform automatic actions (in its simplest form: if "this" happens, openHAB will do "that") |
|
Sitemap |
is the openHAB (software) generated user interface (web site) that presents information and allows for interactions |
While the table above gives an overview, please remember that it is incomplete and a simplification of openHAB for the sake of this overview. More elements will be introduced in the documentation.
Concepts
When first thinking about your home automation system, it may be helpful to bear in mind that there are two ways of thinking about or viewing your system: the physical view and the functional view.
The physical view will be familiar to you. This view focuses on the devices in your system, the connections between these devices (e.g. wires, Z-Wave, WiFi hardware), and other physical aspects of the system.
The functional view might be a new concept for you. The functional view focuses on how information about the devices, connections, and so on, is represented in user interfaces. The functional view includes focusing on how rules affect representations of physical devices in software. Perhaps most important to you, the functional view focuses on how an action in a user interface affects the software associated with the physical device it represents.
It is a bit of an over-simplification, but you can think of the physical view as being a view of the 'real world', and the functional view being a view of the 'software world'.
Things, Channels, Bindings, Items and Links
Things are entities that can be physically added to a system. Things may provide more than one function (for example, a Z-Wave multi-sensor may provide a motion detector and also measure room temperature). Things do not have to be physical devices; they can also represent a web service or any other manageable source of information and functionality.
Things expose their capabilities through Channels. Whether an installation takes advantage of a particular capability reflected by a Channel depends on whether it has been configured to do so. When you configure your system, you do not necessarily have to use every capability offered by a Thing. You can find out what Channels are available for a Thing by looking at the documentation of the Thing's Binding.
Bindings can be thought of as software adapters, making Things available to your home automation system. They are add-ons that provide a way to link Items to physical devices. They also abstract away the specific communications requirements of that device so that it may be treated more generically by the framework.
Items represent capabilities that can be used by applications, either in user interfaces or in automation logic. Items have a State and they may receive Commands.
The glue between Things and Items are Links. A Link is an association between exactly one Channel and one Item. If a Channel is linked to an Item, it is "enabled", which means that the capability the Item represents is accessible through that Channel. Channels may be linked to multiple Items and Items may be linked to multiple Channels.
To illustrate these concepts, consider the example below of a two-channel actuator that controls two lights:
The actuator is a Thing that might be installed in an electrical cabinet. It has a physical address and it must be configured in order to be used (remember the physical view introduced at the beginning of this article).
In order for the user to control the two lights, he or she accesses the capability of the actuator Thing (turning on and off two separate lights) through two Channels, that are Linked to two switch Items presented to the user through a user interface.
Channels
Channels are the logical link between a Thing and an Item. Channels originate from Things definition and define how your Thing can communicate with Item (and vice versa). You will create channels when defining your Thing.
During the definition of your Thing you will identify the channel to which your Item will be linked. These two steps ensure that openHAB can transmit the information from the Thing to the Item (and vice versa).
Bindings
Bindings are software packages that are installed by the user in openHAB. The main purpose of Bindings is to establish the connection between your device and your Thing. Bindings communicate with your device and translate all commands to and from openHAB between your device and your Thing.
Bindings are provided in the Add-on section (opens new window) of this website. Here you will find a searchable list of several hundred bindings to support as many devices as possible. New bindings are regularly added as developers integrate more devices into openHAB.
For each binding, detailed instructions and examples are provided that include guidance on configuration (if any) of the binding itself, the definition of Things supported by this binding and the Channels these Things provide. In most cases, the description also contains a fully worked out example that includes a definition of Things and its Channels, Items linked to those Channels and the use of these Items in a sitemap.
Event Bus
The openHAB framework provides an event bus for inter-component communication. The communication is based on events which can be sent and received through the event bus in an asynchronous way. Examples of openHAB event types are ItemCommandEvent, ItemStateEvent, ItemAddedEvent, ThingStatusInfoEvent, etc.
For us, only the items and the item events are relevant.
So if we simplify it a lot, then we have a device and as a Digital Twin for this we have a Thing. This device is connected via various bindings and a Thing is created in openHAB for this device on the basis of the binding, which you can imagine as an instance of the class of the binding for this device. For different manufacturers, communication technologies, etc. there is a corresponding binding. In this binding several classes are created, since e.g. a manufacturer owns several devices. Means for a device there are defined functions in a class and for another device there is accordingly another class with differently defined functions. Thus Things do not only differ on the basis of the Binding but many Binding offer for different devices also again different Things. In the end, an item is created via a Thing. An item refers to a function of the device. If this function is a pure sensor, then this item only receives a state. But if this function is also something that can be switched or a mode, a program or whatever can be changed, a state is assigned and a command can be sent to the device so that something changes.
Every changing state, but also every command runs through the event bus of openHAB.
The Interfaces
The EventPublisher posts Events through the openHAB event bus in an asynchronous way. The EventSubscriber defines the callback interface to receive events of specific types to which the event subscriber is subscribed. The EventPublisher and the EventSubscribers are registered as OSGi services. An event subscriber can provide an EventFilter in order to filter events based on the topic or the content. If there is no filter all subscribed event types are received. The event itself will be subclassed for each event type, which exists in the System (e.g. ItemCommandEvent, ItemUpdatedEvent, ThingStatusInfoEvent).
The Core Events
This section lists the core events provided by openHAB which can be divided into the categories Item Events, Thing Events and Inbox Events.
An event consists of a topic, a type, a payload and a source. The payload can be serialized with any String representation and is determined by its concrete event type implementation (e.g. ItemCommandEvent, ItemUpdatedEvent). The payloads of the openHAB core events are serialized with JSON. Each event implementation provides the payload as high level methods as well, usually presented by a data transfer object (DTO).
A topic clearly defines the target of the event and its structure is similar to a REST URI, except the last part, the action. The topics of openHAB events are divided into the following four parts: {namespace}/{entityType}/{entity}/{action}, e.g. openhab/items/{itemName}/command.
The type of an event is represented by a string, usually the name of the concrete event implementation class, e.g. ItemCommandEvent, ItemUpdatedEvent . This string type presentation is used by event subscribers for event subscription (see chapter "Receive Events") and by the framework for the creation of concrete event instances.
The event source is optional and represents the name of the source identifying the sender.
Item Events
There are the following item events in openHAB:
Event |
Description |
Topic |
ItemAddedEvent |
An item has been added to the item registry. |
openhab/items/{itemName}/added |
ItemRemovedEvent |
An item has been removed from the item registry. |
openhab/items/{itemName}/removed |
ItemUpdatedEvent |
An item has been updated in the item registry. |
openhab/items/{itemName}/updated |
ItemCommandEvent |
A command is sent to an item via a channel. |
openhab/items/{itemName}/command |
ItemStateEvent |
The state of an item is updated. |
openhab/items/{itemName}/state |
ItemStatePredictedEvent |
The state of an item predicted to be updated. |
openhab/items/{itemName}/statepredicted |
ItemStateChangedEvent |
The state of an item has changed. |
openhab/items/{itemName}/statechanged |
GroupItemStateChangedEvent |
The state of a group item has changed through a member. |
openhab/items/{itemName}/{memberName}/statechanged |
The ItemStateEvent is always sent if the state of an item is updated, even if the state did not change. ItemStateChangedEvent is sent only if the state of an item was really changed. It contains the old and the new state of the item.
The GroupItemStateChangedEvent is sent only if the state of a group item was changed by a member. It contains the old and the new state of the group item as well as the member.
As a note to the Topics, one can add that openhab could also be replaced by smarthome.
Interesting for us are the two events ItemStateEvent and ItemCommandEvent.
An ItemCommandEvent is executed when, for example, I switch in the sitemap a switch from OFF to ON or execute a sendCommand in a rule. An ItemStateEvent is triggered when the state of an item changes. This happens immediately, for example, after an ItemCommandEvent or when a binding performs a status update. I can also operate a device without openHAB and the item then recognizes that a state has changed. Or a temperature sensor changes the measured temperature as a state several times by itself.
The bridge from openhab to ROS works bidirectionally. A ROS device, such as a robot, should be able to subscribe to the items from openHAB. For this purpose, the state of an item is published. However, since one is not a binding that changes the information in an item, a sendCommand and no postUpdate must be performed. This means that the bridge must subscribe commands! Then openHAB will execute this command.
Item Types
To subscribe the items from openHAB or to publish an item including a command to openHAB you need the appropriate message types. These are based on the Item Types and Command Types of openHAB.
The Item type defines what kind of state can be stored in that Item and which commands the Item will accept. Item types are comparable to basic variable data types in programming languages. Each Item type has been optimized for a particular kind of component in your smart home. This optimization is reflected in the data and command types.
Available Item types are:
Item Type |
Description |
Command Types |
Color |
Color information (HSB) |
OnOff, IncreaseDecrease, Percent, HSB |
Contact |
Status of contacts, e.g. door/window contacts. Does not accept commands, only status updates. |
- |
DateTime |
Stores date and time |
- |
Dimmer |
Percentage value for dimmers |
OnOff, IncreaseDecrease, Percent |
Group |
Item to nest other items / collect them in groups |
- |
Image |
Binary data of an image. This means a base64 encoded string |
- |
Location |
GPS coordinates |
Point |
Number |
Values in number format |
Decimal |
Player |
Allows control of players (e.g. audio players) |
PlayPause, NextPrevious, RewindFastforward |
Rollershutter |
Rollershutter Item, typically used for blinds |
UpDown, StopMove, Percent |
String |
Stores texts |
String |
Switch |
Switch Item, used for anything that needs to be switched ON and OFF |
OnOff |
Command Types
In the last step we take a closer look at the Command Types and its Range of Values.
Command Type |
Range of Values |
Decimal |
<int> or <float> |
HSB |
"<hue>,<saturation>,<brightness>" |
IncreaseDecrease |
"INCREASE" or "DECREASE" |
NextPrevious |
"NEXT" or "PREVIOUS" |
OnOff |
"ON" or "OFF" |
OpenClosed |
"OPEN" or "CLOSED" |
!Percent |
0...100 |
PlayPause |
"PLAY" or "PAUSE" |
Point |
"<longitude>,<latitude>,<altitude>" |
RewindFastforward |
"REWIND" or "FASTFORWARD" |
StopMove |
"STOP" or "MOVE" |
String |
<String> |
UpDown |
"UP" or "DOWN" |
A command type like OnOff is ultimately an enum and contains the strings "ON" and "OFF" as constants (this is why they are written in UPPERCASE), so the other enum commands actually look the same. This means that there are only two constants per each enum type.
The Command Types are only used within openHAB. The openhab_msgs also have these enums in their field description, but you may have to work with a string in parts of your program!
Installation
The bridge can be installed with or without HABApp. Since both options access the REST API of openHAB, ROS and openHAB do not need to be installed on the same computer (or virtual machine). However, ROS and openHAB must be able to find each other. Ideally they are in the same network for this.
openHAB
You can skip this part if openHAB is installed. More informations you can find here.
At first you have to install Java:
# install the necessary dependencies sudo apt-get -q update sudo apt-get -yq install gnupg curl # add Azul's public key sudo apt-key adv \ --keyserver hkp://keyserver.ubuntu.com:80 \ --recv-keys 0xB1998361219BD9C9 # download and install the package that adds # the Azul APT repository to the list of sources curl -O https://cdn.azul.com/zulu/bin/zulu-repo_1.0.0-3_all.deb # install the package sudo apt-get install ./zulu-repo_1.0.0-3_all.deb # update the package sources sudo apt-get update # install Azul Zulu JDK 11 sudo apt-get install zulu11-jdk
After that you have to install openHAB 3 and its addons:
curl -fsSL "https://openhab.jfrog.io/artifactory/api/gpg/key/public" | gpg --dearmor > openhab.gpg sudo mkdir /usr/share/keyrings sudo mv openhab.gpg /usr/share/keyrings sudo chmod u=rw,g=r,o=r /usr/share/keyrings/openhab.gpg echo 'deb [signed-by=/usr/share/keyrings/openhab.gpg] https://openhab.jfrog.io/artifactory/openhab-linuxpkg stable main' | sudo tee /etc/apt/sources.list.d/openhab.list sudo apt-get update sudo apt-get install openhab sudo apt-get install openhab-addons
To run openHAB automaticall after restart you have to enable it:
sudo systemctl enable openhab.service sudo systemctl start openhab.service
ROS 1
You can skip this part if ROS 1 is installed.
ROS Noetic for Ubuntu 20.04 ROS Melodic for Ubuntu 18.04 ROS Kinetic for Ubuntu 16.04
After installing ROS you have to create a catkin workspace:
source /opt/ros/<distro>/setup.bash mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_make source devel/setup.bash
As example for ROS Kinetic:
source /opt/ros/kinetic/setup.bash mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_make source devel/setup.bash
Since you access openHAB via the REST API, it is possible that you install the bridge for multiple ROS distributions at the same time. This allows multiple robots running under different distributions to communicate with openHAB. For this you need several computers or virtual machines, HABApp or the pip packages have to be installed on each of them accordingly.
Setting environment variables
If some packages cannot be found please edit the /etc/environment to something like this:
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:$ROS_ROOT:/home/<user>/.local/bin" JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64" ROS_HOME="/home/<user>/.ros" ROS_LOG_DIR=$ROS_HOME/log export PYTHONPATH=$PYTHONPATH:/usr/lib/python3.8/site-packages:/usr/lib/python3/dist-packages:/opt/ros/<ros_distro>/lib/python3/dist-packages:/core/roslib/src:/opt/habapp/bin:/opt/habapp/lib/python3.8/site-packages:/home/<user>/catkin_ws/devel/lib/python3/dist-packages:/home/<user>/.local/lib/python3.8/site-packages:/usr/local/lib/python3.8/dist-packages
Please edit <ros_distro> to your ROS distribution and <user> to the username of your user.
The JAVA_HOME is only needed if you are using openHAB on the same computer or virtual machine than ROS and the openHAB Bridge.
With HABApp
In the variant with HABApp, you must first install HABApp and then adjust it accordingly so that one can use ROS and HABApp together.
Install HABApp
If you are using an older Ubuntu Linux distribution please make sure that you install python3, pip3 and python3-virtualenv. Further informations you can get here.
You have to install HABApp like this:
cd /opt python3 -m venv habapp cd habapp source bin/activate python3 -m pip install --upgrade pip setuptools python3 -m pip install habapp habapp --config /etc/openhab/habapp
To make HABApp run after reboot you have to create a service file with sudo nano /etc/systemd/system/habapp.service:
[Unit] Description=HABApp Documentation=https://habapp.readthedocs.io After=network-online.target [Service] Type=simple User=openhab Group=openhab UMask=002 Environment=LD_LIBRARY_PATH=/home/<user>/catkin_ws/devel/lib:/opt/ros/<ros_distro>/lib ExecStart=/bin/bash -c 'source /etc/environment; /usr/bin/python3 /opt/habapp/bin/habapp -c <PATH_TO_CONFIGURATION_FOLDER>' Restart=on-failure RestartSec=30s [Install] WantedBy=multi-user.target
If you have openHAB and HABApp installed on the same computer, you can also write the service so that HABApp starts, stops and restarts depending on openHAB:
[Unit] Description=HABApp Documentation=https://habapp.readthedocs.io Requires=openhab.service After=openhab.service BindsTo=openhab.service PartOf=openhab.service [Service] Type=simple User=openhab Group=openhab UMask=002 Environment=LD_LIBRARY_PATH=/home/<user>/catkin_ws/devel/lib:/opt/ros/<ros_distro>/lib ExecStart=/bin/bash -c 'source /etc/environment; /usr/bin/python3 /opt/habapp/bin/habapp -c <PATH_TO_CONFIGURATION_FOLDER>' Restart=on-failure RestartSec=30s [Install] WantedBy=openhab.service
Both services are already minimally different from the standard installation of HABApp!
Make sure that your replace <user> with the username on which account you have installed your catkin_ws. Also you have to change the <ros_distro> to the actual ros distro you are using.
Now execute the following commands to enable autostart:
sudo systemctl --system daemon-reload sudo systemctl enable habapp.service
It is now possible to start, stop, restart and check the status of HABApp with:
sudo systemctl start habapp.service sudo systemctl stop habapp.service sudo systemctl restart habapp.service sudo systemctl status habapp.service
How does HABApp work?
HABApp is a Python rule engine for home automation. It has local items, an event bus and can integrate external systems, e.g. openHAB and MQTT. Rules can listen to events from the event bus. These events are generated by HABApp or by the external systems. Additionally there is a scheduler available that makes time based triggering very easy.
The folder structure looks like:
HABApp connects to the openHAB event stream and automatically updates the local openHAB items when an item in openHAB changes. These item values are cached, so accessing and working with items in rules is very fast. The events from openHAB are also mirrored to the internal event bus which means that triggering on these events is also possible.
When HABApp connects to openHAB for the first time it will load all items/things from the openHAB instance and create local items. The name of the local openHAB items is equal to the name in openHAB.
Posting updates, sending commands or any other openHAB interface call will issue a corresponding REST-API call to change openHAB.
Hack HABApp for using ROS
To run ROS with HABApp at the same time, HABApp must be modified accordingly. This is possible because you can also use rospy outside of the catkin workspace to create a node.
Create a ROS node outside the catkin workspace.
Further informations hacking HABApp you can get in the openHAB community.
Edit /opt/habapp/bin/habapp to:
# -*- coding: utf-8 -*- import re import sys import rospy from HABApp.__main__ import main if __name__ == '__main__': rospy.init_node("habapp", anonymous=False) sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) sys.exit(main())
So after starting HABApp you should see the node habapp:
$ rosnode list /habapp /rosout
You could also change the node name to openhab then you will see of course the node openhab.
# -*- coding: utf-8 -*- import re import sys import rospy from HABApp.__main__ import main if __name__ == '__main__': rospy.init_node("openhab", anonymous=False) sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) sys.exit(main())
$ rosnode list /openhab /rosout
Install the ROS openHAB Bridge HABApp Rule
You have to go to the rules folder of HABApp and download the python file. After that you have to make it executable:
cd <PATH_TO_CONFIGURATION_FOLDER>/rules wget https://raw.githubusercontent.com/Michdo93/HABApp-ROS-openHAB-Bridge/main/openhab_bridge.py sudo chown +x openhab_bridge.py
Please make sure that in <PATH_TO_CONFIGURATION_FOLDER>/config.yml the connection is set to your openHAB instance!
Without HABApp
In the variant without HABApp you have to install a catkin package in the source folder of your catkin workspace.
Install dependencies with pip
You have to access the REST API from openHAB to CREATE, READ, UPDATE or DELETE items and you have also to access the Item Events from the Event Bus of openHAB. So you have to install following:
pip install python-openhab-crud pip install python-openhab-itemevents
Install the openHAB Bridge
In the next step you have to install the openhab_bridge in your catkin workspace:
cd ~/catkin_ws/src # does not exist currently. Please use the HABApp solution instead # git clone --branch <branchname> https://github.com/Michdo93/openhab_bridge cd ~/catkin_ws catkin_make
Please replace <branchname> with your branch, as example kinetic-devel, melodic-devel or noetic-devel.
Install the openhab_msgs
Message types for the openhab_bridge. It is based on the Item Types and Command Types of openHAB.
For subscribing from openHAB a State Message Type is used and for publishing to openHAB a Command Message Type is used. For an item type (openHAB), this means that two message types (ROS) are used in this event bus.
Type Name |
State Message Type |
Command Message Type |
Color |
||
Contact |
||
DateTime |
||
Dimmer |
||
Group |
n/a |
|
Image |
||
Location |
||
Number |
||
Player |
||
Rollershutter |
||
String |
||
Switch |
In the next step you have to install the openhab_msgs in your catkin workspace:
cd ~/catkin_ws/src git clone --branch <branchname> https://github.com/Michdo93/openhab_msgs cd ~/catkin_ws catkin_make
Please replace <branchname> with your branch, as example kinetic-devel, melodic-devel or noetic-devel.
Library Overview
ROS package/stack |
Description |
A bridge between ROS and openHAB |
|
Message types for the openhab_bridge. It is based on the Item Types and Command Types of openHAB. |
|
Subscribes States from openhab using a bridge between openHAB and ROS. These are just examples of how you need to proceed for each item type. You can test this by testing the openhab_static_examples. |
|
Publishes Commands to openhab using a bridge between openHAB and ROS. These are just examples of how you need to proceed for each item type. You can test this by testing the openhab_static_examples. |
|
ROS package which listens and subscribes to a topic which uses sensor_msgs/Image or sensor_msgs/CompressedImage as message type. This image will be published as command to openHAB using a bridge between openHAB and ROS. |
|
ROS package which listens and subscribes to the map topic. The subscribed map will be converted to a JPEG image and this image will be published as command to openHAB using a bridge between openHAB and ROS. |
|
Subscribes States from openHAB using a bridge between openHAB and ROS. Similar to rqt_plot, matplotlib is then used to create a mathematical representation that shows the changing values of the States over time. |
|
Does the same as openhab_bridge_plotter with the difference that the plot is converted to an image and then published. |
In a minimal installation you need at least openhab_bridge and openhab_msgs.
Another word for openhab_bridge_image_listener is openhab_bridge_image_converter. And for openhab_bridge_map_listener you can also use openhab_bridge_map_converter.
Tutorials
To work with openHAB and ROS you need a deeper understanding of both. It is possible that I send data from openHAB to ROS and vice versa. I can control ROS via openHAB or I can also control devices that are integrated in openHAB via ROS. Also interesting are rules that I want to use in my smart home. To explain the variety of possibilities you could probably fill a lot of reference books.
In the tutorials section some basics are explained.