ardtweeno 0.0.2 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +179 -1
  3. data/COPYING +4 -3
  4. data/Gemfile +29 -0
  5. data/Gemfile.lock +76 -0
  6. data/INSTALL +12 -0
  7. data/Procfile +1 -0
  8. data/README.md +26 -2
  9. data/Rakefile +14 -7
  10. data/lib/ardtweeno/api.rb +542 -0
  11. data/lib/ardtweeno/configreader.rb +65 -0
  12. data/lib/ardtweeno/db.rb +51 -0
  13. data/lib/ardtweeno/dispatcher.rb +538 -0
  14. data/lib/ardtweeno/exceptions.rb +33 -0
  15. data/lib/ardtweeno/node.rb +117 -0
  16. data/lib/ardtweeno/nodemanager.rb +300 -0
  17. data/lib/ardtweeno/packet.rb +98 -0
  18. data/lib/ardtweeno/restapi.rb +266 -0
  19. data/lib/ardtweeno/serialparser.rb +221 -0
  20. data/lib/ardtweeno.rb +120 -1
  21. data/public/glossy_green_button.svg +123 -0
  22. data/public/glossy_red_button.svg +75 -0
  23. data/public/main.css +129 -0
  24. data/public/raspberrypi.jpg +0 -0
  25. data/resources/conf.yaml +41 -0
  26. data/resources/nodelist.yaml +26 -0
  27. data/resources/serialparser.js +84 -0
  28. data/test/api_test.rb +255 -0
  29. data/test/dispatcher_test.rb +115 -0
  30. data/test/node_test.rb +105 -0
  31. data/test/nodemanager_test.rb +167 -0
  32. data/test/packet_test.rb +75 -0
  33. data/test/parser_test.rb +147 -0
  34. data/test/post_watch +11 -0
  35. data/test/rest_api_test.rb +248 -0
  36. data/test/run_mock +17 -0
  37. data/test/run_packet_push +14 -0
  38. data/test/serialport_mock.rb +43 -0
  39. data/test/test_helper.rb +15 -0
  40. data/test/tty0tty-1.1/AUTHORS +1 -0
  41. data/test/tty0tty-1.1/COPYING +340 -0
  42. data/test/tty0tty-1.1/INSTALL +18 -0
  43. data/test/tty0tty-1.1/README +52 -0
  44. data/test/tty0tty-1.1/THANKS +4 -0
  45. data/test/tty0tty-1.1/TODO +3 -0
  46. data/test/tty0tty-1.1/VERSION +4 -0
  47. data/test/tty0tty-1.1/module/Makefile +41 -0
  48. data/{bin/ardtweeno → test/tty0tty-1.1/module/Module.symvers} +0 -0
  49. data/test/tty0tty-1.1/module/modules.order +1 -0
  50. data/test/tty0tty-1.1/module/tty0tty.c +678 -0
  51. data/test/tty0tty-1.1/module/tty0tty.ko +0 -0
  52. data/test/tty0tty-1.1/module/tty0tty.mod.c +51 -0
  53. data/test/tty0tty-1.1/module/tty0tty.mod.o +0 -0
  54. data/test/tty0tty-1.1/module/tty0tty.o +0 -0
  55. data/test/tty0tty-1.1/pts/Makefile +10 -0
  56. data/test/tty0tty-1.1/pts/tty0tty +0 -0
  57. data/test/tty0tty-1.1/pts/tty0tty.c +222 -0
  58. data/views/createpost.erb +45 -0
  59. data/views/home.erb +59 -0
  60. metadata +89 -37
  61. data/README +0 -1
  62. data/test/Rakefile +0 -6
  63. data/test/features/ardtweeno.feature +0 -14
  64. data/test/features/step_definitions/ardtweeno_steps.rb +0 -24
