Wall switch wonderland

wallc-s-e

In my previous post I explained how to connect Z-Wave (Plus) wall plugs to Openhab via MQTT with the help of mqttwarn and Z-Way server. Today is time to do the same with Z-Wave.me WALLC-S wall switches. Some people have been able to get these to work just fine, but I stumbled across to quite many posts where people have been having trouble configuring them especially in DIY installations, such as Openhab.

These too are Z-Wave Plus (Gen 5) devices that require SECURITY class functionality from Z-Wave server and thus there was no way to use them with the Z-Wave stack of Openhab. I did try to turn off the security functionality but in the end didn’t figure out how to do that. Nonetheless, the Z-way server from Z-Wave.me (that we hacked a bit in the previous post) works with these switches just fine. I like also the ability to decouple the handling of Z-Wave communication from Openhab and use MQTT as the interface for as many devices as possible.

WALLC-S can act as a basic on/off switch, dimmer as well as a scene switch. I didn’t want to program any kind of scene handling to devices but instead let the Openhab handle all the logic side, so dumb on/off and dimmer functionality is enough for my needs.

wallc-s-conf

After Z-Wave device inclusion we must first add the Z-Way server (more accurately, the Razberry) to WALLC-S’s control groups A and B (to receive notifications about button #1 and #3 presses) as well as to its “Life line” group (to receive update and battery status messages). Note that we must associate each WALLC-S to unique instance of Razberry to differentiate between switches. So for WALLC-S #1 (and #2), it is added to instance #1 (and #2 respectively) of control groups A and B.

Then we have to configure the button behaviour. I have a single paddle on both of the switches, so I set the switch in a pair mode (uppermost buttons 1 and 2 work in pairs, as well as the lower row buttons 3 and 4). Actually separate mode would work just as well, since we are not interested in the control group C and D messages.

Finally we configure for both control groups the command type which is sent to Razberry, in this case “Switch On/Off and Dim”.

Another Z-Way JSON debugging session…

Now when buttons #1 and #3 of WALLC-S #1 are pressed, the following data structures are updated:

[2015-07-11 01:24:02.944] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.srcNodeId = 22 (0x00000016)
[2015-07-11 01:24:02.945] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 01:24:02.945] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.level = 255 (0x000000ff)
.
.
[2015-07-11 01:25:24.109] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.srcNodeId = 22 (0x00000016)
[2015-07-11 01:25:24.109] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 01:25:24.110] [D] [zway] SETDATA devices.1.instances.1.commandClasses.32.data.level = 0 (0x00000000)

So command class 32 level is 255 for button #1 press and 0 for button #3 press.

Battery levels are received like this:

[2015-07-11 01:31:40.961] [D] [zway] SETDATA devices.22.data.lastReceived = 0 (0x00000000)
[2015-07-11 01:31:40.961] [D] [zway] SETDATA devices.22.instances.0.commandClasses.128.data.history.96 = 1436567500 (0x55a047cc)
[2015-07-11 01:31:40.962] [D] [zway] SETDATA devices.22.instances.0.commandClasses.128.data.last = 96 (0x00000060)

When button #1 is kept pressed (dimmer up)..

[2015-07-11 15:21:11.145] [D] [zway] SETDATA devices.19.data.lastReceived = 0 (0x00000000)
[2015-07-11 15:21:11.146] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcNodeId = 19 (0x00000013)
[2015-07-11 15:21:11.146] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 15:21:11.146] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.startChange = True

..and released:

[2015-07-11 15:21:12.650] [D] [zway] SETDATA devices.19.data.lastReceived = 0 (0x00000000)
[2015-07-11 15:21:12.650] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcNodeId = 19 (0x00000013)
[2015-07-11 15:21:12.650] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 15:21:12.650] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.stopChange = Empty

Similarily, button #3 is kept pressed (dimmer down)..

[2015-07-11 15:25:11.367] [D] [zway] SETDATA devices.19.data.lastReceived = 0 (0x00000000)
[2015-07-11 15:25:11.368] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcNodeId = 19 (0x00000013)
[2015-07-11 15:25:11.368] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 15:25:11.368] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.startChange = False

..and released:

[2015-07-11 15:25:12.440] [D] [zway] SETDATA devices.19.data.lastReceived = 0 (0x00000000)
[2015-07-11 15:25:12.440] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcNodeId = 19 (0x00000013)
[2015-07-11 15:25:12.440] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.srcInstanceId = 0 (0x00000000)
[2015-07-11 15:25:12.440] [D] [zway] SETDATA devices.1.instances.2.commandClasses.38.data.stopChange = Empty

So the “StopChange” indicates button release and “StartChange” is true for dimmer up and false for dimmer down. Note that the actual values will be lingering in the JSON tree long after buttons have been released and StopChange doesn’t seem to ever change its value, but only the updateTime tag is updated. Nonetheless, we don’t have to check for changes in values but just bind to the JSON tree to get notifications when the tags have been updated, just like in previous post.

