Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 399 lines (346 sloc) 14.457 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>
38
39 //~ template <class T>
40 //~ std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
41 //~ {
42 //~ std::ostringstream oss;
43 //~ oss << f << t;
44 //~ return oss.str();
45 //~ }
8603286 Initial repo set-up
Elias Karakoulakis authored
46
47 using namespace ::apache::thrift;
48 using namespace ::apache::thrift::protocol;
49 using namespace ::apache::thrift::transport;
50 using namespace ::apache::thrift::server;
51
52 using boost::shared_ptr;
53
54 using namespace OpenZWave;
55
56 // boost: extra includes
57 #include <boost/thread.hpp>
58 // the global mutex for accessing OpenZWave library
59 static boost::recursive_mutex g_criticalSection;
60
61 //
62 // Struct to hold all valid OpenZWave ValueID's
63 // (used by RemoteManager_server.cpp)
64 typedef struct
65 {
66 uint32 m_homeId;
67 uint8 m_nodeId;
68 bool m_polled;
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
69 //std::map<uint64, ValueID*> m_values;
70 list<ValueID> m_values;
8603286 Initial repo set-up
Elias Karakoulakis authored
71 } NodeInfo;
72 //
be7923d Added LGPL licence headers
Elias Karakoulakis authored
73 static list<NodeInfo*> g_nodes;
34c2ebe More OpenZWave compatibility fixes
Elias Karakoulakis authored
74
8603286 Initial repo set-up
Elias Karakoulakis authored
75 // OpenZWave includes
76 #include "Notification.h"
77
78 // PocoStromp
79 #include "PocoStomp.h"
80
81 static uint32 g_homeId = 0;
82 static bool g_initFailed = false;
83 //
84
85 static boost::condition_variable initCond ;
86 static boost::mutex initMutex;
87
88 // STOMP statics
89 static STOMP::PocoStomp* stomp_client;
90 static string* notifications_topic = new string("/queue/zwave/monitor");
91
92 //-----------------------------------------------------------------------------
93 // <GetNodeInfo>
94 // Callback that is triggered when a value, group or node changes
95 //-----------------------------------------------------------------------------
96 NodeInfo* GetNodeInfo
97 (
98 Notification const* _notification
99 )
100 {
101 uint32 const homeId = _notification->GetHomeId();
102 uint8 const nodeId = _notification->GetNodeId();
103 for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it )
104 {
105 NodeInfo* nodeInfo = *it;
106 if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) )
107 {
108 return nodeInfo;
109 }
110 }
111
112 return NULL;
113 }
114
115 //-----------------------------------------------------------------------------
116 // <OnNotification>
117 // Callback that is triggered by OpenZWave when a value, group or node changes
118 //-----------------------------------------------------------------------------
119 void OnNotification
120 (
121 Notification const* _notification,
122 void* _context
123 )
124 {
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
125 bool notify_stomp = true;
be7923d Added LGPL licence headers
Elias Karakoulakis authored
126 bool send_valueID = false;
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
127
8603286 Initial repo set-up
Elias Karakoulakis authored
128 // Must do this inside a critical section to avoid conflicts with the main thread
129 g_criticalSection.lock();
130
131 switch( _notification->GetType() )
132 {
133 /**< A new node value has been added to OpenZWave's list.
134 These notifications occur after a node has been discovered,
135 and details of its command classes have been received.
136 Each command class may generate one or more values,
137 depending on the complexity of the item being represented. */
138 case Notification::Type_ValueAdded:
139 {
140 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
141 {
142 // Add the new value to the node's value list
143 ValueID v = _notification->GetValueID();
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
144 nodeInfo->m_values.push_back( v );
8603286 Initial repo set-up
Elias Karakoulakis authored
145 }
be7923d Added LGPL licence headers
Elias Karakoulakis authored
146 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
147 break;
148 }
149
150 /**< A node value has been removed from OpenZWave's list.
151 This only occurs when a node is removed. */
152 case Notification::Type_ValueRemoved:
153 {
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
154 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
155 {
8603286 Initial repo set-up
Elias Karakoulakis authored
156 // Remove the value from out list
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
157 for( list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it )
158 {
159 if( (*it) == _notification->GetValueID() )
160 {
161 nodeInfo->m_values.erase( it );
162 break;
163 }
164 }
165
166 //~ // Remove the value from out list
167 for( list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it )
168 {
169 if( (*it) == _notification->GetValueID() )
170 {
171 nodeInfo->m_values.erase( it );
172 break;
173 }
174 }
175 }
be7923d Added LGPL licence headers
Elias Karakoulakis authored
176 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
177 break;
178 }
179
180 /**< A node value has been updated from the Z-Wave network. */
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
181 case Notification::Type_ValueChanged: {
be7923d Added LGPL licence headers
Elias Karakoulakis authored
182 send_valueID = true;
8603286 Initial repo set-up
Elias Karakoulakis authored
183 /**< The associations for the node have changed. The application
184 should rebuild any group information it holds about the node. */
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
185 }
8603286 Initial repo set-up
Elias Karakoulakis authored
186 case Notification::Type_Group:
187 /**< A new node has been found (not already stored in zwcfg*.xml file) */
188 case Notification::Type_NodeNew:
189 /**< Basic node information has been receievd, such as whether the node is a
190 listening device, a routing device and its baud rate and basic, generic and
191 specific types. It is after this notification that you can call Manager::GetNodeType
192 to obtain a label containing the device description. */
193 case Notification::Type_NodeProtocolInfo:
194 /**< A node has triggered an event. This is commonly caused when a node sends
195 a Basic_Set command to the controller. The event value is stored in the notification. */
196 case Notification::Type_NodeEvent:
197 {
198 if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) )
199 {
200 // One of the node's association groups has changed
201 // TBD...
202 nodeInfo = nodeInfo;
203 }
204 break;
205 }
206
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:
295 {
296 }
297 }
298
299 // now we can send the captured event to STOMP queue
300 //
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
301 if (notify_stomp) {
302 STOMP::hdrmap headers;
be7923d Added LGPL licence headers
Elias Karakoulakis authored
303 headers["NotificationNodeId"] = to_string<uint16_t>(_notification->GetNodeId(), std::hex);
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
304 headers["NotificationType"] = to_string<uint32_t>(_notification->GetType(), std::hex);
be7923d Added LGPL licence headers
Elias Karakoulakis authored
305 headers["NotificationByte"] = to_string<uint16_t>(_notification->GetByte(), std::hex);
306 if (send_valueID) {
307 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
308 headers["ValueID"] = to_string<uint64_t>(_notification->GetValueID().GetId(), std::hex);
be7923d Added LGPL licence headers
Elias Karakoulakis authored
309 }
4951e1d create_server.rb: refactored code
Elias Karakoulakis authored
310 //
311 string empty = "" ;
312 stomp_client->send(*notifications_topic, headers, empty);
313 }
8603286 Initial repo set-up
Elias Karakoulakis authored
314 //
315 g_criticalSection.unlock();
316 }
317
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
318 // Send all known values via STOMP
319 void send_all_values() {
be7923d Added LGPL licence headers
Elias Karakoulakis authored
320 //
321 g_criticalSection.lock();
322 //
323 for( list<NodeInfo*>::iterator node_it = g_nodes.begin(); node_it != g_nodes.end(); ++node_it )
324 {
325 NodeInfo* nodeInfo = *node_it;
326
327 for( list<ValueID>::iterator val_iter = nodeInfo->m_values.begin(); val_iter != nodeInfo->m_values.end(); ++val_iter )
328 {
329 ValueID v = *val_iter;
330 STOMP::hdrmap headers;
331 headers["HomeID"] = to_string<uint32_t>(v.GetHomeId(), std::hex);
332 headers["ValueID"] = to_string<uint64_t>(v.GetId(), std::hex);
333 //
334 string empty = "" ;
335 stomp_client->send(*notifications_topic, headers, empty);
336 }
337 }
338 //
339 g_criticalSection.unlock();
67efa38 add SendAllValues() to send all known ValueID's to STOMP
Elias Karakoulakis authored
340 }
341
8603286 Initial repo set-up
Elias Karakoulakis authored
342 // ------------------------
343 // THRIFT MAGIC
344 // ------------------------
345 // the Thrift-generated (and manually edited) RemoteManager implementation
346 // for OpenZWave::Manager class
347 #include "gen-cpp/RemoteManager_server.cpp"
348 //
349
350 int main(int argc, char **argv) {
351 // STOMP
352 stomp_client = new STOMP::PocoStomp("localhost", 61613);
353 stomp_client->connect();
354
355 // OpenZWave initialization
356 //initMutex.lock();
357
358 // Create the OpenZWave Manager.
359 // The first argument is the path to the config files (where the manufacturer_specific.xml file is located
360 // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL
361 // the log file will appear in the program's working directory.
362 Options::Create( "/home/ekarak/ozw/open-zwave-read-only/config/", "", "" );
363 Options::Get()->Lock();
364
365 Manager::Create();
366
367 // Add a callback handler to the manager. The second argument is a context that
368 // is passed to the OnNotification method. If the OnNotification is a method of
369 // a class, the context would usually be a pointer to that class object, to
370 // avoid the need for the notification handler to be a static.
371 Manager::Get()->AddWatcher( OnNotification, NULL );
372
373 // Add a Z-Wave Driver
374 // Modify this line to set the correct serial port for your PC interface.
375
376 string ozw_port = "/dev/ttyUSB0";
377
378 Manager::Get()->AddDriver( ozw_port );
379 //Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid );
380
381 // Now we just wait for the driver to become ready, and then write out the loaded config.
382 // In a normal app, we would be handling notifications and building a UI for the user.
383 boost::unique_lock<boost::mutex> initLock(initMutex);
384 initCond.wait(initLock);
385
386 // initialize RemoteManager
387 int port = 9090;
388 shared_ptr<RemoteManagerHandler> handler(new RemoteManagerHandler());
389 shared_ptr<TProcessor> processor(new RemoteManagerProcessor(handler));
be7923d Added LGPL licence headers
Elias Karakoulakis authored
390 TServerSocket* ss = new TServerSocket(port);
391 ss->setRecvTimeout(3000);
392 shared_ptr<TServerTransport> serverTransport(ss);
8603286 Initial repo set-up
Elias Karakoulakis authored
393 shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
394 shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
395
396 TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
397 server.serve();
398 return 0;
399 }
Something went wrong with that request. Please try again.