-
Notifications
You must be signed in to change notification settings - Fork 0
How To Implement A Binding
Bindings are the most interesting bit for people to get into coding for openHAB and therefore, many questions arise around this topic regularly.
This page tries to give you a starting point, if you intend to implement (and hopefully contribute) your own binding.
For information about how to setup a development environment, please see the according wiki page.
The openHAB runtime distribution comes without any binding. All bindings are considered to be "add-ons", which the user can optionally install by putting it in the "addons" folder of the runtime. As a consequence of this, a binding should usually be a single file and as a file corresponds to an OSGi bundle, a binding should be a single bundle.
The purpose of a binding is to translate between events on the openHAB event bus and an external system. This translation should happen "stateless", i.e. the binding must not access the ItemRegistry in order to get hold of the current state of an item. Likewise, it should not itself keep states of items in memory.
As explained above, a binding should correspond to one bundle. The naming convention for the binding bundle is "org.openhab.binding.<name>
". To create a working binding skeleton one should use the Maven archetype which facilitates the creation process. The following steps have to be performed:
-
run a full build (meaning run
mvn clean install
in the topmost directory)* -
use maven archetype
mvn archetype:generate -B -DarchetypeGroupId=org.openhab.archetype \ -DarchetypeArtifactId=org.openhab.archetype.binding \ -DarchetypeVersion=1.8.0-SNAPSHOT -Dauthor=<author> -Dversion=<target-version-of-binding> \ -DartifactId=org.openhab.binding.<binding-name-in-small-caps> \ -Dpackage=org.openhab.binding.<binding-name-in-small-caps> \ -Dbinding-name=<binding-name-in-camel-case>
-
import newly created project by selecting 'Import->Existing Java project'
-
active the new plugin in !RunConfiguration 'Run Configurations->openHAB Runtime->Plugins->activate your plugin->Auto-start true'
If you have imported the project before, follow the same steps. If you select the same root directory, eclipse scans the path and detects your already imported components. You can only chose your new bundle to import.
Another possibility is to copy an existing binding and do a search&replace for the name.
If the first step fails due to insufficient memory - Java's memory allowance may need to be increased (export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m"
)
#####Integrated binding configuration approach with Declarative Services and Configuration Admin service
A binding may require general configuration settings, such as a host and port of the external system to connect to. This can be done through the OSGi Configuration Admin service. If the binding requires a configuration to be present in order to function, set the configuration policy in the OSGI-INF/binding.xml
file to require
.
configuration-policy="require"
This setting ensures that the binding method activate
will only be called once there is a configuration for the corresponding PID available. The PID is generated by the archetype script and defaults to org.openhab.<name>
, where <name>
is the lower case name of the binding. This name
is used in the openhab.cfg
file as a prefix for the binding configuration.
Setting the configuration policy to optional
means that the binding will be activated even if there is no configuration found for the PID. Should a configuration become available later, or in case the configuration is updated dynamically, the callback method modified
is called from the binding.
Use the maven archetype to create a sample binding project and take a look at the generated stubs for comments.
Note, the activate
and modified
methods are called with a Map<String,Object>
containing the configuration details. An exception thrown by either of the methods will ensure that the binding is not activated and an error is logged by the framework.
/**
* Called by the SCR to activate the component with its configuration read from CAS
*
* @param bundleContext BundleContext of the Bundle that defines this component
* @param configuration Configuration properties for this component obtained from the ConfigAdmin service
*/
public void activate(final BundleContext bundleContext, final Map<String, Object> configuration) {
/**
* Called by the SCR when the configuration of a binding has been changed through the ConfigAdmin service.
* @param configuration Updated configuration properties
*/
public void modified(final Map<String, Object> configuration) {
// update the internal configuration accordingly
}
Furthermore, both methods may be declared to accept a BundleContext
object. This object is only valid while the bundle containing the implementation is ACTIVE
, i.e. started. While the object may be passed around to other objects, care must be taken with regard to its state. When the bundle is stopping, the BundleContext
becomes invalid and throws exceptions on access.
A binding component is automatically deactivated when its bundle is stopped, a mandatory dependency is no longer available, or the required configuration is deleted. In any of these cases, the deactivate
callback method is called with an Integer argument that gives a hint about the reason for the deactivation.
/**
* Called by the SCR to deactivate the component when either the configuration is removed or
* mandatory references are no longer satisfied or the component has simply been stopped.
* @param reason Reason code for the deactivation:<br>
* <ul>
* <li> 0 – Unspecified
* <li> 1 – The component was disabled
* <li> 2 – A reference became unsatisfied
* <li> 3 – A configuration was changed
* <li> 4 – A configuration was deleted
* <li> 5 – The component was disposed
* <li> 6 – The bundle was stopped
* </ul>
*/
public void deactivate(final int reason) {
this.bundleContext = null;
// deallocate resources here that are no longer needed and
// should be reset when activating this binding again
}
In the openhab.cfg
file configure the specific binding properties using the <name>
prefix as described above.
################################ <name> Binding ##########################################
#
# refresh interval in milliseconds (optional, defaults to 900000 [15 minutes])
<name>:refresh=60000
#####Alternative manual binding configuration approach
This section describes how bindings can be configured using the OSGi Configuration Admin service.
A binding may require general configuration settings, such as a host and port of the external system to connect to. This can be done through the OSGi Configuration Admin service, i.e. by registering an OSGi service, which implements the interface org.osgi.service.cm.ManagedService
.
Besides implementing the ManagedService
interface, you have to add the service.pid
property as well as the provide element for the ManagedService
to the OSGi Declarative Services XML file (in the OSGI-INF
folder):
<service>
<provide interface="org.osgi.service.cm.ManagedService"/>
</service>
<property name="service.pid" type="String" value="org.openhab.<name>"/>
Replace <name>
with the prefix to be used in openhab.cfg
.
openHAB then allows to add configuration information in openhab.cfg
, which is automatically dispatched to your ManagedService.
Please refer to the KNX binding for an example on how to implement a ManagedService
and how to register it through OSGi Declarative Services.
t.b.d.
There are two directions for the communication of a binding - either sending out commands and status updates from the openHAB event bus to some external system or to receive information from an external system and post this on the openHAB event bus for certain items.
A binding can implement the one or the other direction or both. We usually talk about "Out-", "In-" or "InOut-Bindings" respectively.
A good example for such an "Out-Binding" is the Exec-binding. When receiving a command for an item, a configured command is executed on the command line of the host system.
Such bindings can be implemented pretty easily: All you have to do is to extend the class AbstractBinding
([Abstract binding on GitHub] (https://github.com/openhab/openhab/blob/master/bundles/core/org.openhab.core/src/main/java/org/openhab/core/binding/AbstractBinding.java)) and override the methods
public void internalReceiveCommand(String itemName, Command command)
and / or
protected void internalReceiveUpdate(String itemName, State newState)
As the method signatures suggest, you are passed the name of the item and the command or state that was sent on the openHAB event bus. In these methods, you can then perform whatever code is appropriate for your use case. See the ExecBinding class as an example.
All there is left to do is to register your class with the OSGi event admin service. To do so, your component has to provide the EventHandler
service and define the property event.topics
. In your OSGI-INF/binding.xml
file, this should look like this:
<service>
<provide interface="org.osgi.service.event.EventHandler"/>
</service>
<property name="event.topics" type="String" value="openhab/*"/>
If you are only interested in commands, you can also choose openhab/command/*
as a topic.
See the component descriptor of the ExecBinding as an example.
If you receive information from an external system somewhere in your code and you want to post commands or status updates on the openHAB event bus, you can as well simply extend AbstractBinding
for your implementation. Your binding class should then reference the EventPublisher
service in the OSGI-INF/binding.xml
file. This should look like this:
<reference bind="setEventPublisher" cardinality="1..1" interface="org.openhab.core.events.EventPublisher" name="EventPublisher" policy="dynamic" unbind="unsetEventPublisher"/>
In your code, you can then simply refer to the instance variable eventPublisher
in order to very easily send events:
eventPublisher.postUpdate(itemName, state);
eventPublisher.postCommand(itemName, command);
eventPublisher.sendCommand(itemName, command);
Please note the difference between sendCommand
and postCommand
: Sending means a synchronous call, i.e. the method does not return until all event bus subscribers have processed the event. So if you just want to do a fire&forget, use the asynchronous postCommand method instead.
In order to receive information from an external system, you usually either need some background thread continuously listening to the external system (e.g. on a socket or serial interface) or you need to regularly actively poll the external system. In both cases, choosing to extend the class AbstractActiveBinding
(Abstract Active Binding on GitHub) will help you.
AbstractActiveBinding
extends AbstractBinding
(Abstract Binding on GitHub) so everything said above will still be the same. You will simply get an additional feature: The active binding provides a thread creation and handling and all you have to do is to specify a pause interval between calls of the execute()
method.
See the NtpBinding class for a simple example of such a binding. ntp:refresh
in openhab.cfg is the ntp specific pause interval.
A few notes on the lifecyle: Bindings are dynamic OSGi services and thus behave according to the OSGi specs. The dynamics make it easy to change openHAB during runtime (add new bindings later on, reconfigure items, etc.), but it also brings some complexity in the coding. In consequence the methods of the interfaces that the bindings implement (such as addBindingProvider()
, allBindingsChanged()
, updated()
, processBindingConfiguration()
etc.) can be called at any time and in any order. So you need to make sure that you write your code in a way that you can always react in a decent way when a method is called and reach a valid state of your binding.
This specifically means:
-
activate()
is called as soon as all required dependencies (e.g. the first !BindingProvider) are resolved and set in your service instance - optional dependencies might be set any time (e.g. a second !BindingProvider is set through
addBindingProvider()
) -
updated()
is called any time, but afteractivate()
. So you should even consider the case that you receive invalid configuration at a later time and thus stop your services again (->setProperlyConfigured(false)
). -
processBindingConfigurations()
can be called anytime, but always afteractivate()
After IDE setup and creating/testing your binding, you may want others to use it. For this, you can use the Eclipse export function as follows:
- Right-click on your binding project
- Select Export
- Choose Plug-in Development->Deployable plug-ins and fragments
- Fill "Directory" with the Path where you want your jar-file to appear
- Check "Use class files compiled in the workspace" on the "Options" tab
- Click Finish and check yor Directory
###Linux / OS X
###Windows
- Cosm Persistence
- db4o Persistence
- Exec Persistence
- InfluxDB Persistence
- JDBC Persistence
- JPA Persistence
- Logging Persistence
- mapdb Persistence
- MongoDB Persistence
- MQTT Persistence
- my.openHAB Persistence
- MySQL Persistence
- rrd4j Persistence
- Sen.Se Persistence
- SiteWhere Persistence
- AlarmDecoder Binding
- Anel Binding
- Arduino SmartHome Souliss Binding
- Asterisk Binding
- Astro Binding
- Autelis Pool Control Binding
- BenQ Projector Binding
- Bluetooth Binding
- Bticino Binding
- CalDAV Binding
- Comfo Air Binding
- Config Admin Binding
- CUL Binding
- CUL Intertechno Binding
- CUPS Binding
- DAIKIN Binding
- Davis Binding
- Denon Binding
- digitalSTROM Binding
- DMX512 Binding
- DSC Alarm Binding
- DSMR Binding
- eBUS Binding
- Ecobee Binding
- EDS OWSever Binding
- eKey Binding
- Energenie Binding
- EnOcean Binding
- Enphase Energy Binding
- Epson Projector Binding
- Exec Binding
- Freebox Binding
- Freeswitch Binding
- Frontier Silicon Radio Binding
- Fritz AHA Binding
- Fritz!Box Binding
- FS20 Binding
- Global Cache IR Binding
- GPIO Binding
- HAI/Leviton OmniLink Binding
- HDAnywhere Binding
- Heatmiser Binding
- Homematic / Homegear Binding
- HTTP Binding
- IEC 62056-21 Binding
- IHC / ELKO Binding
- ImperiHome Binding
- Insteon Hub Binding
- Insteon PLM Binding
- IPX800 Binding
- IRtrans Binding
- jointSPACE-Binding
- KNX Binding
- Koubachi Binding
- LCN Binding
- LightwaveRF Binding
- Leviton/HAI Omnilink Binding
- Lg TV Binding
- Logitech Harmony Hub
- MailControl Binding
- MAX!Cube-Binding
- MAX! CUL Binding
- MiLight Binding
- MiOS Binding
- Modbus TCP Binding
- MPD Binding
- MQTT Binding
- MQTTitude binding
- Neohub Binding
- Nest Binding
- Netatmo Binding
- Network Health Binding
- Network UPS Tools Binding
- Nibe Heatpump Binding
- Nikobus Binding
- Novelan/Luxtronic Heatpump Binding
- NTP Binding
- One-Wire Binding
- Onkyo AV Receiver Binding
- Open Energy Monitor Binding
- OpenPaths presence detection binding
- OpenSprinkler Binding
- OSGi Configuration Admin Binding
- Panasonic TV Bindung
- panStamp Binding
- Philips Hue Binding
- Piface Binding
- pilight Binding
- Pioneer-AVR-Binding
- Plex Binding
- Plugwise Binding
- PLCBus Binding
- Primare Binding
- Pulseaudio Binding
- RFXCOM Binding
- RWE Smarthome Binding
- Sager WeatherCaster Binding
- Samsung AC Binding
- Samsung TV Binding
- Serial Binding
- Sallegra Binding
- Satel Alarm Binding
- Sinthesi Sapp Binding
- Snmp Binding
- Somfy URTSI II Binding
- Sonos Binding
- Squeezebox Binding
- Swegon ventilation Binding
- System Info Binding
- TA CMI Binding
- TCP/UDP Binding
- Tellstick Binding
- TinkerForge Binding
- Tivo Binding
- VDR Binding
- Velleman-K8055-Binding
- Wago Binding
- Wake-on-LAN Binding
- Waterkotte EcoTouch Heatpump Binding
- Weather Binding
- Wemo Binding
- Withings Binding
- XBMC Binding
- xPL Binding
- Yamahareceiver Binding
- Zibase Binding
- Z-Wave Binding
- Asterisk
- Google Calendar
- Linux Media Players
- ROS Robot Operating System
- Telldus Tellstick
- Zoneminder
- Wink Hub (rooted)
- Wink Monitoring
- Transformations
- XSLT
- JSON
- REST-API
- Security
- Service Discovery
- Voice Control
- BritishGasHive-Using-Ruby
- Dropbox Bundle
A good source of inspiration and tips from users gathered over the years. Be aware that things may have changed since they were written and some examples might not work correctly.
Please update the wiki if you do come across any out of date information.
- Comfo Air Binding
- Ecobee Examples
- Nest Examples
- Rollershutter Bindings
- Squeezebox
- WAC Binding
- WebSolarLog
- Alarm Clock
- Convert Farenheit to Celcius
- The mother of all lighting rules
- Reusable Rules via Functions
- Combining different Items
- Items, Rules and more Examples of a SmartHome
- Google Map
- Controlling openHAB with Android
- Usecase examples
- B-Control Manager
- Spell checking for foreign languages
- Flic via Tasker
- Chromecast via castnow