Wednesday, November 5, 2014

ZWay in C++: initialization

I have been trying to wire ZWave door sensor to ZWave power switch. It took four weeks for me to get it working in C++ as I wanted. I learned several things in hard way but it wasn't all enjoyable. lol

This article is to show how to start ZWay system running in C++. One of the advantages for using C++ instead of ZWay JavaScript based system is that it gives me more control at system level.

A few days ago I posted a way to access ZWay information via HTTP protocol in Shell Script. But later I found that it doesn't give me the full control I wanted so I continued C++ approach. This post assumes that you installed ZWay on your Raspberry Pi. The instruction of how to install can be found from ZWave.me webpage.

1
2
3
4
5
6
7
8
// stdafx.h written by Jae Hyuk Kwak
#include <stdexcept>    // runtime_error
#include <iostream>     // cerr, cout
#include <thread>       // this_thread::sleep_for
#include <ZWayLib.h>
#include <ZDataPublic.h>
#include <ZLogging.h>
using namespace std;
1
2
3
4
5
6
7
8
9
// config.hpp written by Jae Hyuk Kwak
namespace Configuration
{
    // check config.xml for the device path
    ZWCSTR devPath = ZSTR( "/dev/ttyAMA0" );
    ZWCSTR configPath = ZSTR( "/opt/z-way-server/config" );
    ZWCSTR translationsPath = ZSTR( "/opt/z-way-server/translations" );
    ZWCSTR ZDDXPath = ZSTR( "/opt/z-way-server/ZDDX" );
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// myzway.cpp written by Jae Hyuk Kwak
#include "stdafx.h"
#include "MyZWay.hpp"
#include "config.hpp"
using namespace Configuration;
using namespace MyZWayNS;
int main( int argc, char *argv[] )
{
    Init myZWay( devPath, configPath, translationsPath, ZDDXPath );
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Makefile written by Jae Hyuk Kwak
CC=g++-4.7
LD_LIBRARY_PATH=/opt/z-way-server/libs
CFLAGS=-Wall -g -std=c++11 -I/opt/z-way-server/libzway-dev/ -L/opt/z-way-server/libs

all: myzway

myzway: *.hpp myzway.cpp stdafx.h.gch
    $(CC) $(CFLAGS) -o myzway myzway.cpp -lzway -lxml2 -larchive -lssl -Wl,-rpath=$(LD_LIBRARY_PATH)

stdafx.h.gch: stdafx.h
    $(CC) $(CFLAGS) -c stdafx.h

clean:
    rm stdafx.h.gch myzway
The source code above shows how to setup the basic environment. It doesn't do anything but executing the constructor of MyZWayInit class and the destructor.

Note that Makefile has an option, "-Wl,-rpath,$(LD_LIBRARY_PATH)" and LD_LIBRARY_PATH is "/opt/z-way-server/libs". This is to link the runtime library at compile time. Without this option, you will need to change the environment variable, LD_LIBRARY_PATH, before every time you want to launch the program. You can do that by typing in "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/z-way-server/libs". But again, I found it easier to just link it at compile time.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// MyZWay.hpp written by Jae Hyuk Kwak
namespace MyZWayNS
{
    static const uint32_t idleTimeout = 60u; // in seconds
    static const bool enableDebug = false;

    void WaitUntilAvailable( ZWay zway );
    runtime_error critical( ZWay zway, const char *msg, ZWError r );

    class Init
    {
        ZWay zway_;
    public:
        Init( ZWCSTR devPath, ZWCSTR configPath, ZWCSTR translationsPath, ZWCSTR ZDDXPath )
        {
            memset( &zway_, 0, sizeof( ZWay ) );    // required
            if ( ZWError r = zway_init( &zway_, devPath, configPath, translationsPath, ZDDXPath, NULL, enableDebug ? Debug : Critical ) )
                throw critical( zway_, "zway_init() failed.", r );
            if ( ZWError r = zway_start( zway_, NULL ) ) throw critical( zway_, "zway_start() failed.", r );
            if ( ZWError r = zway_discover( zway_ ) ) throw critical( zway_, "zway_discover() failed.", r );
            WaitUntilAvailable( zway_ );
        }
        ~Init()
        {
            if ( ZWError r = zway_stop( zway_ ) ) throw critical( zway_, "zway_stop() failed.", r );
            zway_terminate( &zway_ );
        }
        ZWay native() { return zway_; }
    };

    void WaitUntilAvailable( ZWay zway )
    {
        if ( !zway_is_running( zway ) ) throw runtime_error( "zway is not running." );
        for ( uint32_t idleCounter = 0; idleCounter < idleTimeout; ++idleCounter )
        {
            if ( zway_is_idle( zway ) ) return;
            this_thread::sleep_for( chrono::seconds( 1 ) );
        }
        throw runtime_error( "zway is too busy" );
    }

    runtime_error critical( ZWay zway, const char *msg, ZWError r )
    {
        zway_log_error( zway, Critical, msg, r );
        return runtime_error( msg );
    }
}
The class, MyZWayInit, shows how to initiate the ZWay server and how to shutdown. It also shows how to handle the error message with a function, "critical". ZWay service follows the steps:
  1. zway_init
  2. zway_start
  3. zway_discover
  4. [do whatever we want]
  5. zway_stop
  6. zway_terminate
The method, "WaitUntilAvailable", is to wait until ZWay system is available. I am not sure about when the function, zway_is_idle, returns false. One case I found is that when the ZWay system is locked by a thread, it seems to return false.

When you execute the program, it may give you an error like the screenshot above:
Failed to exclusively lock device: Resource temporarily unavailable
zway_start failed: Can not open port (-20)

Probably it is because there is another process already running and using the ZWay device. By default, z-way-server starts at booting time. You can manually stop it as the screenshot shows. To permanently disable the service you can type in "sudo update-rc.d z-way-server disable".

This program doesn't to anything but starting the zway server and shut it down. I will show how to access data and send command later.

1 comment:

  1. Hello,

    Actually i work on the same project and i try your program but when i launch Makefile i have an error
    "stdafx.h:6:25: fatal error: ZDataPublic.h: No such file or directory
    compilation terminated.".

    Is it possible to tell me the version of libzway you use cause i dont find ZDataPublic.h ^^ ?

    Thanks in advance.

    ReplyDelete

About Me

My photo
Tomorrow may not come, so I want to do my best now.