I found out that Z-Way server holds no functionality to contain dimmer value nor there is any way to automatically get notifications on certain intervals that the button is still kept pressed, so we have to implement our on notification mechanism with timers in JavaScript. For the actual dimmer value (e.g. 0-100%), we let Openhab take care of that.

Hooking Z-Way server…

The amount of our extra code in main.js of Z-Way server is getting bigger (see the previous post), so we move it to separate file (mqtt.js) and just put this in the end of main.js:

    executeFile("mqtt.js");

In mqtt.js we define (in addition to Wall Plug code explained in the previous post)


// Here the id:19 and id:22 are hardcoded Z-Wave device ID's. Change them (and associated instance IDs) accordingly to your setup
var dimmers = [];
dimmers.push( { id:19, instance:1, timer:null, timercount:0 } );
dimmers.push( { id:22, instance:2, timer:null, timercount:0 } );

var dimmer_publish_interval = 100;  // in milliseconds

function getById(id, myArray) {
        for ( var i=0; i<myArray.length; i++) {
                if(myArray[i].id == id) {
                         return myArray[i];
                }
        }
        return null;
}

function battery_level_publish (device, theValue) {
        eventString = 'Device' + device + "/battery";
        publish_mqtt(eventString, theValue);
}

function wallswitch_binary (device, theValue) {
        eventString = 'Device' + device + "/wallswitch/binary";
        state = 'on';
        if (theValue == false){
                state = 'off';
        }
        publish_mqtt(eventString, state);
}

function wallswitch_dimmer_publish (device, theValue) {
        eventString = 'Device' + device + "/wallswitch/dimmer";
        state = 'increase';
        if (theValue == false){
                state = 'decrease';
        }
        publish_mqtt(eventString, state);
}

function wallswitch_dimmer_start (device, theValue) {
        wallswitch_dimmer_publish (device, theValue);
        dimmer = getById(device, dimmers);
        if (dimmer != null)
        {
                if (dimmer.timer != null) {
                        clearInterval(dimmer.timer);
                }
                dimmer.timercount = 0;
                dimmer.timer = setInterval(
                        function() {
                                wallswitch_dimmer_publish (device, theValue);
                                dimmer.timercount++;
                                if (dimmer.timercount>20) {
                                        // this is to stop sending updates eventually if for some reason the "dimmer_stop" 
                                        // message is not received and the dimmer gets "stuck"
                                        clearInterval(dimmer.timer);
                                }
                        }, dimmer_publish_interval);
        } else
        {
                console.log("dimmer not found!");
        }
}


function wallswitch_dimmer_stop (device, theValue) {
        dimmer = getById(device, dimmers);
        if (dimmer != null)
        {
                if (dimmer.timer != null)
                        clearInterval(dimmer.timer);
        }
}

// Binding to WALLC-S devices
for (var i=0; i < dimmers.length; i++) {

        var id = dimmers[i].id;
        (function(devid) {
                console.log("MQTT plugin: Configure dimmer " + devid);
                zway.devices[1].instances[ dimmers[i].instance ].commandClasses[38].data.startChange.bind(function() {
                        wallswitch_dimmer_start ( devid, this.value);
                });
                zway.devices[1].instances[ dimmers[i].instance ].commandClasses[38].data.stopChange.bind(function() {
                    wallswitch_dimmer_stop( devid, this.value);
                 });
                zway.devices[1].instances[ dimmers[i].instance ] .commandClasses[32].data.level.bind(function() {
                    console.log("MQTT plugin: wallswitch #" + devid + ": binary " + this.value);
                    wallswitch_binary (devid, this.value);
                 });
                zway.devices[ dimmers[i].id ].instances[0].commandClasses[128].data.last.bind(function() {
                    battery_level_publish (devid, this.value);
                 });
        })(id); // tie device ID so it is referenced correctly from callback funcs
}


And when testing the following MQTT messages are seen:

home/zwave/Device22/wallswitch/binary on
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer increase
home/zwave/Device22/wallswitch/dimmer decrease
home/zwave/Device22/wallswitch/dimmer decrease
home/zwave/Device22/wallswitch/dimmer decrease
home/zwave/Device22/wallswitch/dimmer decrease
home/zwave/Device22/wallswitch/dimmer decrease
home/zwave/Device22/wallswitch/binary off
home/zwave/Device22/battery 96

It works! 🙂

Openhab configuration

We can then define the items in .items file..

Switch Kitchen_Light_Switch "Kitchen light switch" (GF_Kitchen)  {mqtt="<[mosquitto:home/zwave/Device19/wallswitch/binary:state:MAP(wallswitchFromMqtt.map)]"}
String Kitchen_Light_Dimmer "Kitchen light switch" (GF_Kitchen)  {mqtt="<[mosquitto:home/zwave/Device19/wallswitch/dimmer:state:MAP(wallswitchFromMqtt.map)]"}
Number Kitchen_Light_Switch_Battery "Kitchen light switch battery [%3f %]" (gBattery,GF_Kitchen) {mqtt="<[mosquitto:home/zwave/Device22/battery:state:default"}

And add appropriate rules in .rules file:

var Integer manualTimeOut = 1800

