Setting sails with Docker: OpenHAB on Synology

My weekend project has been with Docker. Unless you have been living in a barrel in the middle of Sahara, you might have heard of it. For those who haven’t, please DO check it out – it’s almost the best thing since sliced bread. Up until now, I really hadn’t had time nor a use-case where Docker containers would be useful, but recently few incidents set the ball in motion and I decided to jump in the Docker bandwagon.

First was the trouble with Raspberry Pi SD cards. I thought I would have spared from the rampant file system corruption when I bought a supposedly compatible and reliable Kingston SD card and then made sure that I don’t EVER turn it off without explicit shutdown command from the command line. Also Openhab and Z-Way servers were configured not to trash the SD card with excessive logging (by moving the /var/log to memory using tmpfs). Still, I managed somehow to corrupt the file system on three separate occasions. It was not that funny to discover after rebooting that connections to outside servers were crippled. After some head-scratching I found out that /lib/libresolv.so had just vanished! After re-installing and re-configuring the whole system again it wouldn’t reboot anymore. The culprit was this time missing /etc/inittab … You can guess my frustration. The corruption may have been caused by the shutdown scripts hanging before the root filesystem was un-mounted and causing data corruption when I pulled the plug. Just a hypothesis – I haven’t had trouble after I started to shutdown RPi directly from the console while viewing the logs with a monitor hooked up to the RPi, making sure the system really is halted before switching it off. Solution wise, there are of course ways to make the file system read-only, but the whole incident made me think if I should migrate from RPi to something more robust.

I have a Synology 1812+ 8-bay NAS that serves as a local network provider for music, movies and personal files, as well as backup target for various devices (such as my desktop computer and laptop). I’ve once tried hacking with it, but I remember having trouble installing even such basic stuff as multi-threaded Perl on Synology. Exercises in trying to compile anything more complex than “Hello World” have been getting resistance in the form of dozens missing library dependencies. The custom Linux distro that Synology uses is quite limited, and I wasn’t prepared to brute force it open with the possibility of breaking stuff and data loss lingering in my mind. Just wasn’t worth the fight at that time.

It all changed when I heard the news about the new Synology DSM 5.2 having Docker on its application center as a turn-key solution. Now we’re getting somewhere!

Preparing the Synology

First I needed to update to DSM 5.2. That wasn’t exactly straightforward, since for some reason the update function of web based DSM didn’t work (“Connection failed. Please check you network connection.”) There was nothing wrong with my network settings and this was a known problem with some versions of DSM 4.2. Nor did the instructions on how to update it manually via shell work. My last resort was to boot the Synology to network update mode and only after then could the firmware be updated to 5.2 from desktop computer with pre-downloaded DSM file. Obviously, backups were made of all important files before that.

After that I enabled the SSH shell (it’s there on DSM’s Control Panel / Terminal & SNMP window), logged in and installed bootstrap script to enable ipkg in order to install vim, bash and other more familiar unix tools.

I use 3 * 3 TB Western Digital drives in RAID5 configuration to serve most of my files, but I had an extra 120gb SSD drive laying around that I decided to dedicate to Docker, since there’s never enough speed when moving around these few hundred MB containers. Since containers itself are easily downloadable and disposable, I don’t need to worry about backups so much – only these small data volumes that contain user data and configuration files need to be backupped to the main RAID volume with a regular cron script, so I could just run Docker from single disk configuration.

The Docker can be installed from the DSMs application manager, and even though it’s not the newest version (1.6.2 on Synology and 1.7.0 on Github), there doesn’t seem to be big changes according to changelog, so I took the route of least resistance and used app manager to install Docker. BTW, one nice tutorial for Docker on Synology can be found here, showing how to install GitLab and Jenkins on Synology as Docker containers. I personally tried GitLab but it is a bit memory hog (taking several hundred megabytes of the 1 gig memory on 1812+), so I chose to use the more light-weight Gogs. Also it can be found as a Docker container (my pick was the one by codeskyblue).

Installing Openhab Docker container

I first tried the most popular Openhab container from tdecker, but found out that there was this one bug with managing addons (though easily fixed), but there also was no easy way to turn on debugging and logging, so I customized my own Docker container (wetware/openhab on Docker Hub, wetwarelabs/docker-openhab on GitHub). Also JDK 1.7 was replaced with JRE 1.8 for slightly smaller images and faster execution.

The container can be downloaded with command:

docker pull wetware/openhab

Directories for config files and logs are created (here on my new SSD volume):

mkdir /volume3/openhab
mkdir /volume3/openhab/configurations
mkdir /volume3/openhab/logs

Then it is easy to map the /volume3/openhab as a new Samba network share on a desktop computer if one likes to remotely edit the configuration files or follow logs easily (I did that previously on Raspberry too).

Instrunctions for configuring and running the container can be found on both GitHub and Docker hub pages. You could then either copy your existing Openhab configuration (from Raspberry etc) to configurations directory, or run Openhab in a demo mode.

After configuring addons and timezone, Openhab can be run with command:

docker run -d -p 8080:8080 -p 9001:9001 -v /volume3/openhab/configurations/:/etc/openhab -v /volume3/openhab/logs:/opt/openhab/logs wetware/openhab

This maps configuration and logging directory from the host to the container as well as allows access to Supervisor (in port 9001) and Openhab web page (in port 8080).

If you then want to monitor Openhab running status or switch between normal and debug mode, you can do it from Supervisor web page (http://your.host:9001).

Aftermath

Migrating Openhab from Raspberry Pi to Synology has been quite pain-free, and these past few days it has been running happily inside the container. I also think that the extra CPU power doesn’t hurt running the complex Java beast that Openhab is, either. Of course Mosquitto and mqttwarn are still running on Raspberry, but I think I’ll try converting them to Docker containers as well in the near future. That would leave the Z-Way server and Razberry the sole inhabitants on my RasPi, but I think there might be workarounds to get them running on Synology too..!

Anyway, I hope you too try out the Openhab container and let me hear if you have any issues, regardless of whether you have Synology or not!

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? 😀