OpenHAB2 binding architecture

by kacang bawang

In this article I will walk the reader through the inner workings of an OpenHAB2 binding. It is meant to answer the question of “who calls who and when?”, which invariably arises when one starts working with a new framework. It is a summary of what I had learned while writing the binding for my smart switch. If you are thinking about writing a custom binding from scratch, then this article is for you!

What is a binding?

An OpenHAB binding is the layer between OpenHAB and your device, which manages internal OpenHAB commands and decides when and how to send them to your actual device (and vice versa). Think of it as a driver for your device in the OpenHAB “OS”. OpenHAB only knows its own language and its own commands, while the binding translates those OpenHAB commands into different commands that the device expects and understands.

How is a binding implemented?

A binding is implemented as an OSGI bundle, which somewhat resembles a Java DLL. It contains a bunch of code and one or more classes exposed for outside users for something to grab on to. So, to create a binding we will create an OSGI bundle which will expose a class that OpenHAB will know what to do with.

How will OpenHAB detect my binding?

Openhab will look in a certain directory, and will load all bundles (jar files, called addons) within it. It will then look at the “exposed handles” of each addon and will attempt to interact with it if it finds what it was looking for. Each such handle is declared via an xml file, found in:

Typically, such exported classes will be:
– DiscoveryService
– ThingHandlerFactory

How will OpenHAB interface to my binding?

There are two major parts to a binding:
1. Thing discovery
2. Thing management

Discovery service is a class that is instantiated as OpenHAB is starting regardless of whether or not a device is actually connected. Its job is to look for devices as they are connected. It is typically implemented as a thread, which either polls for new devices or listens for new devices to report in on their own. Discovery is not mandatory – if you do not have a discovery service for your device, each new device will need to be manually added via the OpenHAB configs.

OpenHAB will look for a DiscoveryService within our bundle and launch it if it finds one.

Thing handler is a class that gets instantiated when a device is known to the system from either the config files or through the discovery service. ThingHandler’s correspond 1:1 with “Things” – which, in turn, are the virtual counterparts to our device/sensor/etc within OpenHAB. ThingHandler class will act upon received OpenHAB commands and will also provide a way for the device to relay information to OpenHAB.

OpenHAB will look for a ThingHandlerFactory in our binding bundle. This is what it will use to instantiate ThingHandler’s. Only the ThingHandlerFactory needs to be exposed to OpenHAB.

How will the binding communicate with the physical device

Generally we need to be able to send messages to our device and either: poll for device status or listen for asynchronous communications from it. These operations rely on whatever physical protocol the device utilizes: RF/WiFi/RS232/etc.

This is the point where there will be a lot of variation in terms of binding architecture design. For example, one can imagine a system that keeps one “server” that is central to all messages in and out, and which has a link to every ThingHandler in order to call its methods. Another, less efficient, approach would be for every ThingHandler to maintain its own thread for sending and receiving messages.

Example

Let’s dissect the yahooweather binding as an example. The first thing that happens is a DiscoveryService is created. Why? Because we declared it as an OSGI export. So upon the loading of our addon bundle, OSGI will create and launch it. Let’s take a look at the key functions in this class.

These functions must be overridden in order to inherit from AbstractDiscoveryService:

Above is all that is required. However, the really useful methods are the following, despite them being “optional”.

The last several methods worth mentioning are the following:

So, our discovery thread kicked off, went, and fetched a location based on our IP address, and submitted a locationName/locationId pair to thingDiscovered. Out of these two, a unique id for the Thing is constructed. After some internal digestion OpenHAB will realize that to handle this type of Thing it needs a YahooWeatherHandler, which can only be made by a YahooWeatherHandlerFactory. Helpfully, the Factory class has also already been created by OSGI for us, as we declared it in the OSGI exports.

We are required to implement the following two methods. This class is pretty straightforward.

Ok, now that the factory has been identified, the system, acting on the thingDiscovered() message will grab a ThingHandler from the factory. Then it will proceed to call some of the handler’s methods. Let’s take a look at key functions of the ThingHandler class.

First the functions that must be defined:

Next are some lifecycle functions that can be overridden from the parent:

The following paragraph does not apply to YahooWeather binding, as it does not use what is discussed within.

The problem is this – known Things will be created whether they are currently available (online) or not. This is somewhat logical – just because an item went offline (could be a flaky connection) doesn’t mean it’s uninstalled from the home. Therefore we must make a distinction between an Thing structure being allocated in the system, and Thing coming online. The former is realized in initialize(), the latter is best realized though the discovery service. Thus, the discovery service accepts new devices as well as prodigal ones.

To receive these discovery events, the ThingHandler class can realize the DiscoveryListener interface. The framework will then call the relevant
methods for all discovery events that go through the system – such as when DiscoveryService calls thingDiscovered().

So far, the discussion of ThingHandler has only concerned with data coming /in/ to the Thing. But how can the Thing send messages to the framework? For example – temperature reading changed, as indicated by polling, now we need to update the UI. What to do?

The following functions are available to a ThingHandler (via parent class) to send data /out/ of the Thing.

What is a Status and what is a State?

Status describes things like whether the Thing is ONLINE or not. It does not describe the “contents” of the Thing, such as a temperature reading, or a relay position in device. Here is a list of possible statuses:

State describes the value of one of the readings from the device that is stored in the Thing. These readings are represented by Channels. Thus, a Thing includes one or more Channels, where Channels can be of different types. For example, a Switch channel with two states – ON and OFF. Or a Decimal channel, whose state is the value of that Decimal. Therefore, an update of State involves telling the framework that the value of one of the channels changed, and here’s the new value.

The full list of States can be found in this directory. All classes that implement State are “States”.

Incidentally, that same folder also contains all the Commands. Any class that implements Command are “Command”s. As such, the same class frequently represents both a State and a Command.

In Conclusion

With this our discussion of OpenHAB binding architecture has come to an end. Hopefully, the above will save you some time designing your custom binding when you first dig your teeth into OpenHAB2.