rule "Kitchen Light Switch"
        when
        Item Kitchen_Light_Switch received update
        then
{
    logInfo("Kitchen Light Switch", "button changed state ("+Kitchen_Light_Switch.state +")")
    if (Kitchen_Light_Switch.state==ON)
        {
        sendCommand(Kitchen_Light_Toggle, ON)  
        sendCommand(Kitchen_Light_CT_Dimm, Color_Temperature.state as DecimalType)
        if (KitchenTimer == null )
            {                       
            // create timer
            logInfo("Kitchen Light Switch", " creating timer for " + manualTimeOut + "sec" )
                        
            KitchenTimer = createTimer( now.plusSeconds(manualTimeOut) )
                [ 
                logInfo("Kitchen Light Switch", "timer expired, switching off ")
                sendCommand(Kitchen_Light_Toggle,OFF)       
                KitchenTimer=null
                ]               
            }
        else
            {
                logInfo("Kitchen Light Switch", " rescheduling timer" )
                KitchenTimer.reschedule(now.plusSeconds(manualTimeOut))
            }
        }
    else
        {
        sendCommand(Kitchen_Light_Toggle, OFF)                  
        if (KitchenTimer != null )
            KitchenTimer.cancel
        KitchenTimer=null
        }
}
end

rule "Kitchen Light Dimmer"
    when
        Item Kitchen_Light_Dimmer received update
    then
{
    logInfo("Kitchen Light Dimmer", "changed state ("+Kitchen_Light_Dimmer.state +")")
    if (Kitchen_Light_Dimmer.state=="INCREASE")
        {
        sendCommand(Kitchen_Light_Dimm, INCREASE)
        }
    else
        {
        sendCommand(Kitchen_Light_Dimm, DECREASE)
        }
}
end

Also add the transformation map wallswitchFromMqtt.map

on=ON
off=OFF
increase=INCREASE
decrease=DECREASE

With this configuration the setup works nicely, except that there's 500-600 millisecond delay between a button press and a change in lighting, most of which can be accounted to Z-Wave (delay inside WALLC-S, Z-Wave transceiver, decoding and Z-Way server). When our JSON binding callback is called, a MQTT message is sent nearly instantaneously and Philips Hue lights react also quite quickly. I have to look into it more deeply in the future whether there's any way to speed up it a bit.

Trouble in Z-Wave paradise: Decoupling Z-Wave from Openhab via MQTT

In the previous post I described how I successfully connected Everspring AN158 (a non-Z-Wave Plus) device to Openhab. However the Z-Wave Plus devices (Aeon Smart Switch and Z-Wave.me WALLC-S) haven’t been that cooperative. It seems that the SECURITY class used by Z-Wave Plus devices is not quite that well supported by Openhab Z-Wave engine. I know that the issue is with Openhab, since I can easily turn the smart switch on and off with Z-Way server GUI.

After configuring the devices with Z-Way server I shut it down (as it cannot co-exist with Openhab since they both use exclusively the /dev/ttyAMA0 device which RazBerry binds to). Then I browesed through the Openhab Z-Wave logs after pushing manually the on/off button on Aeon switch:

2015-07-07 20:40:22.092 [DEBUG] [eController$ZWaveReceiveThread:1528]- Receive Message = 01 11 00 49 84 14 0B 04 10 01 5E 86 72 98 56 EF 5A 82 7A
2015-07-07 20:40:22.096 [DEBUG] [eController$ZWaveReceiveThread:1452]- Receive queue ADD: Length=1
2015-07-07 20:40:22.096 [DEBUG] [b.z.i.protocol.ZWaveController:1210]- Receive queue TAKE: Length=0
2015-07-07 20:40:22.100 [DEBUG] [o.b.z.i.protocol.SerialMessage:233 ]- Assembled message buffer = 01 11 00 49 84 14 0B 04 10 01 5E 86 72 98 56 EF 5A 82 7A
2015-07-07 20:40:22.103 [DEBUG] [b.z.i.protocol.ZWaveController:1211]- Process Message = 01 11 00 49 84 14 0B 04 10 01 5E 86 72 98 56 EF 5A 82 7A
2015-07-07 20:40:22.106 [DEBUG] [b.z.i.protocol.ZWaveController:190 ]- Message: class = ApplicationUpdate (0x49), type = Request (0x00), payload = 84 14 0B 04 10 01 5E 86 72 98 56 EF 5A 82
2015-07-07 20:40:22.107 [DEBUG] [.ApplicationUpdateMessageClass:44  ]- NODE 20: Application update request. Node information received.
2015-07-07 20:40:22.109 [WARN ] [.o.b.z.i.p.c.ZWaveCommandClass:221 ]- NODE 20: Unsupported command class ZWAVE_PLUS_INFO
2015-07-07 20:40:22.111 [DEBUG] [.o.b.z.i.p.c.ZWaveCommandClass:224 ]- NODE 20: Creating new instance of command class VERSION
2015-07-07 20:40:22.114 [DEBUG] [.o.b.z.i.p.c.ZWaveCommandClass:224 ]- NODE 20: Creating new instance of command class MANUFACTURER_SPECIFIC
2015-07-07 20:40:22.116 [WARN ] [.o.b.z.i.p.c.ZWaveCommandClass:221 ]- NODE 20: Unsupported command class SECURITY
2015-07-07 20:40:22.118 [DEBUG] [.o.b.z.i.p.c.ZWaveCommandClass:224 ]- NODE 20: Creating new instance of command class CRC_16_ENCAP
2015-07-07 20:40:22.121 [DEBUG] [.z.i.p.s.ZWaveCommandProcessor:63  ]- Sent message Message: class = SendData (0x13), type = Request (0x00), payload = 15 01 00
2015-07-07 20:40:22.124 [DEBUG] [.z.i.p.s.ZWaveCommandProcessor:64  ]- Recv message Message: class = ApplicationUpdate (0x49), type = Request (0x00), payload = 84 14 0B 04 10 01 5E 86 72 98 56 EF 5A 82
2015-07-07 20:40:22.125 [DEBUG] [.z.i.p.s.ZWaveCommandProcessor:65  ]- Checking transaction complete: class=ApplicationUpdate, expected=SendData, cancelled=false
2015-07-07 20:40:23.053 [DEBUG] [eController$ZWaveReceiveThread:1528]- Receive Message = 01 08 00 04 00 14 02 98 40 3D
2015-07-07 20:40:23.056 [DEBUG] [eController$ZWaveReceiveThread:1452]- Receive queue ADD: Length=1
2015-07-07 20:40:23.056 [DEBUG] [b.z.i.protocol.ZWaveController:1210]- Receive queue TAKE: Length=0
2015-07-07 20:40:23.060 [DEBUG] [o.b.z.i.protocol.SerialMessage:233 ]- Assembled message buffer = 01 08 00 04 00 14 02 98 40 3D
2015-07-07 20:40:23.062 [DEBUG] [b.z.i.protocol.ZWaveController:1211]- Process Message = 01 08 00 04 00 14 02 98 40 3D
2015-07-07 20:40:23.064 [DEBUG] [b.z.i.protocol.ZWaveController:190 ]- Message: class = ApplicationCommandHandler (0x04), type = Request (0x00), payload = 00 14 02 98 40
2015-07-07 20:40:23.066 [DEBUG] [ApplicationCommandMessageClass:38  ]- NODE 20: Application Command Request (ALIVE:DYNAMIC_VALUES)
2015-07-07 20:40:23.068 [DEBUG] [ApplicationCommandMessageClass:56  ]- NODE 20: Incoming command class SECURITY
2015-07-07 20:40:23.069 [DEBUG] [ApplicationCommandMessageClass:62  ]- NODE 20: Command class SECURITY not found, trying to add it.
2015-07-07 20:40:23.071 [WARN ] [.o.b.z.i.p.c.ZWaveCommandClass:221 ]- NODE 20: Unsupported command class SECURITY
2015-07-07 20:40:23.073 [ERROR] [ApplicationCommandMessageClass:75  ]- NODE 20: Unsupported command class SECURITY (0x98)

Also similar error messages can be seen with WALLC-S when I push one of its buttons:

2015-07-07 20:29:04.626 [DEBUG] [eController$ZWaveReceiveThread:1528]- Receive Message = 01 08 00 04 00 05 02 98 40 2C
2015-07-07 20:29:04.629 [DEBUG] [eController$ZWaveReceiveThread:1452]- Receive queue ADD: Length=1
2015-07-07 20:29:04.630 [DEBUG] [b.z.i.protocol.ZWaveController:1210]- Receive queue TAKE: Length=0
2015-07-07 20:29:04.633 [DEBUG] [o.b.z.i.protocol.SerialMessage:233 ]- Assembled message buffer = 01 08 00 04 00 05 02 98 40 2C
2015-07-07 20:29:04.635 [DEBUG] [b.z.i.protocol.ZWaveController:1211]- Process Message = 01 08 00 04 00 05 02 98 40 2C
2015-07-07 20:29:04.637 [DEBUG] [b.z.i.protocol.ZWaveController:190 ]- Message: class = ApplicationCommandHandler (0x04), type = Request (0x00), payload = 00 05 02 98 40
2015-07-07 20:29:04.638 [DEBUG] [ApplicationCommandMessageClass:38  ]- NODE 5: Application Command Request (ALIVE:PING)
2015-07-07 20:29:04.640 [DEBUG] [ApplicationCommandMessageClass:56  ]- NODE 5: Incoming command class SECURITY
2015-07-07 20:29:04.641 [DEBUG] [ApplicationCommandMessageClass:62  ]- NODE 5: Command class SECURITY not found, trying to add it.
2015-07-07 20:29:04.643 [WARN ] [.o.b.z.i.p.c.ZWaveCommandClass:221 ]- NODE 5: Unsupported command class SECURITY
2015-07-07 20:29:04.644 [ERROR] [ApplicationCommandMessageClass:75  ]- NODE 5: Unsupported command class SECURITY (0x98)