@@ -0,0 +1,538 @@
1
+ ####################################################################################################
2
+ # @author David Kirwan <davidkirwanirl@gmail.com>
3
+ # @description Dispatcher system for the Ardtweeno Mesh Network
4
+ #
5
+ # @date 30-03-2013
6
+ ####################################################################################################
7
+
8
+ # Imports
9
+ require 'rubygems'
10
+ require 'serialport'
11
+ require 'logger'
12
+ require 'yaml'
13
+ require 'json'
14
+ require 'singleton'
15
+ require 'ardtweeno'
16
+ require 'mongo'
17
+
18
+ module Ardtweeno
19
+
20
+ ##
21
+ # Ardtweeno::Dispatcher system for the Ardtweeno Mesh Network
22
+ #
23
+ class Dispatcher
24
+
25
+ include Singleton
26
+
27
+ attr_accessor :nodeManager, :parser, :confdata, :nodedata, :db, :auth, :coll, :log, :running
28
+
29
+
30
+ ##
31
+ # Constructor for the Ardtweeno::Dispatcher class
32
+ #
33
+ # * *Args* :
34
+ # - ++ ->
35
+ # * *Returns* :
36
+ # -
37
+ # * *Raises* :
38
+ #
39
+ def initialize
40
+ @log = Ardtweeno.options[:log] ||= Logger.new(STDOUT)
41
+ @log.level = Ardtweeno.options[:level] ||= Logger::DEBUG
42
+
43
+ @running = false
44
+ @parser = nil
45
+
46
+ unless Ardtweeno.options[:test] ||= false
47
+ @log.debug "Calling bootstrap()"
48
+ bootstrap()
49
+ end
50
+ end
51
+
52
+
53
+ ##
54
+ # Ardtweeno::Dispatcher#flush method for flushing packet data to the Database
55
+ #
56
+ # * *Args* :
57
+ # - ++ ->
58
+ # * *Returns* :
59
+ # - true
60
+ # * *Raises* :
61
+ # Ardtweeno::DBError
62
+ def flush()
63
+ begin
64
+ @log.debug "Ardtweeno::Dispatcher#flush called"
65
+
66
+ db_host = @confdata["db"]["dbHost"]
67
+ db_port = @confdata["db"]["dbPort"]
68
+ db_name = @confdata["db"]["dbName"]
69
+ db_username = @confdata["db"]["dbUser"]
70
+ db_password = @confdata["db"]["dbPass"]
71
+ db_collection = @confdata["db"]["dbPacketsColl"]
72
+
73
+ if @db == nil
74
+ @log.fatal "The database connector is not connected to a database!"
75
+ @log.debug "Attempting to construct the MongoDB driver instance"
76
+
77
+ begin
78
+ @db = Mongo::Connection.new(db_host, db_port).db(db_name)
79
+
80
+ rescue Mongo::ConnectionFailure => e
81
+ raise Ardtweeno::DBError, e
82
+ end
83
+ end
84
+
85
+
86
+ # Ensure we are authenticated to use the MongoDB DB
87
+ begin
88
+ @auth = @db.authenticate(db_username, db_password)
89
+ @coll = @db.collection(db_collection)
90
+ rescue Mongo::AuthenticationError => e
91
+ raise Ardtweeno::DBError, e
92
+ end
93
+
94
+
95
+ nodeList = @nodeManager.nodeList
96
+ packetqueue = Array.new
97
+
98
+ nodeList.each do |i|
99
+
100
+ i.packetqueue.each do |j|
101
+
102
+ data = {
103
+ :key=>j.key,
104
+ :seqNo=>j.seqNo,
105
+ :date=>j.date,
106
+ :hour=>j.hour,
107
+ :minute=>j.minute,
108
+ :node=>j.node,
109
+ :data=>j.data
110
+ }
111
+
112
+ packetqueue << data
113
+ end
114
+
115
+ # Sorted the packetqueue by the sequence number sequentially
116
+ packetqueue = packetqueue.sort_by {|x| x[:seqNo]} # Not exactly ideal.. but it works ;p
117
+ end
118
+
119
+ @log.debug "Packetqueue size: #{packetqueue.size}"
120
+ @log.debug "Saving packetqueue to the Database"
121
+ @nodeManager.flush()
122
+
123
+
124
+ begin
125
+ packetqueue.each do |i|
126
+ @coll.insert(i)
127
+ end
128
+ rescue Exception => e
129
+ raise e
130
+ end
131
+
132
+
133
+ rescue Ardtweeno::DBError => e
134
+ raise e
135
+ end
136
+
137
+ return true
138
+ end
139
+
140
+
141
+ ##
142
+ # Ardtweeno::Dispatcher#retrieve_zones method for retrieving zone data from the system
143
+ #
144
+ # * *Args* :
145
+ # - ++ -> params Hash
146
+ # * *Returns* :
147
+ # - String in JSON form
148
+ # * *Raises* :
149
+ #
150
+ def retrieve_zones(params)
151
+ apitimer = Time.now
152
+
153
+ result = Ardtweeno::API.retrievezones(@confdata, params)
154
+
155
+ @log.debug "Duration: #{Time.now - apitimer} seconds"
156
+ return result
157
+ end
158
+
159
+
160
+
161
+ ##
162
+ # Ardtweeno::Dispatcher#retrieve_nodes method for retrieving node data from the system
163
+ #
164
+ # * *Args* :
165
+ # - ++ -> params Hash
166
+ # * *Returns* :
167
+ # - String in JSON form
168
+ # * *Raises* :
169
+ #
170
+ def retrieve_nodes(params)
171
+ apitimer = Time.now
172
+
173
+ result = Ardtweeno::API.retrievenodes(@nodeManager.nodeList, params)
174
+
175
+ @log.debug "Duration: #{Time.now - apitimer} seconds"
176
+ return result
177
+ end
178
+
179
+
180
+
181
+ ##
182
+ # Ardtweeno::Dispatcher#retrieve_packets method for retrieving packet data from the system
183
+ #
184
+ # * *Args* :
185
+ # - ++ -> params Hash
186
+ # * *Returns* :
187
+ # - String in JSON form
188
+ # * *Raises* :
189
+ #
190
+ def retrieve_packets(params)
191
+ apitimer = Time.now
192
+
193
+ result = Ardtweeno::API.retrievepackets(@nodeManager.nodeList, params)
194
+
195
+ @log.debug "Duration: #{Time.now - apitimer} seconds"
196
+ return result
197
+ end
198
+
199
+
200
+ ##
201
+ # Ardtweeno::Dispatcher#addWatch method to add a watch on a node
202
+ #
203
+ # * *Args* :
204
+ # - ++ -> params Hash
205
+ # * *Returns* :
206
+ # -
207
+ # * *Raises* :
208
+ #
209
+ def addWatch(params)
210
+ begin
211
+ apitimer = Time.now
212
+
213
+ if params.has_key? "node" and
214
+ params.has_key? "notifyURL" and
215
+ params.has_key? "method" and
216
+ params.has_key? "timeout"
217
+
218
+ @log.debug "Watch API call seems valid, passing to NodeManager"
219
+ @nodeManager.addWatch(params)
220
+ else
221
+ raise Exception, "Invalid Parameters"
222
+ end
223
+
224
+ @log.debug "Duration: #{Time.now - apitimer} seconds"
225
+ rescue Exception => e
226
+ raise e
227
+ end
228
+ end
229
+
230
+
231
+ ##
232
+ # Ardtweeno::Dispatcher#store stores a packet retrieved by the API into the system
233
+ #
234
+ # * *Args* :
235
+ # - ++ -> payload String - containing JSON data to match structure of Ardtweeno::Packet
236
+ # * *Returns* :
237
+ # - true
238
+ # * *Raises* :
239
+ # Ardtweeno::InvalidData if data is invalid or TypeError if not valid JSON
240
+ def store(origionalPayload)
241
+ begin
242
+
243
+ @log.debug "Payload recieved, processing.."
244
+ payload = JSON.parse(origionalPayload)
245
+
246
+ if payload["data"].nil? then raise Ardtweeno::InvalidData, "Packet missing data" end
247
+ @log.debug "Payload contains a :data key, continuing.."
248
+ if payload["key"].nil? then raise Ardtweeno::InvalidData, "Packet missing key" end
249
+ @log.debug "Payload contains a :key key, continuing.."
250
+
251
+ @log.debug "Searching for the corresponding Ardtweeno::Node in the system.."
252
+ node = @nodeManager.search({:key=>payload["key"]})
253
+ @log.debug "This packet belongs to a valid node.."
254
+
255
+ @log.debug "Constructing a new Ardtweeno::Packet from the payload.."
256
+ packet = Ardtweeno::Packet.new(Ardtweeno.nextSeq(), payload["key"], payload["data"])
257
+
258
+ @log.debug "Adding packet to the node.."
259
+ node.enqueue(packet)
260
+
261
+ @log.debug "Check if its being watched"
262
+ if @nodeManager.watched?(node)
263
+ @log.debug "There is a watch on this node, pushing notifications"
264
+ @nodeManager.pushNotification(node.node)
265
+ else
266
+ @log.debug "There is no watch associated with this node"
267
+ end
268
+
269
+ @log.debug "Success!"
270
+
271
+ rescue Ardtweeno::NotInNodeList => e
272
+ @log.debug "Node is not authorised to communicate with the gateway.."
273
+ raise Ardtweeno::NodeNotAuthorised, "Node is not authorised for this network, ignoring"
274
+ rescue Ardtweeno::InvalidData => e
275
+ raise Ardtweeno::InvalidData, "Data is invalid, ignoring"
276
+ rescue Exception => e
277
+ @log.debug e
278
+ raise e
279
+ end
280
+
281
+ return true
282
+ end
283
+
284
+
285
+ ##
286
+ # Ardtweeno::Dispatcher#start which launches the Ardtweeno Mesh Network Router
287
+ #
288
+ # * *Args* :
289
+ # - ++ ->
290
+ # * *Returns* :
291
+ # - true/false
292
+ # * *Raises* :
293
+ #
294
+ def start()
295
+
296
+ begin
297
+ unless Ardtweeno.options[:test]
298
+ unless @running == true
299
+
300
+ dev = @confdata["dev"]
301
+ speed = @confdata["speed"]
302
+ key = @confdata["adminkey"]
303
+
304
+ cmd = "/bin/bash -c '/usr/local/bin/node resources/serialparser.js #{dev} #{speed} #{key}'"
305
+
306
+ @parser = fork do
307
+ Signal.trap("SIGTERM") { `killall node`; exit }
308
+ `#{cmd}`
309
+ end
310
+
311
+ @log.debug "Dispatcher#start has been called starting the system up.."
312
+ @running = true
313
+
314
+ return true
315
+
316
+ end
317
+ else
318
+ unless @running == true
319
+ @running = true
320
+ return true
321
+ end
322
+ end
323
+ rescue Exception => e
324
+ `killall node`
325
+ raise e
326
+ end
327
+
328
+ @log.debug "The SerialParser system is already running.. ignoring.."
329
+ return false
330
+
331
+ end
332
+
333
+
334
+ ##
335
+ # Ardtweeno::Dispatcher#stop which stops the Ardtweeno Mesh Network Router
336
+ #
337
+ # * *Args* :
338
+ # - ++ ->
339
+ # * *Returns* :
340
+ # - true/false
341
+ # * *Raises* :
342
+ #
343
+ def stop()
344
+
345
+ begin
346
+ unless Ardtweeno.options[:test]
347
+ unless @running == false
348
+
349
+ @log.debug "Dispatcher#stop has been called shutting system down.."
350
+
351
+ Process.kill("SIGTERM", @parser)
352
+ Process.wait
353
+ @parser = nil
354
+
355
+ @running = false
356
+ return true
357
+
358
+ end
359
+ else
360
+ unless @running == false
361
+ @running = false
362
+ return true
363
+ end
364
+ end
365
+ rescue Exception => e
366
+ `killall node`
367
+ @parser = nil
368
+ raise e
369
+ end
370
+
371
+ @log.debug "SerialParser system is inactive.. ignoring.."
372
+ return false
373
+
374
+ end
375
+
376
+ ##
377
+ # Ardtweeno::Dispatcher#reboot which reboots the Ardtweeno Gateway host
378
+ #
379
+ # * *Args* :
380
+ # - ++ ->
381
+ # * *Returns* :
382
+ # -
383
+ # * *Raises* :
384
+ #
385
+ def reboot()
386
+ @log.debug "Dispatcher#reboot has been called, restarting the gateway host.."
387
+
388
+ cmd = 'ls -l' #'sudo reboot'
389
+
390
+ rebootFork = fork do
391
+ Signal.trap("SIGTERM") { exit }
392
+ `#{cmd}`
393
+ end
394
+ end
395
+
396
+
397
+ ##
398
+ # Ardtweeno::Dispatcher#running? checks to see if the SerialParser is running
399
+ #
400
+ # * *Args* :
401
+ # - ++ ->
402
+ # * *Returns* :
403
+ # - true/false
404
+ # * *Raises* :
405
+ #
406
+ def running?()
407
+ return @running
408
+ end
409
+
410
+
411
+ ##
412
+ # Ardtweeno::Dispatcher#authenticate? Checks the API key provided with that in the DB
413
+ #
414
+ # * *Args* :
415
+ # - ++ -> key String
416
+ # * *Returns* :
417
+ # - true/false
418
+ # * *Raises* :
419
+ #
420
+ def authenticate?(key)
421
+ if key == @confdata["adminkey"]
422
+ return true
423
+ else
424
+
425
+ @confdata["zones"].each do |i|
426
+ if i["zonekey"] == key
427
+ return true
428
+ end
429
+ end
430
+
431
+ return false
432
+ end
433
+ end
434
+
435
+
436
+ ##
437
+ # Ardtweeno::Dispatcher#config returns the configuration as read in from the DB
438
+ #
439
+ # * *Args* :
440
+ # - ++ ->
441
+ # * *Returns* :
442
+ # - @confdata
443
+ # * *Raises* :
444
+ #
445
+ def config()
446
+ return @confdata
447
+ end
448
+
449
+
450
+ ##
451
+ # Ardtweeno::Dispatcher#bootstrap which configures the Dispatcher instance for initial operation
452
+ #
453
+ # * *Args* :
454
+ # - ++ ->
455
+ # * *Returns* :
456
+ # -
457
+ # * *Raises* :
458
+ #
459
+ private
460
+ def bootstrap()
461
+
462
+ # Read in the configuration files
463
+ begin
464
+ @log.debug "Reading in the configuration files"
465
+
466
+ @confdata = Ardtweeno::ConfigReader.load(Ardtweeno::DBPATH)
467
+ @nodedata = Ardtweeno::ConfigReader.load(Ardtweeno::NODEPATH)
468
+
469
+ rescue Exception => e
470
+ @log.fatal e.message
471
+ @log.fatal e.backtrace
472
+ raise e
473
+ end
474
+
475
+ # Create the NodeManager instance
476
+ begin
477
+ @log.debug "Creating an instance of NodeManager inside the Dispatcher"
478
+
479
+ nodelist = Array.new
480
+
481
+ @nodedata.each do |i|
482
+
483
+ @log.debug i.inspect
484
+
485
+ noptions = {
486
+ :description => i["description"],
487
+ :version => i["version"],
488
+ :sensors => i["sensors"]
489
+ }
490
+
491
+ @log.debug noptions.inspect
492
+
493
+ nodelist << Ardtweeno::Node.new(i["name"], i["key"], noptions)
494
+ end
495
+
496
+ nmoptions = {:nodelist => nodelist}
497
+
498
+ @nodeManager = Ardtweeno::NodeManager.new(nmoptions)
499
+ rescue Exception => e
500
+ @log.debug e.message
501
+ @log.debug e.backtrace
502
+ raise e
503
+ end
504
+
505
+
506
+ # Create the MongoDB connector instance
507
+ begin
508
+ @log.debug @confdata["db"]["dbHost"]
509
+ @log.debug @confdata["db"]["dbPort"]
510
+ @log.debug @confdata["db"]["dbUser"]
511
+ @log.debug @confdata["db"]["dbPass"]
512
+ @log.debug @confdata["db"]["dbName"]
513
+ @log.debug @confdata["db"]["dbPacketsColl"]
514
+
515
+ @log.debug "Constructing the MongoDB driver instance"
516
+
517
+ db_host = @confdata["db"]["dbHost"]
518
+ db_port = @confdata["db"]["dbPort"]
519
+ db_name = @confdata["db"]["dbName"]
520
+ db_username = @confdata["db"]["dbUser"]
521
+ db_password = @confdata["db"]["dbPass"]
522
+ db_collection = @confdata["db"]["dbPacketsColl"]
523
+
524
+
525
+ @db = Mongo::Connection.new(db_host, db_port).db(db_name)
526
+
527
+ rescue Mongo::ConnectionFailure => e
528
+ @log.fatal "#{e}"
529
+ rescue Exception => e
530
+ raise e
531
+ end
532
+
533
+
534
+ end # End of the bootstrap()
535
+
536
+
537
+ end
538
+ end
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'ardtweeno'
3
+
4
+ module Ardtweeno
5
+
6
+ class DBError < Exception
7
+ end
8
+
9
+ class InvalidData < Exception
10
+ end
11
+
12
+ class NotANode < Exception
13
+ end
14
+
15
+ class NotInNodeList < Exception
16
+ end
17
+
18
+ class NotAPacket < Exception
19
+ end
20
+
21
+ class PacketListEmpty < Exception
22
+ end
23
+
24
+ class ManagerNotDefined < Exception
25
+ end
26
+
27
+ class NodeNotAuthorised < Exception
28
+ end
29
+
30
+ class SerialDeviceNotFound < Exception
31
+ end
32
+
33
+ end
@@ -0,0 +1,117 @@
1
+ ####################################################################################################
2
+ # @author David Kirwan <davidkirwanirl@gmail.com>
3
+ # @description Class to model an Ardtweeno Mesh Network Node
4
+ #
5
+ # @date 21-02-2013
6
+ ####################################################################################################
7
+ # Imports
8
+ require 'rubygems'
9
+ require 'logger'
10
+ require 'yaml'
11
+ require 'json'
12
+ require 'ardtweeno'
13
+
14
+ module Ardtweeno
15
+
16
+ ##
17
+ # Ardtweeno::Node class to model an Ardtweeno mesh network node
18
+ #
19
+ # Example YAML representation of an Ardtweeno::Node
20
+ #-
21
+ # name: node0
22
+ # key: 500d81aafe637717a52f8650e54206e64da33d27
23
+ # description: This node is outside
24
+ # version: 0.0.3
25
+ # sensors:
26
+ # - Temperature
27
+ # - Barometric Pressure
28
+ # - Altitude
29
+ class Node
30
+
31
+ attr_accessor :node, :key, :description, :version, :sensors, :log, :packetqueue
32
+
33
+
34
+ ##
35
+ # Ardtweeno::Node#new Constructor
36
+ #
37
+ # * *Args* :
38
+ # - ++ -> newNode String, newKey String, options Hash{:description String,
39
+ # :version String, :sensors Array}
40
+ # * *Returns* :
41
+ # -
42
+ # * *Raises* :
43
+ #
44
+ def initialize(newNode, newKey, options={})
45
+ @log = Ardtweeno.options[:log] ||= Logger.new(STDOUT)
46
+ @log.level = Ardtweeno.options[:level] ||= Logger::DEBUG
47
+
48
+ @node = newNode
49
+ @key = newKey
50
+
51
+ @description = options[:description] ||= "Default Description"
52
+ @version = options[:version] ||= Ardtweeno::VERSION
53
+ @sensors = options[:sensors] ||= Array.new
54
+
55
+ @packetqueue = Array.new
56
+
57
+ end
58
+
59
+
60
+
61
+ ##
62
+ # Ardtweeno::Node#enqueue stores an Ardtweeno::Packet in the maintained packet list
63
+ #
64
+ # * *Args* :
65
+ # - ++ -> Ardtweeno::Packet
66
+ # * *Returns* :
67
+ # - true
68
+ # * *Raises* :
69
+ # - Ardtweeno::NotAPacket
70
+ def enqueue(packet)
71
+
72
+ if packet.class == Ardtweeno::Packet
73
+ packet.node = @node
74
+ @packetqueue << packet
75
+ return true
76
+ else
77
+ raise Ardtweeno::NotAPacket
78
+ end
79
+
80
+ end
81
+
82
+
83
+ ##
84
+ # Ardtweeno::Node#dequeue stores an Ardtweeno::Packet in the maintained packet list
85
+ #
86
+ # * *Args* :
87
+ # - ++ ->
88
+ # * *Returns* :
89
+ # - Ardtweeno::Packet
90
+ # * *Raises* :
91
+ # - Ardtweeno::PacketListEmpty
92
+ def dequeue()
93
+
94
+ if @packetqueue.empty?
95
+ raise Ardtweeno::PacketListEmpty
96
+ else
97
+ return @packetqueue.delete(@packetqueue.first)
98
+ end
99
+
100
+ end
101
+
102
+
103
+ ##
104
+ # Ardtweeno::Node#to_s converts a Node instance to String
105
+ #
106
+ # * *Args* :
107
+ # - ++ ->
108
+ # * *Returns* :
109
+ # - String
110
+ # * *Raises* :
111
+ #
112
+ def to_s
113
+ return @node + ", " + @key + ", " + @description + ", " + @version + ", " + @sensors.to_s, @packetqueue.to_s
114
+ end
115
+
116
+ end
117
+ end