Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 455 lines (400 sloc) 16.792 kb
be7923d Added LGPL licence headers
Elias Karakoulakis authored
1 /*
2 Thrift4OZW - An Apache Thrift wrapper for OpenZWave
3 ----------------------------------------------------
4 Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
5
6 SOFTWARE NOTICE AND LICENSE
7
8 Thrift4OZW is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation, either version 3 of the License,
11 or (at your option) any later version.
12
13 Thrift4OZW is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with Thrift4OZW. If not, see <http://www.gnu.org/licenses/>.
20
21 for more information on the LGPL, see:
22 http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
23 */
24
8603286 Initial repo set-up
Elias Karakoulakis authored
25 //
be7923d Added LGPL licence headers
Elias Karakoulakis authored
26 // Main.cpp: OpenZWave Thrift Server for Project Ansible
8603286 Initial repo set-up
Elias Karakoulakis authored
27 // (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
28 //
29
30 #include "RemoteManager.h"
31 #include <protocol/TBinaryProtocol.h>
32 #include <server/TSimpleServer.h>
33 #include <transport/TServerSocket.h>
34 #include <transport/TBufferTransports.h>
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
35 #include <string>
36 #include <sstream>
37 #include <iostream>
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
38 #include "unistd.h"
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
39 // we're using Boost's program_options
40 #include <boost/program_options.hpp>
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
41 #include <boost/program_options/parsers.hpp>
42 #include <boost/program_options/variables_map.hpp>
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
43 namespace po = boost::program_options;
8603286 Initial repo set-up
Elias Karakoulakis authored
44
45 using namespace ::apache::thrift;
46 using namespace ::apache::thrift::protocol;
47 using namespace ::apache::thrift::transport;
48 using namespace ::apache::thrift::server;
49
50 using boost::shared_ptr;
51
52 using namespace OpenZWave;
53
54 // boost: extra includes
55 #include <boost/thread.hpp>
56 // the global mutex for accessing OpenZWave library
57 static boost::recursive_mutex g_criticalSection;
58
59 //
60 // Struct to hold all valid OpenZWave ValueID's
61 // (used by RemoteManager_server.cpp)
62 typedef struct
63 {
64 uint32 m_homeId;
65 uint8 m_nodeId;
66 bool m_polled;
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
67 //std::map<uint64, ValueID*> m_values;
68 list<ValueID> m_values;
8603286 Initial repo set-up
Elias Karakoulakis authored
69 } NodeInfo;
70 //
be7923d Added LGPL licence headers
Elias Karakoulakis authored
71 static list<NodeInfo*> g_nodes;
34c2ebe More OpenZWave compatibility fixes
Elias Karakoulakis authored
72
8603286 Initial repo set-up
Elias Karakoulakis authored
73 // OpenZWave includes
74 #include "Notification.h"
75
76 // PocoStromp
77 #include "PocoStomp.h"
78
79 static uint32 g_homeId = 0;
80 static bool g_initFailed = false;
81 //
82
83 static boost::condition_variable initCond ;
84 static boost::mutex initMutex;
85
86 // STOMP statics
87 static STOMP::PocoStomp* stomp_client;
88 static string* notifications_topic = new string("/queue/zwave/monitor");
89
90 //-----------------------------------------------------------------------------
91 // <GetNodeInfo>
92 // Callback that is triggered when a value, group or node changes
93 //-----------------------------------------------------------------------------
94 NodeInfo* GetNodeInfo
95 (
96 Notification const* _notification
97 )
98 {
99 uint32 const homeId = _notification->GetHomeId();
100 uint8 const nodeId = _notification->GetNodeId();
101 for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it )
102 {
103 NodeInfo* nodeInfo = *it;
104 if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) )
105 {
106 return nodeInfo;
107 }
108 }
109
110 return NULL;
111 }
112
113 //-----------------------------------------------------------------------------
114 // <OnNotification>
115 // Callback that is triggered by OpenZWave when a value, group or node changes
116 //-----------------------------------------------------------------------------
117 void OnNotification
118 (
119 Notification const* _notification,
120 void* _context
121 )
122 {
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
123 bool notify_stomp = true;
be7923d Added LGPL licence headers
Elias Karakoulakis authored
124 bool send_valueID = false;
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
125
8603286 Initial repo set-up
Elias Karakoulakis authored
126 // Must do this inside a critical section to avoid conflicts with the main thread
127 g_criticalSection.lock();
128
129 switch( _notification->GetType() )
130 {
131 /**< A new node value has been added to OpenZWave's list.
132 These notifications occur after a node has been discovered,
133 and details of its command classes have been received.
134 Each command class may generate one or more values,
135 depending on the complexity of the item being represented. */
136 case Notification::Type_ValueAdded:
137 {
138 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
139 {
140 // Add the new value to the node's value list
141 ValueID v = _notification->GetValueID();
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
142 nodeInfo->m_values.push_back( v );
8603286 Initial repo set-up
Elias Karakoulakis authored
143 }
be7923d Added LGPL licence headers
Elias Karakoulakis authored
144 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
145 break;
146 }
147
148 /**< A node value has been removed from OpenZWave's list.
149 This only occurs when a node is removed. */
150 case Notification::Type_ValueRemoved:
151 {
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
152 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
153 {
8603286 Initial repo set-up
Elias Karakoulakis authored
154 // Remove the value from out list
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
155 for( list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it )
156 {
157 if( (*it) == _notification->GetValueID() )
158 {
159 nodeInfo->m_values.erase( it );
160 break;
161 }
162 }
163
164 //~ // Remove the value from out list
165 for( list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it )
166 {
167 if( (*it) == _notification->GetValueID() )
168 {
169 nodeInfo->m_values.erase( it );
170 break;
171 }
172 }
173 }
be7923d Added LGPL licence headers
Elias Karakoulakis authored
174 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
175 break;
176 }
177
178 /**< A node value has been updated from the Z-Wave network. */
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
179 case Notification::Type_ValueChanged:
180 case Notification::Type_ValueRefreshed: {
be7923d Added LGPL licence headers
Elias Karakoulakis authored
181 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
182 /**< The associations for the node have changed. The application
183 should rebuild any group information it holds about the node. */
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
184 }
cdcf187 @ekarak updated demo files
ekarak authored
185 break;
186
8603286 Initial repo set-up
Elias Karakoulakis authored
187 case Notification::Type_Group:
188 /**< A new node has been found (not already stored in zwcfg*.xml file) */
189 case Notification::Type_NodeNew:
190 /**< Basic node information has been receievd, such as whether the node is a
191 listening device, a routing device and its baud rate and basic, generic and
192 specific types. It is after this notification that you can call Manager::GetNodeType
193 to obtain a label containing the device description. */
194 case Notification::Type_NodeProtocolInfo:
195 /**< A node has triggered an event. This is commonly caused when a node sends
196 a Basic_Set command to the controller. The event value is stored in the notification. */
cdcf187 @ekarak updated demo files
ekarak authored
197 /* case Notification::Type_NodeEvent:
8603286 Initial repo set-up
Elias Karakoulakis authored
198 {
199 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
200 {
201 // One of the node's association groups has changed
202 // TBD...
203 }
204 break;
205 }
cdcf187 @ekarak updated demo files
ekarak authored
206 */
8603286 Initial repo set-up
Elias Karakoulakis authored
207
208 /**< A new node has been added to OpenZWave's list. This may be due
209 to a device being added to the Z-Wave network, or because
210 the application is initializing itself. */
211 case Notification::Type_NodeAdded:
212 {
213 // Add the new node to our list
214 NodeInfo* nodeInfo = new NodeInfo();
215 nodeInfo->m_homeId = _notification->GetHomeId();
216 nodeInfo->m_nodeId = _notification->GetNodeId();
217 nodeInfo->m_polled = false;
218 g_nodes.push_back( nodeInfo );
219 break;
220 }
221
222 /**< A node has been removed from OpenZWave's list. This may be due
223 to a device being removed from the Z-Wave network, or because the application is closing. */
224 case Notification::Type_NodeRemoved:
225 {
226 // Remove the node from our list
227 uint32 const homeId = _notification->GetHomeId();
228 uint8 const nodeId = _notification->GetNodeId();
229 for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it )
230 {
231 NodeInfo* nodeInfo = *it;
232 if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) )
233 {
234 g_nodes.erase( it );
235 break;
236 }
237 }
238 break;
239 }
240
241 // Type_NodeNaming missing
242
243 /**< Polling of a node has been successfully turned off by a call to Manager::DisablePoll */
244 case Notification::Type_PollingDisabled:
245 {
246 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
247 {
248 nodeInfo->m_polled = false;
249 }
250 break;
251 }
252
253 /**< Polling of a node has been successfully turned on by a call to Manager::EnablePoll */
254 case Notification::Type_PollingEnabled:
255 {
256 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
257 {
258 nodeInfo->m_polled = true;
259 }
260 break;
261 }
262
263 /**< A driver for a PC Z-Wave controller has been added and is ready to use. The notification
264 will contain the controller's Home ID, which is needed to call most of the Manager methods. */
265 case Notification::Type_DriverReady:
266 {
267 g_homeId = _notification->GetHomeId();
268 break;
269 }
270
271 /**< Driver failed to load */
272 case Notification::Type_DriverFailed:
273 {
274 g_initFailed = true;
275 initCond.notify_all();
276 break;
277 }
278
279 //missing Type_DriverReset: < All nodes and values for this driver have been removed. This is sent instead of potentially hundreds of individual node and value notifications. */
280 //missing MsgComplete < The last message that was sent is now complete. */
281 //missing Type_EssentialNodeQueriesComplete, /**< The queries on a node that are essential to its operation have been completed. The node can now handle incoming messages. */
282 //missing Type_NodeQueriesComplete, /**< All the initialisation queries on a node have been completed. */
283
284 /*< All awake nodes have been queried, so client application can expected complete data for these nodes. */
285 case Notification::Type_AwakeNodesQueried:
286
287 /**< All nodes have been queried, so client application can expected complete data. */
288 case Notification::Type_AllNodesQueried:
289 {
290 initCond.notify_all();
291 break;
292 }
293
294 default:
cdcf187 @ekarak updated demo files
ekarak authored
295 break;
8603286 Initial repo set-up
Elias Karakoulakis authored
296 }
297
298 // now we can send the captured event to STOMP queue
299 //
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
300 if (notify_stomp) {
301 STOMP::hdrmap headers;
be7923d Added LGPL licence headers
Elias Karakoulakis authored
302 headers["NotificationNodeId"] = to_string<uint16_t>(_notification->GetNodeId(), std::hex);
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
303 headers["NotificationType"] = to_string<uint32_t>(_notification->GetType(), std::hex);
be7923d Added LGPL licence headers
Elias Karakoulakis authored
304 headers["NotificationByte"] = to_string<uint16_t>(_notification->GetByte(), std::hex);
305 if (send_valueID) {
306 headers["HomeID"] = to_string<uint32_t>(_notification->GetValueID().GetHomeId(), std::hex);
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
307 headers["ValueID"] = to_string<uint64_t>(_notification->GetValueID().GetId(), std::hex);
be7923d Added LGPL licence headers
Elias Karakoulakis authored
308 }
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
309 //
310 string empty = "" ;
311 stomp_client->send(*notifications_topic, headers, empty);
312 }
8603286 Initial repo set-up
Elias Karakoulakis authored
313 //
314 g_criticalSection.unlock();
315 }
316
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
317 // Send all known values via STOMP
318 void send_all_values() {
be7923d Added LGPL licence headers
Elias Karakoulakis authored
319 //
320 g_criticalSection.lock();
321 //
322 for( list<NodeInfo*>::iterator node_it = g_nodes.begin(); node_it != g_nodes.end(); ++node_it )
323 {
324 NodeInfo* nodeInfo = *node_it;
325
326 for( list<ValueID>::iterator val_iter = nodeInfo->m_values.begin(); val_iter != nodeInfo->m_values.end(); ++val_iter )
327 {
328 ValueID v = *val_iter;
329 STOMP::hdrmap headers;
330 headers["HomeID"] = to_string<uint32_t>(v.GetHomeId(), std::hex);
331 headers["ValueID"] = to_string<uint64_t>(v.GetId(), std::hex);
332 //
333 string empty = "" ;
334 stomp_client->send(*notifications_topic, headers, empty);
335 }
336 }
337 //
338 g_criticalSection.unlock();
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
339 }
340
bde506c [Begin/Cancel]ControllerCommand implementation, callback skeleton mec…
Elias Karakoulakis authored
341 // the Thrift-generated (and manually patched) RemoteManager implementation
8603286 Initial repo set-up
Elias Karakoulakis authored
342 // for OpenZWave::Manager class
343 #include "gen-cpp/RemoteManager_server.cpp"
344 //
345
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
346
347 // -----------------------------------------
348 int main(int argc, char *argv[]) {
349 // -----------------------------------------
350 string stomp_host = "localhost";
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
351 int stomp_port = 61613;
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
352 string ozw_config_dir = "/home/ekarak/ozw/open-zwave-read-only/config/";
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
353 string ozw_user = string(get_current_dir_name()+'/');
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
354 string ozw_port = "/dev/ttyUSB0";
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
355 int thrift_port = 9090;
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
356
357 try {
358 // Declare the supported options.
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
359 po::options_description desc("Project Ansible - OpenZWave orbiter");
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
360 desc.add_options()
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
361 ("help,?", "print this help message")
362 ("stomphost,h", po::value(&stomp_host), "STOMP server hostname")
363 ("stompport,s", po::value(&stomp_port), "STOMP server port number")
364 ("thriftport,t", po::value(&thrift_port), "Thrift service port")
365 ("ozwconf,c", po::value(&ozw_config_dir), "OpenZWave config/ path (manufacturer database)")
366 ("ozwuser,u", po::value(&ozw_user), "OpenZWave user path (network & configuration state)")
367 ("ozwport,p", po::value(&ozw_port), "OpenZWave driver port (e.g. /dev/ttyUSB0)")
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
368 ;
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
369 // a boost:program_options variable map
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
370 po::variables_map vm;
371 po::parsed_options l_parsed = po::parse_command_line(argc, argv, desc);
372 po::store(l_parsed, vm);
373 po::notify(vm);
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
374 // exit on help
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
375 if (vm.count("help")) {
376 cout << desc << "\n";
377 return 1;
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
378 }
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
379 }
3e7c24a updated API to OpenZWave main trunk rev.466
Elias Karakoulakis authored
380 catch (exception& e)
381 {
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
382 cerr << "Error parsing options: " << e.what() << "\n";
383 return 2;
384 }
385
386 // ------------------
387 try {
3e28ed8 further options in cmd-line flags.
Elias Karakoulakis authored
388 // connect to STOMP server in order to send openzwave notifications
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
389 stomp_client = new STOMP::PocoStomp(stomp_host, stomp_port);
390 stomp_client->connect();
3e7c24a updated API to OpenZWave main trunk rev.466
Elias Karakoulakis authored
391 }
392 catch (exception& e)
393 {
8bb9da5 use boost::program_options to parse arguments to main()
Elias Karakoulakis authored
394 cerr << "Error connecting to STOMP: " << e.what() << "\n";
395 return 3;
396 }
8603286 Initial repo set-up
Elias Karakoulakis authored
397
398 // OpenZWave initialization
399 //initMutex.lock();
3e7c24a updated API to OpenZWave main trunk rev.466
Elias Karakoulakis authored
400 try {
401 // Create the OpenZWave Manager.
402 // The first argument is the path to the config files (where the manufacturer_specific.xml file is located
403 // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL
404 // the log file will appear in the program's working directory.
aef10b7 fix GetValueListItems patch
Elias Karakoulakis authored
405 cout << "OpenZWave configuration dir: " << ozw_config_dir << std::endl;
406 cout << "OpenZWave user dir: " << ozw_user << std::endl;
3e7c24a updated API to OpenZWave main trunk rev.466
Elias Karakoulakis authored
407 Options::Create(ozw_config_dir, ozw_user, "" );
408 Options::Get()->Lock();
409
410 Manager::Create();
411
412 // Add a callback handler to the manager.
413 Manager::Get()->AddWatcher( OnNotification, NULL );
414
415 // Add a Z-Wave Driver
416 Manager::Get()->AddDriver( ozw_port );
417 //Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid );
418 }
419 catch (exception& e)
420 {
421 cerr << "Error initializing OpenZWave: " << e.what() << "\n";
422 return 4;
423 }
424
425 try {
426 // THRIFT: initialize RemoteManager
427 shared_ptr<RemoteManagerHandler> handler(new RemoteManagerHandler());
428 shared_ptr<TProcessor> processor(new RemoteManagerProcessor(handler));
429 TServerSocket* ss = new TServerSocket(thrift_port);
430 ss->setRecvTimeout(3000);
431 shared_ptr<TServerTransport> serverTransport(ss);
432 shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
433 shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
434 TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
435
436 // Now we just wait for the driver to become ready, and then write out the loaded config.
437 boost::unique_lock<boost::mutex> initLock(initMutex);
438 initCond.wait(initLock);
439 usleep(500);
440 cout << "------------------------------------------------------------------------" << endl;
441 cout << "OpenZWave is initialized, Thrift interface now listening on port " << thrift_port << endl;
442 cout << "------------------------------------------------------------------------" << endl;
443
444 server.serve();
445
446 }
447 catch (exception& e)
448 {
449 cerr << "Exception in OpenZWave Thrift server: " << e.what() << "\n";
450 return 5;
451 }
8603286 Initial repo set-up
Elias Karakoulakis authored
452
453 return 0;
cdcf187 @ekarak updated demo files
ekarak authored
454 }
Something went wrong with that request. Please try again.