Documentation regarding Z-Wave Plus security is sparse, but OpenZWave (another z-wave stack NOT used by Openhab) has this very nice and informative page.

So, maybe it’s an issue with Z-Way server setting up a Network Key to manage encrypted communication with Plus devices but now Openhab doesn’t know the Network key and fails?
In /opt/z-way-server/config-zddx/ directory is a file named something like cb2ce85ed-DevicesData.xml that contains an entry such as:

   <data name="networkKey" invalidateTime="1435679337" updateTime="1435679338" type="binary" value="[ 35 c3 34 b2 44 e3 cf ca 23 db b1 3d 15 79 07 12 ]"/>

Bingo! Now, how to configure Openhab with it?

I browsed through the configuration files and their GitHub repository, but didn’t find any real references to implementation of Security Class. Quick search on their Google group provided a discussion about it. It seems (as of July 2015) the Z-Wave Security is still not supported. That’s a bummer.. Now, I could start using OpenZWave since it has preliminary support for it, but there’s no way to use it with Openhab, but instead I would be forced to switch to Domotiga, Domoticz, Jeedom or other system using OpenZWave. Since Z-Wave documentation is behind NDA and open-source implementation requires reverse-engineering it, I wonder why there are two different camps re-inventing the wheel (OpenZWave and Z-Wave stack of Openhab). For historical reasons? Openhab itself is a already a huge monolith, so the reason why they have decided to split the effort and code their own Z-Wave stack is just beyond me..

Anyway, to use Z-Wave Plus devices with Openhab there’s another way..

MQTT cavarly to the rescue!

From a DIY perspective, it’s best to use separate components that each do their own job very well instead of relying on a monolith that tries to do everything on its own. I decided to decouple Z-Wave from Openhab using MQTT, but I wasn’t sure which way to go. There’s one attempt with OpenZWave and MQTT bridge, but without any documentation and it has only one commit 6 months ago. Since I had already set up Z-Way server, I decided to do some hacking with it.

By browsing Z-Way API documentation one can see that the embedded web server offers JSON API, which you can use to configure Z-Wave settings, read device data and also control devices. For example to turn on and off the wall switch (here Z-Wave device #20), these simple HTTP requests can be issued with a browser:

http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].Basic.Set(1)
http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].Basic.Set(0)

Here we use the Basic command class to control the device. It’s little bit tricky to find out the exact JSON tree to read and control each device, but you can try to mesh the information seen on the GUI of Z-Way server with the Z-Way API doc, or you could decipher the JSON tree itself. You can read all the available command classes with command

http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].commandClasses

In my case the Aeon Smart Switch supports following command classes:

  • Basic (32)
  • SwitchBinary (37)
  • SwitchAll (39)
  • SceneActivation (43)
  • SceneActuatorConf (44)
  • Meter (50)
  • CRC16 (86)
  • AssociationGroupInformation (89)
  • ZWavePlusInfo (94)
  • Configuration (112)
  • ManufacturerSpecific (114)
  • PowerLevel (115)
  • FirmwareUpdate (122)
  • Association (133)
  • Version (134)
  • Security (152)
  • DeviceResetLocally (90)
  • Hail (130)

Here the SwitchBinary and Meter classes seem most interesting. It seems that Basic class is just re-mapped internally by the switch to SwitchBinary, since all Z-Wave devices must understand Basic class to facilitate interoperability between dumb sensors and actuators. Also you can reference the class by the number instead of name. Hence, all these four commands work equally:

http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].Basic.Set(1)
http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].SwitchBinary.Set(1)
http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].commandClasses[32].Set(1)
http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].commandClasses[37].Set(1)

mqttwarn – a swiss knife of MQTT

Now, how to best translate MQTT messages into JSON HTTP POSTs? There’s mqttwarn, an excellent piece of python software (on Github here), that not only does this, but can also convert MQTT messages into notifications on your cell phone (using Pushover or Instapush), send e-mail, post on your Twitter account, send e-mail, transfer your sensor data over to your remote EmonCMS server and tons more!

To install and configure mqttwarn, just follow the instructions at the end of the (very long) GitHub project description. Then, edit the mqttwarn.ini:

First add the http service provider:

; name the service providers you will be using.
launch   = file, log, http

Then configure the provider. Here the HTTP URL is modified with the MQTT message payload in following way:

[config:http]
timeout = 60

targets = {
                #method     #URL               # query params or None          # list auth
  'dev20set'    : [ "post", "http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].Basic.Set({payload})", None, None ],
  'dev21set'    : [ "post", "http://192.168.1.80:8083/ZWaveAPI/Run/devices[21].instances[0].Basic.Set({payload})", None, None ]
  }

Finally we add a list of MQTT messages that trigger the launch of the HTTP provider:

[#]
targets = {
        'home/zwave/Device20/switch/set' : 'http:dev20set',
        'home/zwave/Device21/switch/set' : 'http:dev21set'
        }

After you start mqttwarn, you can test it by sending MQTT messages like this:

mosquitto_pub -t home/zwave/Device20/switch/set -m 1

If you successfully installed mqttwarn you should now have all the required python dependencies set up (such as Paho MQTT Python module). Note that I tested few other python bindings and I remember having first some trouble connecting to the Mosquitto server, but the culprit was an old version of Mosquitto. Since the version in Raspberry Pi repositories is ancient, you should download it straight from Mosquittos repository (instructions here).

Supervisor – the big brother of small scripts

You can add the mqttwarn into your server init scripts, but I prefer Supervisor to handle all these small scripts, since it allows the administrator to monitor their status, see their output log and stop/start/restart them, all combined in a very nice web server UI.

To install it on Raspberry Pi, first install setuptools

wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python

Then install supervisor via easy_install:

easy_install supervisor

Update the /etc/supervisord.conf and check the http port and add username:password if needed. Also double-check that separate script config files are included:

[include]
files = /etc/supervisord.d/*.ini

Create /etc/supervisord.d/mqttwarn.ini and check that the mqttwarn installation directory and config files are referred correctly:

[program:mqttwarn]
directory = /home/pi/services/mqttwarn
command = /home/pi/services/mqttwarn/mqttwarn.py
user = pi
environment= MQTTWARNINI="/home/pi/services/mqttwarn/mqttwarn.ini"
stdout_logfile = /tmp/mqttwarn.log

Finally restart the supervisord

/etc/init.d/supervisor restart

And browse to http://192.168.1.80:9001/ and you should see the nice web GUI.

supervisord

From Z-Way to MQTT

We have now just configured one-way communication from MQTT to Z-Wave server. To be able for us to receive messages from various Z-Way devices, we must hack the Z-Way server Javascript a bit and bind to the JSON tree changes. I found about this trick from this EventGhost forum discussion and modified the scripts posted there (originals by Walter Krambring)

Edit /etc/opt/z-way-server/automation/main.js (depending on your installation directory) and add this snippet to the end:

var mqtt_host = '192.168.1.80';
var mqtt_port = 1883;
var mqtt_topic_prefix = 'home/zwave/';

// Here the 20 and 21 are hardcoded Z-Wave device ID's for wall plugs/power switches. Change them accordingly to your setup
var powerswitches = [20, 21];

function publish_mqtt (topic, key) {
    try {
        system(
            "mosquitto_pub",
            "-h",
            mqtt_host,
            "-p",
            mqtt_port,
            "-t",
            mqtt_topic_prefix + topic,
            "-m",
            key
        );
        return;
    } catch(err) {
        debugPrint("Failed to execute script system call: " + err);
    }
}

function switch_binary (device, instance, theValue) {
    console.log("MQTT plugin: dev#" + device + " (binary switch): " + theValue)
    state = 'on';
    key = 255;
    if (theValue == false){
        state = 'off';
        key = 0;
    }
    eventString = 'Device' + device + "/switch";
    publish_mqtt(eventString, state);
}

function switch_binary_meter (device, instance, theValue) {
    console.log("MQTT plugin: dev#" + device + " (binary switch meter): " + theValue)
    eventString = 'Device' + device + "/meter";
    publish_mqtt(eventString, theValue);
}

for (var i=0; i < powerswitches.length; i++) {

        var id = powerswitches[i];
        (function(devid) {
                console.log("MQTT plugin: Configure power switch  " + devid);
                zway.devices[ powerswitches[i] ].instances[0].SwitchBinary.data.level.bind(function() {
                        switch_binary (id, 0, this.value);
                });
                zway.devices[ powerswitches[i] ].instances[0].Meter.data[2].val.bind(function() {
                    switch_binary_meter (id, 0, this.value);
                 });
        })(id); // tie device ID so it is referenced correctly from callback funcs

}

This code will bind to changes in the Watt meter and on/off status of my Aeon and Evergreen wall switches and send MQTT message using external python script every time the data changes. The syntax for binding uses exactly the same data format as the Z-Way server JSON API, so we can use again the web interface to find the sub-item to bind with. However finding the correct item will indeed be bit like searching for a needle in a haystack if we use only the JSON tree. Instead of sifting through the giant data tree, we can use the Expert UI to find out clues where the interesting data is. For example in the case of Aeon switch we are interested in the Meter service:
z-way
Here we can see the scaleString of entry #2 is 'W' so .data2 should contain the watt meter reading. We confirm this by plugging in a known load (here 14W) and viewing the JSON tree:

http://192.168.1.80:8083/ZWaveAPI/Run/devices[20].instances[0].Meter.data[2]
returns
{"invalidateTime":1436389382,"updateTime":1436389383,"type":"empty","value":null,
"sensorType":{"invalidateTime":1435686498,"updateTime":1435686499,"type":"int","value":1},
"sensorTypeString":{"invalidateTime":1435686498,"updateTime":1435686499,"type":"string","value":"Electric"},
"val":{"invalidateTime":1435686498,"updateTime":1436389383,"type":"float","value":14.384},
"scale":{"invalidateTime":1435686498,"updateTime":1435686499,"type":"int","value":2},
"scaleString":{"invalidateTime":1435686498,"updateTime":1435686499,"type":"string","value":"W"},
"ratetype":{"invalidateTime":1435686498,"updateTime":1436389383,"type":"int","value":1},
"delta":{"invalidateTime":1435686498,"updateTime":1436389383,"type":"int","value":0},
"previous":{"invalidateTime":1435686498,"updateTime":1436389383,"type":"float","value":0}}

The '14.384' stored in 'val' sub-item looks awfully lot like our load. Thus the correct binding function will be

zway.devices[20].instances[0].Meter.data[2].val.bind

as shown in the example code above.

We must also allow the Javascript to invoke mosquitto_pub by adding .syscommands file to the same directory where main.js resides:

mosquitto_pub 

Openhab binding

Finally you can replace the z-wave binding with MQTT ones in the .items file:

Switch Kitchen_Coffee_Switch "Coffee machine" {mqtt=">[mosquitto:home/zwave/Device21/switch/set:command:*:MAP(switchToMqtt.map)]"} 
Number Kitchen_Coffee_Watts "Coffee machine power consumption [%.1f W]" {mqtt="<[mosquitto:home/zwave/Device21/meter:state:default]"}

Switch Livingroom_Power1_Switch "Living room power #1" {mqtt=">[mosquitto:home/zwave/Device20/switch/set:command:*:MAP(switchToMqtt.map)]"} 
Number Livingroom_Power1_Watts "Living room power #1 consumption [%.1f W]" {mqtt="<[mosquitto:home/zwave/Device20/meter:state:default]"}

We must also map the ON/OFF states to 1/0's that are understood by JSON API. Create configurations/transform/SwitchToMqtt.map:

ON=1
OFF=0

... aaand we're done! That was easy, wasn't it? 😀

Wall plug mania

To prevent my coffee pot from being burned every other weekday I had to be able to control wall outlets remotely and automatically via Openhab. For this I looked into into few possible solutions:

  • Build those outlets myself by modifying bunch of Kill-A-Watts, just like what Felix@Moteino Labs has done here with his WattMote or Mike on his Micromania Blog. I must say I was tempted to try experimenting with those, but since I eventually want quite a many of them, assembling those by myself seemed more like a chore. Also it is against the local Electrical Code to make permanent high voltage installations in here without proper license. Even though they are plug-in accessories, let’s be honest, they ARE permanent if one keeps them on 24/7. And besides, I wouldn’t want to sleep in a house full of DIY mains appliances – My sleeping disorder is bad enough as it is 🙂
Few pre-home automation era wall plugs. Don't these just scream for wireless connectivity!

Few pre-home automation era wall plugs. Don’t these just scream for wireless connectivity!

  • There’s a whole family of cheap 433 Mhz sensors, wall sockets/plug-ins, remote controls, doorbells and whatnot. Nexa is one of the manufacturers and their products are sold even here at local Clas Ohlsons. One could then buy for example Tellstick Duo or their more basic Tellstick USB stick, and connect it with RaspBerry Pi. Also Openhab supports Tellsticks natively. For complete device compatibility, see a list here. There’s also Tellstick Net, which is a ethernet connected stand-alone hub that doesn’t require another computer. I do like that modularity aspect, but the down-side is that it connects to their own Telldus Live! service (yuck!) and thus requires constant internet connection (another yuck!). Luckily there’s now an unofficial firmware available which removes that requirement.

    To my disappointment none of these 433 Mhz wall plug-ins (to my knowledge) are able to send their status or output power consumption to the hub i.e. you can only switch them on/off. Now that’s a bummer, since the use-case for turning off the coffee maker after some timeout period explicitly requires power consumption to be measured all the time (how else could the system know when the coffee maker has been manually turned on?)

    However the most concerning thing about these devices is that the security is a joke: all the wireless messages are transmitted without encryption so the attacker is able to just listen to the transmission outside your house and then replay the messages. Anyone still remember Wardriving? I can almost imagine script-kiddies driving around the city, looking for these devices and annoying the hell out of people by switching them on and off 🙂 In fact, there’s an interesting thesis written by students of Linkoping University that examines the security aspect of Tellstick Net. While it mainly concentrates on threats from (wired) network perspective and examines scenarios involving the Telldus Live! service, it’s interesting read. Also what’s funny is that they mention the wireless security only in one paragraph since the security flaw is so obvious they didn’t need the feel to research it more deeply 🙂

  • Wi-Fi 2.4Ghz remote wall plugs are available from D-Link, Belkin and Ankuoo (rebranded Netwjork here) just to name a few. The problem with these is that these look quite nice on brochures but actual user experience has been ranging from so-so to just horrible according to customer reviews on Amazon and other sites. The main annoyances have been flaky connectivity, pairing problems with WiFi router as well as 2.4 Ghz band collisions. I decided to opt out of this mess.

  • Finally there’s Z-Wave, a technology with a family of products that even remotely (pun intended) seemed usable. Using 868 Mhz band here in Europe (908 Mhz in the US) and providing encryption as well as better low-power support (compared to Wi-Fi products), this seemed the best pick out of options mentioned above. The only obvious down-side with Z-Wave devices is that they are quite expensive! Be it a simple flood switch, motion sensor or a wall switch, they all seem to cost a minimum of 40-50 euros / sensor. Since I wasn’t going to lock myself with only Z-Wave by using a proprietary hub, this wouldn’t be a problem. I can begin with wall plugs and then add more devices if needed should their prices come down.

Z-Wave jungle

For wall plugs there are quite many options available just to name a few:

In the end, they all seem quite alike, supporting power measurements beside remote switching. There’s also a new updated standard called Z-Wave Plus (another name for ‘Gen 5’ variety of Z-Wave products, such as the Aeon Smart Switch.)

According to the specs the Z-Wave Plus Features:

  • Significant increased range – up to 150m (clear air)
  • 50% improvement in battery life
  • 250% more bandwidth
  • Three F channels for improved noise immunity and higher bandwidth
  • New Plug-n-Play Network-wide Inclusion feature
  • Improved self-healing and fault tolerance with Explorer Frame feature
  • Standardised method for Over the Air firmware updates (OTA)
  • Improved product information capture for product certification database

This all looks good on paper, but there has been conflicting reports of success with Z-Wave Plus devices and Openhab and other DIY systems, so I decided to pick one older wall plug (AN158 by Everspring) without the Plus support as well as the newer Aeon Smart Switch Gen with Plus capability, both which are readily available here.

To enable communication between Z-Wave devices one needs a main controller that can include and exclude devices to and from the Z-Wave network as well as do bunch of other maintenance and configuration work in the network. When it comes to choosing the Z-Wave controller it all boils down to 2 options: Razberry and Aeon Labs Z-Stick Series 2. Both support Z-Wave Plus devices, but whereas the Z-Stick dangles outside Raspberry and occupies one of the USB slots, Razberry connects to Pis GPIO connector and slides nicely inside the enclosure. I chose the Razberry which seemed a nice idea at that time, but in hindsight Z-Stick maybe would have been better choice should I ever want to migrate away from Raspberry.

In a bit of shopping frenzy I bought also 2 wall switches WALLC_S Secure Wall Switch by Z-Wave.me, since there always will be some occasions when you cannot rely on automated scripts but want to do some manual switching instead. Even though these kind of switches could be easily built using a Moteino and 3.3V coin cell battery, I clearly lack the skill at this stage to create nice enclosures and thus didn’t want to stick any of my frankensteinos (Frankenmotes?) on walls or other visible surfaces 😀

First batch of Z-Wave devices to be tested

First batch of Z-Wave devices to be tested

Connecting with Openhab

For configuring Razberry to be used with Openhab I followed instructions from Home Automation For Geeks. I first tried HAbmin but I didn’t have any luck getting Z-Wave devices detected nor included in the network, so I resorted to the Z-Way server from Z-Wave.me (same manufacturer as Razberry). After fumbling around with the not-so-intuitive settings, all devices were finally set up nicely (or so I thought.. See the next post). After configuring devices the Z-Way server has to be shut down, since it cannot use Razberry simultaneously with Openhab.

First attempt was to use AN158 as coffee maker switch in kitchen. As before, items are defined in .items file (here Z-Wave device #3 is AN158)

Switch Kitchen_Coffee_Switch "Coffee machine" (GF_Kitchen) {zwave="3:command=switch_binary"} 
Number Kitchen_Coffee_Watts "Coffee machine power consumption [%.1f W]" (GF_Kitchen,GF_Energy) { zwave="3:command=meter" }

Then a rule for switching it off after 50 minutes can be set in coffee.rules. It automatically will detect when it has been switched on (consumption goes over pre-defined threshold value) and starts the timer.
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*

var Integer coffee_watts_threshold = 5
var Integer coffee_timeout = 50
var Timer coffee_timer = null

rule "Coffee switch off"
    when
        Item Kitchen_Coffee_Watts received update
        then
        {
        logInfo("coffee switch", "consumption " + Kitchen_Coffee_Watts.state + " watts. " )         

        if ( ((Kitchen_Coffee_Watts.state as DecimalType).intValue() > coffee_watts_threshold) && (coffee_timer == null) )
            {
            logInfo("coffee switch", "Coffee on. consumption " + Kitchen_Coffee_Watts.state + " watts. Setting switch off timer to " + coffee_timeout + " minutes." )
            coffee_timer = createTimer(now.plusMinutes(coffee_timeout)) [|
                if ((Kitchen_Coffee_Watts.state as DecimalType).intValue() > coffee_watts_threshold)
                    {
                    logInfo("coffee switch", "coffee maker still on after timeout period. Switching off.. " )   
                    sendCommand(Kitchen_Coffee_Switch,OFF)
                    }
                    coffee_timer=null
                ]
            }
        else if ( (Kitchen_Coffee_Watts.state < coffee_watts_threshold) && (coffee_timer != null) ) 
            {
            logInfo("coffee switch", "Coffee off. Canceling switch off timer" )
            coffee_timer.cancel()
            coffee_timer=null
            }
        }
    end

To my surprise, it started to work out-of-the-box without any additional head scratching. No more burned coffee pots 🙂