This program is based on a ZWave binary power switch I bought but it shouldn't be hard to apply the same to any other ZWave devices.
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 | // myzway.cpp written by Jae Hyuk Kwak #include "stdafx.h" #include "WaitForSignal.hpp" #include "MyZWay.hpp" #include "MyZWayCommandEnum.hpp" #include "MyZWayGet.hpp" #include "MyZWaySend.hpp" #include "config.hpp" using namespace Configuration; using namespace MyZWayNS; int main( int argc, char *argv[] ) { Init zway( devPath, configPath, translationsPath, ZDDXPath ); Device raz( &zway, 1 ); Device sensor( &zway, 2 ); Device power( &zway, 3 ); Device repeater( &zway, 4 ); cout << "1: " << Get< string >( &raz, "deviceTypeString" ) << endl; cout << "2: " << Get< string >( &sensor, "deviceTypeString" ) << endl; cout << "3: " << Get< string >( &power, "deviceTypeString" ) << endl; cout << "4: " << Get< string >( &repeater, "deviceTypeString" ) << endl; Instance power0( &power, 0 ); const bool before = Get< bool >( &power0, SWITCH_BINARY_GET, "level" ); cout << "Power of device 3 is " << ( before ? "on" : "off" ) << endl; Send< SWITCH_BINARY_SET >( &power0, true ); const bool after = Get< bool >( &power0, SWITCH_BINARY_GET, "level" ); cout << "Power of device 3 is " << ( after ? "on" : "off" ) << endl; return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // MyZWayCommandEnum.hpp written by Jae Hyuk Kwak namespace MyZWayNS { enum CommandEnum { SET_BIT_MASK = 0X100, REMOVE_BIT_MASK = 0X200, BASIC_GET = ( 0X20 ), BASIC_SET = ( BASIC_GET | SET_BIT_MASK ), SWITCH_BINARY_GET = ( 0X25 ), SWITCH_BINARY_SET = ( SWITCH_BINARY_GET | SET_BIT_MASK ), SENSOR_BINARY_GET = ( 0X30 ), // there is no set counter-part ASSOCIATION_REMOVE = ( 0X85 | REMOVE_BIT_MASK ), }; } |
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | // MyZWaySend.hpp written by Jae Hyuk Kwak namespace MyZWayNS { namespace ImplementationNS { struct CallbackUser // Callback Userdata { Instance * const inst; // include "MyZWayGet.hpp" WaitForSignal * const wcb; // include "WaitForSignal.hpp" public: CallbackUser( Instance *inst, WaitForSignal *wcb ) : inst( inst ), wcb( wcb ) {} }; template< bool succeed > void Callback( ZWay zway, ZWBYTE, void *userData ) { if ( succeed ) cout << "Send succeed." << endl; else cerr << "Send failed." << endl; static_cast< CallbackUser * >( userData )->wcb->WaitIsOver(); } template< typename ZWayFuncType, typename... ArgTypes > void TSend( CallbackUser &so, ZWayFuncType zwayFunc, ArgTypes... args ) { zwayFunc( so.inst->zway, so.inst->deviceId, so.inst->instanceId, args..., Callback< true >, Callback< false >, static_cast< void * >( &so ) ); } template< CommandEnum, typename... ArgTypes > void Send( CallbackUser &, ArgTypes... args ); template<> void Send< BASIC_GET >( CallbackUser &so ) { TSend( so, zway_cc_basic_get ); } template<> void Send< BASIC_SET >( CallbackUser &so, bool value ) { TSend( so, zway_cc_basic_set, value ? 1 : 0 ); } template<> void Send< SWITCH_BINARY_GET >( CallbackUser &so ) { TSend( so, zway_cc_switch_binary_get ); } template<> void Send< SWITCH_BINARY_SET >( CallbackUser &so, bool value ) { TSend( so, zway_cc_switch_binary_set, value ? 1 : 0 ); } template<> void Send< SENSOR_BINARY_GET >( CallbackUser &so ) { TSend( so, zway_cc_sensor_binary_get, -1 ); } } template< CommandEnum cmdId, typename... ArgTypes > void Send( Instance *inst, ArgTypes... args ) { using namespace ImplementationNS; WaitForSignal wcb; // destructor will wait for callback CallbackUser so( inst, &wcb ); Send< cmdId >( so, args... ); } } |
All of those zway_cc_XXX functions take two call back functions. The first one will be called when the command processing was successful and the second call back will be called when the processing went wrong. I am sure what can make the execution fail but I do get the failed cases occasionally. Initially I was throwing an exception in the function, "callback< false >", but since I don't know why it fails, I replaced it with cerr. I think it fails when the ZWave signal is too weak.
The call-back function takes three arguments. The 3rd one is supposed to be whatever is given when the zway_cc_XXX functions are called. This call-back with a custom argument is a common patter with call-back style programming but it can go pretty wrong if muti-thread is envolved. If I give an object pointer as the argument, the object must be valid at the time the call-back function is called from the other side.
One more thing to be careful with the call-back functions is that when those call-back functions are called from zway system, the zway is locked for a ZDataHolder. It means that call-back functions should not try to acquire another lock on zway system. In other words, call-back function can do only limited things in the life time.
Also when the callback function is called, it is called from another thread. So be prepared for race condition.
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 | // WaitForSignal.hpp written by Jae Hyuk Kwak class WaitForSignal { mutex mtx_; condition_variable cv_; unique_lock< mutex > lock_; atomic< bool > waitIsOver_; public: WaitForSignal() : lock_( mtx_ ) { waitIsOver_.store( false, memory_order_release ); } ~WaitForSignal() { cv_.wait( lock_, [this] { return waitIsOver_.load( memory_order_acquire ); } ); } void WaitIsOver() { unique_lock< mutex > lock( mtx_ ); waitIsOver_.store( true, memory_order_release ); lock.unlock(); cv_.notify_one(); } }; |
pi@fileserver 10:43:32 myzway$ make g++-4.7 -Wall -g -std=c++11 -I/opt/z-way-server/libzway-dev/ -L/opt/z-way-server/libs -c stdafx.h g++-4.7 -Wall -g -std=c++11 -I/opt/z-way-server/libzway-dev/ -L/opt/z-way-server/libs -o myzway main.cpp -lzway -lxml2 -larchive -lssl -Wl,-rpath=/opt/z-way-server/libs pi@fileserver 10:44:03 myzway$ ./myzway 1: Static PC Controller 2: Routing Binary Sensor 3: Binary Power Switch 4: Repeater Slave Power of device 3 is off Send succeed. Power of device 3 is on
No comments:
Post a Comment