Friday, April 15, 2016

Using Cisco Spark as notification channel for Openhab

Notify from Openhab using Cisco Spark

I'm using Openhab for my home automation for a couple years now and am very happy with it.  One of the things it can do it notify you on various events around the house.  I had XMPP configured to send messages to my Google account, but the last months this has been failing.  Some error about pinning certificates.  There's some information on the internet about how to solve this, but I'm using a Google account with a custom DNS name which seems to complicate matters a bit.

Since Cisco added APIs to the Cisco Spark service (try it!!), I wanted to use Spark instead for my notifications.  The proper way of integration with Openhab is to develop an Openhab plugin, but I wanted something more versatile. So I started the development of a CLI interface for Spark: sparkcli.  Let's get going!

Install and configure sparkcli

First download a copy of sparkcli here: .  Make sure the binary is on the PATH for the OS user that's running Openhab.  Typically /usr/local/bin will do just fine.

Once downloaded, following the configuration instructions here:
In short these are the steps you'll follow:

  1. Set up Cisco Spark developer account and configure an app
  2. Go through the OAuh authorization process
  3. Create a configuration file.  Note: easiest is if you create this in the home directory of the OS user that's running Openhab.
  4. Login once using sparkcli to get access tokens.
That's it.

Use sparkcli in Openhab rules

Now you can use this in any rule that you define in Openhab.

rule "Notify alarm"
  Item o_alarmFull changed
  if (o_alarmFull.state == ON) {
    //sendXMPP("", "Alarm aan")
  } else {

Openhab has some weird syntax about spaces in command lines, but it works.


I might get around building a proper Cisco Spark plugin for Openhab, so stay tuned!

Wednesday, December 2, 2015

Why we need more engineers

Warning: heavy generalization and stereotype thinking ahead!

Why we need more engineers:

Architect: I need this algorithm for my big plans
PM: Did you get that?
Developer: Say what?
Architect: I need this algorithm for my big plans
PM: Did you get that?
Developer: Say what?
Architect: I need this algorithm for my big plans
PM: Did you get that?
Developer: Is this what you need?
Architect: No!
PM: Completed 80%
Developer: Is this what you need?
Architect: No!
PM: Completed 90%
Developer: Is this what you need?
Architect: No!
PM: Completed 95%
Developer: Is this what you need?
Architect: Yes.


Engineer: Let me start a Git repo to collaboratively build this algorithm, so I can move on with the rest of my big plans.

Tuesday, March 3, 2015

IPv6 linux gateway for home network with Telenet (Belgian ISP)

This took me a while to figure out, but I finally got the missing piece figured out.  I'm using Telenet as an ISP to provide access from my home network.  I have a linux box acting as a gateway router for the home network with some basic services that I use in my home.
The ISP has IPv6 enabled on their cable modems for a while, and I've been trying to extend that IPv6 network into my home network.  After all, they're handing out a /64 to all end users.  Here's how I got it to work.

The situation looks like this. The Telenet router is the ISP provided cable modem.  After that I have my Ubuntu linux gateway.  For the examples later, eth0 is the home network, eth1 is towards the internet.

The address range for the home network can be found on the admin pages from the ISP (warning - dutch content)

To turn on IP forwarding, configure in /etc/ufw/sysctl.conf:

I'll focus on the IPv6 specific settings in the remainder of the post.
In /etc/network/interfaces:
iface eth0 inet6 static
 address 2a02:1810:2088:5b00::100
 netmask 64
 up ip route add 2a02:1810:xxxx:xxxx::/64 dev eth0 metric 100
 down ip route del 2a02:1810:xxxx:xxxx::/64 dev eth0 metric 100

Note that I added an explicit metric.  If I didn't do this, the default route that is assigned to eth1 would get the upperhand, and I wouldn't be able to properly communicate within my home network since the gateway would send all traffic out the door.

Install radvd to autoconfigure devices on the home network:
sudo apt-get install radvd

And configure it:
interface eth0
   AdvSendAdvert on;
   MinRtrAdvInterval 30;
   MaxRtrAdvInterval 100;

   # There's no DHCPv6
   AdvManagedFlag off;
   AdvOtherConfigFlag off;

   prefix 2a02:1810:xxxx:xxxx::/64
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr on;

Now before we add the last piece, make sure you have proper firewall rules in place.  I suggest configuring /etc/default/ufw to have disable forwarding by default (and potentially the other chains too):
Then specifically add firewall rules as required for your network.  Two things to know about:
  • There's no need for NAT with IPv6, so you can allow access directly to internal hosts
  • Ensure to configure the firewall on the "Mijn Telenet" ISP admin page in addition to the firewall on the linux gateway.

Now the last piece, which I couldn't figure out for the longest time: when requests come in from the internet (or responses from outgoing packets) the telenet router relies on IPv6 neighbor discovery to figure out who's behind it.  The linux gateway router doesn't proxy such requests by default.
You can compare this with ARP in IPv4.  The Telenet gateway is trying to figure out who has got a certain IPv6 address, and sends out neighbor solicitations.  The linux gateway will respond only when it hears its own address.  We can tell it to respond on behalf of the hosts on the home network by installing ndppd.

sudo dpkg -i ./ndppd_0.2.3-1_amd64.deb

Then configure it (/etc/ndppd.conf):
proxy eth1 {
    rule 2a02:1810:xxxx:xxxx::/64 {

Now start ndppd:
sudo service ndppd start

And that's it.. now the gateway will respond to IPv6 neighbor solications on eth1 for the entire /64 network.
You should not be able to get to IPv6 enabled websites from within your home network.  Most modern Windows computers will automatically configure themselves after the setup above.  Give it a try and navigate to  and you should see a confirmation.

Saturday, October 4, 2014

DDNS with Docker and nsupdate

Many robust and scalable solutions exist for monitoring docker containers and publish their IP addresses into some service discovery solution.  SkyDNS or are such examples.  However I wanted a simpler solution for the few containers I run on my home network server, so I put together the simplest service discovery mechanism possible.

Place the following file in /etc/cron.daily - this has been tested on Ubuntu 14.04:

CONTAINERS=($(docker ps -q))    # fetch all containers
TTL="86400"                     # 1 day

# prepare file
if [ -f $TMPFILE ]; then

  NAME=`docker inspect -f '{{.Name}}' $CONTAINER`
  NAME=${NAME#/} # remove leading / from container name
  IP=`docker inspect -f '{{.NetworkSettings.IPAddress}}' $CONTAINER`
  echo "update add $NAME.$DOMAIN $TTL A $IP" >> $TMPFILE
echo "send" >> $TMPFILE

nsupdate -k $KEY $TMPFILE
exit 0

The script be executed daily. It fetches all containers from docker and publishes their name+domain with their ip address to bind9 DNS server.

If start new containers, you can manually run the script again to update DNS.

Note: this script does not remove DNS names when you stop containers.

Thursday, September 18, 2014

Go on Ubuntu


I have a strong Java background and have messed around with various other languages but never become fluent in any of them.  I guess because I didn't have to.  Perl crossed my path early in my career, then Ruby became popular and later python.
Now I'm looking at Go.  Actually it's the third time or so I'm doing that, and this time there seems to be a click.  What attracts me most is that it's fairly easy to pick up, and... it generates a single executable that can exist on its own without having to install a run-time environment.  I assume that's one of the reasons why it's so popular in the cloud community these days (yes, next to python of course).
Anyway, just a quick write-up so I don't forget how to quickly get started with Go after my next PC refresh.  There's nothing new here... just summarizing few key steps in one place.

The basics

Check the downloads section in the golang website for the latest and download it.

$ cd /tmp
$ wget --no-check-certificate
$ sudo tar -C /usr/local -xzf go1.3.1.linux-amd64.tar.gz

Create a workspace where you want to keep your Go projects

$ cd ~
$ mkdir -p ./workspace/go/src
$ mkdir -p ./workspace/go/bin

Add these lines to your ~/.bashrc file

export PATH=$PATH:/usr/local/go/bin
export GOROOT=$HOME/workspace/go
export PATH=$PATH:/$GOROOT/bin

Syntax highlighting and autocomplete in vi

Once there's good information on various tooling integration in /usr/local/go/misc.  I'm interested in vi.  Based on what's there in /usr/local/go/misc/readme.txt, here is the content of my /etc/vim/vimrc.local file.

" Some Linux distributions set filetype in /etc/vimrc.
" Clear filetype flags before changing runtimepath to force Vim to reload them.
if exists("g:did_load_filetypes")
  filetype off
  filetype plugin indent off
set runtimepath+=/usr/local/go/misc/vim " replace $GOROOT with the output of: go env GOROOT
filetype plugin indent on
syntax on

" Reformat on exit/write of file.
autocmd FileType go autocmd BufWritePre <buffer> Fmt

" Close auto-complete window when exiting edit/insert mode.
autocmd InsertLeave * if pumvisible() == 0|pclose|endif

" Auto-complete braces
inoremap {      {}<Left>
inoremap {<CR>  {<CR>}<Esc>O
inoremap {     {
inoremap {}     {}

inoremap (      ()<Left>
inoremap (<CR>  (<CR>)<Esc>O
inoremap (     (
inoremap ()     ()

inoremap [      []<Left>
inoremap [<CR>  [<CR>]<Esc>O
inoremap [     [
inoremap []     []

And that's it.  You should now see syntax highlighting in vi.  Ctrl+x, ctrl+o opens up auto-complete.

Updated! Initial version of this post had some issues (<> tags where missing)

Tuesday, July 15, 2014

Docker repository for Openhab 1.5.0

I just finished a Docker repository for Openhab 1.5.0 which allows faster deployment.  The repo is available here:

The source code for the repository is available from github:

Assuming you have docker installed on your machine, these are the few steps to take to get openhab up and running.

  1. Create a config directory and store your openhab configuration files there.  This is the content of [OPENHAB_HOME]/configurations and will be injected into the container.  Let's assume you chose /tmp/config.
  2. Add a file called addons.cfg into that same config directory.  This file is used to determine which plugins to enable for your deployment.  Each line in the config file should have the name of the addon jar file to load. My file looks like this:
# cat config/addons.cfg
  1. Run docker:
    docker run --rm -p 80:8080 -v /tmp/config:/opt/openhab/configurations tdeckers/openhab
Now you can access the openhab installation on port 80 of your host.


Tuesday, March 18, 2014

Alarm Clock operates your house

I have my house wired up pretty nicely with all kinds of automation - I'll post details on this later.  Today, I wanted to hook up the alarm clock on my phone.  Basic scenario: when the alarm goes off, turn on the lights and open the shutters.  Let's get to it.

I have a KNX-based home automation system, but most of the advanced scenarios are configured in OpenHAB.  The basic flow for automating this alarm clock scenario is documented here:

Let's go wild and start with the middle part here.  We configure an item in OpenHAB that we can use to trigger the alarm.  Look here for details on adding items in OpenHAB.  We'll add this line:

Switch pWekkerTom "Wekker Tom" {autoupdate="false"}

If you're not familiar with this 'autoupdate' parameter, don't worry about it. It just makes this switch act as a trigger without changing its state.  The scenario would work even without it.

Next we create a rule that catches commands for the pWekkerTom item, and performs whatever actions we want when our alarm goes off.

rule "Wekker Tom"
        Item pWekkerTom received command ON
logInfo("PERSONAL", "Wekker Tom!")
sendCommand(lBMasterGang, 25)
createTimer(now.plusSeconds(45)) [| sendCommand(lBMasterGang, 50)]
createTimer(now.plusSeconds(90)) [| sendCommand(lBMasterGang, 75)]
createTimer(now.plusSeconds(120)) [| sendCommand(shMaster, UP)]

This rule will:

  1. log a note in the openHAB logs
  2. dim lights in the hallway of the bedroom to 25%
  3. after 45 seconds, dim lights to 50%
  4. after 90 seconds, dim lights to 75%
  5. after 120 seconds, move the shutters up
You can completely customize this to your own desires.

Now all is left is a way to have our mobile phone trigger all of the above.  For this purpose, we use the swiss army knife of Android automation: Tasker. (Apologies iPhone users - you're out of luck here.  I'm sure Tasker equivalents exist, I just don't have any experience with them).
We'll use the OpenHAB REST API, so we'll also install the RESTask for Tasker plugin.  This provides a bit more features than the native Tasker HTTP actions.

Once both are installed from the Google Play Store, first go to the Tasks tab in Tasker and create a new Task. in this Task, create an Action by clicking the + sign at the bottom of the screen.  For action category, select Plugin -> RESTask.
In the configuration of the RESTask, fill in these fields:
  • Request Type: POST
  • Host:
  • Basic Auth: <your credetials>
  • Enable custom body: check!
  • Custom body: ON
You can leave most other settings to their defaults, but it depends on your setup.
Save all this goodness.  The last step is to create a profile that ties the alarm clock to the task.
Go to the Profiles tab in Tasker and create a new Profile by clicking the + sign at the bottom of the screen. In event category select Date/Time -> Alarm Clock.
Save this, and then associate this profile with the Task you have created earlier.  Done!

In more detail, this is what we've accomplished: