mqtt-sn-ruby 0.0.9 → 0.0.10

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fcf699ff94826e2f5267318686ddfaa18218b7cd
4
- data.tar.gz: cc30f03cfc41694d059ba2ca021a29250d8d6a61
3
+ metadata.gz: 4bdd116c2da406a3163968c7f8111b7649a83cf8
4
+ data.tar.gz: 775b6358cb108c2475679dc35e5844b0c9f68428
5
5
  SHA512:
6
- metadata.gz: 8274cc0c466571ce851322460dbe47640e14aa5e21cbffbbc6963719190e6d085244a483812a3dd8b2eb45caf9155b2825ce5b0c74a07a20d06f4a0b0eb50cee
7
- data.tar.gz: b47b0b5d1133eda805df011f18bc648c5ca886e36c7097eacdf75508ec68fa4de03d2011e8bdfabd0be95060c21f91435efe5bc62153e95e8f36af4f1e3e8b7f
6
+ metadata.gz: ee3244e7ffe27bd3ebcb2894a731f1e3ecc9afa8bd7807c6755ce035d9621293b83344590619f5a87354c2de6de901dbb3b087324a2eb3b812dfde512dddee2b
7
+ data.tar.gz: 3a7b1be4136a6866bfed5d08dcd14f6a340f582affb25409d14f267e60a0ddf4837afa53c1b39b66ac029709117ddd31457bee156bac972b91fb4609b624b04e
@@ -31,6 +31,10 @@ OptionParser.new do |opts|
31
31
  opts.on("-l", "--localport port", "MQTT-SN local port to listen (1882)") do |v|
32
32
  options[:local_port] = v.to_i
33
33
  end
34
+ options[:gw_id] = 123
35
+ opts.on("-i", "--id GwId", "MQTT-SN if of this GateWay (123)") do |v|
36
+ options[:gw_id] = v.to_i
37
+ end
34
38
  opts.on("-h", "--http port", "Http port for debug/status JSON server (false)") do |v|
35
39
  options[:http_port] = v.to_i
36
40
  end
data/bin/mqtt-sn-pub.rb CHANGED
@@ -39,7 +39,8 @@ OptionParser.new do |opts|
39
39
  options[:topic] = topic
40
40
  end
41
41
  end.parse!
42
-
42
+ #require 'ruby-prof'
43
+ #RubyProf.start
43
44
  puts "MQTT-SN-PUB: #{options.to_json}"
44
45
  begin
45
46
  sn=MqttSN.new options
@@ -47,7 +48,9 @@ begin
47
48
  sn.send :searchgw #replies may or may not come -- even multiple!
48
49
  sn.publish options[:topic]||"test/message/123", options[:msg]||"test_value", qos: options[:qos]
49
50
  puts "Sent ok."
50
- sleep 2 #allow log tu purge ;)
51
+ while not sn.log_empty?
52
+ sleep 0.1
53
+ end
51
54
  rescue SystemExit, Interrupt
52
55
  puts "\nExiting after Disconnect\n"
53
56
  rescue => e
@@ -58,3 +61,8 @@ sn.disconnect if sn
58
61
 
59
62
  puts "MQTT-SN-PUB Done."
60
63
 
64
+ #result = RubyProf.stop
65
+
66
+ # Print a flat profile to text
67
+ #printer = RubyProf::FlatPrinter.new(result)
68
+ #printer.print(STDOUT)
data/lib/mqtt-sn-ruby.rb CHANGED
@@ -51,24 +51,21 @@ class MqttSN
51
51
  QOS1_FLAG =0x20
52
52
  QOS0_FLAG =0x00
53
53
 
54
- @@msg_id=1
55
- @@clients={}
56
- @@gateways={}
57
- @@log_q = Queue.new #log queue :)
58
- @@log_t=Thread.new do
59
- log_thread
54
+
55
+ def logger str,*args
56
+ if @verbose or @debug
57
+ @log_q << sprintf(str,*args)
58
+ end
60
59
  end
61
60
 
62
- def self.logger str,*args
63
- @@log_q << sprintf(str,*args)
61
+ def note str,*args
62
+ @log_q << sprintf(str,*args)
64
63
  end
65
64
 
66
65
  def self.open_port uri_s
67
66
  begin
68
67
  uri = URI.parse(uri_s)
69
- pp uri
70
- if uri.scheme== 'udp'
71
- puts "server: #{@server}:#{@port}"
68
+ if uri.scheme== 'udp'
72
69
  return [UDPSocket.new,uri.host,uri.port]
73
70
  else
74
71
  raise "Error: Cannot open socket for '#{uri_s}', unsupported scheme: '#{uri.scheme}'"
@@ -102,10 +99,23 @@ class MqttSN
102
99
  @verbose=hash[:verbose]
103
100
  @state=:inited
104
101
  @bcast_port=5000
102
+ @bcast_period=10
105
103
  @forward=hash[:forward] #flag to indicate forward mode
106
104
  @will_topic=nil
107
105
  @will_msg=nil
108
106
  @id="?"
107
+
108
+
109
+ @msg_id=1
110
+ @clients={}
111
+ @gateways={}
112
+ @log_q = Queue.new #log queue :)
113
+
114
+ @log_t=Thread.new do
115
+ log_thread
116
+ end
117
+
118
+
109
119
  @sem=Mutex.new
110
120
  @topics={} #hash of registered topics is stored here
111
121
  @iq = Queue.new
@@ -126,96 +136,69 @@ class MqttSN
126
136
  @s.bind("0.0.0.0",hash[:local_port]||1883)
127
137
  @bcast_period=60
128
138
  loop do
129
- forwarder
139
+ forwarder_thread @s
130
140
  end
131
141
  end
132
142
 
133
143
  end
134
144
 
135
145
 
136
- def forwarder
146
+ def forwarder_thread socket
137
147
  begin
138
- last_bcast=0
139
148
  last_kill=0
140
149
  stime=Time.now.to_i
141
- while true
142
- now=Time.now.to_i
143
- if now>last_bcast+@bcast_period
144
- #periodically broadcast :advertize
145
- MqttSN::send_packet [ADVERTISE_TYPE,0xAB,0,30],@bcast_s,MULTICAST_ADDR,@bcast_port
146
- last_bcast=now
147
- end
148
- #periodically kill disconnected clients -- and those timed out..
149
- if now>last_kill+1
150
+ Thread.new do #maintenance
151
+ while true do
152
+ sleep 1
150
153
  changes=false
151
- @@clients.dup.each do |key,data|
154
+ @clients.dup.each do |key,data|
152
155
  if data[:state]==:disconnected
153
156
  dest="#{data[:ip]}:#{data[:port]}"
154
- MqttSN::logger "- %s",dest
155
- @@clients.delete key
157
+ note "- %s",dest
158
+ @clients.delete key
156
159
  changes=true
157
160
  end
158
161
  end
159
162
  if changes
160
- MqttSN::logger "cli:#{@@clients.to_json}"
161
- end
162
- last_kill=now
163
- end
164
-
165
- if false # pac=MqttSN::poll_packet(@bcast)
166
- r,client_ip,client_port=pac
167
- key="#{client_ip}:#{client_port}"
168
- dest="#{MULTICAST_ADDR};#{@bcast_port}"
169
- m=MqttSN::parse_message r
170
- MqttSN::logger "R %-18.18s -> %-18.18s | %s",key,dest,m.to_json
171
-
172
- case m[:type]
173
- when :searchgw
174
- dest="#{client_ip}:#{client_port}"
175
- MqttSN::logger "C %-18.18s -> %-18.18s | %s",key,dest,m.to_json
176
- MqttSN::send_packet [GWINFO_TYPE,0xAB],@bcast_s,MULTICAST_ADDR,@bcast_port
177
- done=true
178
- end
179
-
180
- end
181
- if pac=MqttSN::poll_packet(@s)
182
- r,client_ip,client_port=pac
183
- key="#{client_ip}:#{client_port}"
184
- if not @@clients[key]
185
- @@clients[key]={ip:client_ip, port:client_port, socket: UDPSocket.new, state: :active }
186
- dest="#{client_ip}:#{client_port}"
187
- MqttSN::logger "+ %s\n",dest
188
- MqttSN::logger "cli: #{@@clients.to_json}"
189
- end
190
- @@clients[key][:stamp]=Time.now.to_i
191
- m=MqttSN::parse_message r
192
- done=false
193
-
194
- if not done # not done locally -> forward it
195
- sbytes=@@clients[key][:socket].send(r, 0, @server, @port) # to rsmb -- ok as is
196
- _,port,_,_ = @@clients[key][:socket].addr
197
- dest="#{@server}:#{port}"
198
- MqttSN::logger "C %-18.18s -> %-18.18s | %s",key,dest,m.to_json
163
+ note "cli:#{@clients.to_json}"
199
164
  end
200
165
  end
201
- @@clients.each do |key,c|
202
- if pac=MqttSN::poll_packet(c[:socket])
203
- r,client_ip,client_port=pac
204
- #puts "got packet #{pac} from server to client #{key}:"
205
- #puts "sending to #{c[:ip]}:#{c[:port]}"
206
- @s.send(r, 0, c[:ip], c[:port]) # send_packet
207
- m=MqttSN::parse_message r
208
- _,port,_,_ = @@clients[key][:socket].addr
209
- dest="#{@server}:#{port}"
210
- MqttSN::logger "S %-18.18s <- %-18.18s | %s",key,dest,m.to_json
211
- case m[:type]
212
- when :disconnect
213
- @@clients[key][:state]=:disconnected
166
+ end
167
+ while true
168
+ pac=MqttSN::poll_packet_block(socket) #data from clients to our service sovket
169
+ r,client_ip,client_port=pac
170
+ key="#{client_ip}:#{client_port}"
171
+ if not @clients[key]
172
+ @clients[key]={ip:client_ip, port:client_port, socket: UDPSocket.new, state: :active }
173
+ c=@clients[key]
174
+ puts "thread start for #{key}"
175
+ @clients[key][:thread]=Thread.new(key) do |my_key|
176
+ while true
177
+ pacc=MqttSN::poll_packet_block(@clients[my_key][:socket]) #if we get data from server destined to our client
178
+ rr,client_ip,client_port=pacc
179
+ @s.send(rr, 0, @clients[my_key][:ip], @clients[my_key][:port]) # send_packet to client
180
+ mm=MqttSN::parse_message rr
181
+ _,port,_,_ = @clients[my_key][:socket].addr
182
+ dest="#{@server}:#{port}"
183
+ logger "S %-18.18s <- %-18.18s | %s",my_key,dest,mm.to_json
184
+ case mm[:type]
185
+ when :disconnect
186
+ @clients[my_key][:state]=:disconnected
187
+ end
214
188
  end
215
189
  end
190
+ dest="#{client_ip}:#{client_port}"
191
+ note "+ %s\n",dest
192
+ note "cli: #{@clients.to_json}"
216
193
  end
217
- sleep 0.01
218
- end
194
+ @clients[key][:stamp]=Time.now.to_i
195
+ m=MqttSN::parse_message r
196
+ sbytes=@clients[key][:socket].send(r, 0, @server, @port) # to rsmb -- ok as is
197
+ _,port,_,_ = @clients[key][:socket].addr
198
+ dest="#{@server}:#{port}"
199
+ logger "C %-18.18s -> %-18.18s | %s",key,dest,m.to_json
200
+
201
+ end
219
202
  end
220
203
  end
221
204
 
@@ -265,11 +248,11 @@ class MqttSN
265
248
  @id=hash[:id]
266
249
  when :register
267
250
  raise "Need :topic to Publish!" if not hash[:topic]
268
- p=[REGISTER_TYPE,0,0,@@msg_id >>8 ,@@msg_id & 0xff]
251
+ p=[REGISTER_TYPE,0,0,@msg_id >>8 ,@msg_id & 0xff]
269
252
  hash[:topic].each_byte do |b|
270
253
  p<<b
271
254
  end
272
- @@msg_id+=1
255
+ @msg_id+=1
273
256
  when :register_ack
274
257
  p=[REGACK_TYPE,hash[:topic_id]>>8 ,hash[:topic_id] & 0xff,hash[:msg_id]>>8 ,hash[:msg_id] & 0xff,hash[:return_code]]
275
258
  when :publish_ack
@@ -312,19 +295,19 @@ class MqttSN
312
295
  else
313
296
  flags+=QOS1_FLAG*qos
314
297
  end
315
- p=[SUBSCRIBE_TYPE,flags,@@msg_id >>8 ,@@msg_id & 0xff]
298
+ p=[SUBSCRIBE_TYPE,flags,@msg_id >>8 ,@msg_id & 0xff]
316
299
  hash[:topic].each_byte do |b|
317
300
  p<<b
318
301
  end
319
- @@msg_id+=1
302
+ @msg_id+=1
320
303
 
321
304
  when :unsubscribe
322
305
  raise "Need :topic to :unsubscribe" if not hash[:topic]
323
- p=[UNSUBSCRIBE_TYPE,0,@@msg_id >>8 ,@@msg_id & 0xff]
306
+ p=[UNSUBSCRIBE_TYPE,0,@msg_id >>8 ,@msg_id & 0xff]
324
307
  hash[:topic].each_byte do |b|
325
308
  p<<b
326
309
  end
327
- @@msg_id+=1
310
+ @msg_id+=1
328
311
 
329
312
  when :publish
330
313
  raise "Need :topic_id to Publish!" if not hash[:topic_id]
@@ -336,11 +319,11 @@ class MqttSN
336
319
  else
337
320
  flags+=QOS1_FLAG*qos
338
321
  end
339
- p=[PUBLISH_TYPE,flags,hash[:topic_id] >>8 ,hash[:topic_id] & 0xff,@@msg_id >>8 ,@@msg_id & 0xff]
322
+ p=[PUBLISH_TYPE,flags,hash[:topic_id] >>8 ,hash[:topic_id] & 0xff,@msg_id >>8 ,@msg_id & 0xff]
340
323
  hash[:msg].each_byte do |b|
341
324
  p<<b
342
325
  end
343
- @@msg_id+=1
326
+ @msg_id+=1
344
327
  when :pubrel
345
328
  raise "Need the original :msg_id of the Publish for PubRel!" if not hash[:msg_id]
346
329
  p=[PUBREL_TYPE,hash[:msg_id] >>8 ,hash[:msg_id] & 0xff]
@@ -360,6 +343,15 @@ class MqttSN
360
343
  end
361
344
  status=:timeout
362
345
  m={}
346
+ if not hash[:expect]
347
+ if type==:searchgw
348
+ raw=send_packet p,@bcast,MULTICAST_ADDR,@bcast_port
349
+ else
350
+ raw=send_packet p,@s,@server,@port
351
+ end
352
+ hash[:debug]=raw if @debug
353
+ return
354
+ end
363
355
  @sem.synchronize do #one command at a time --
364
356
  if hash[:expect]
365
357
  while not @iq.empty?
@@ -369,9 +361,9 @@ class MqttSN
369
361
  @iq.clear
370
362
  end
371
363
  if type==:searchgw
372
- raw=MqttSN::send_packet p,@bcast,MULTICAST_ADDR,@bcast_port
364
+ raw=send_packet p,@bcast,MULTICAST_ADDR,@bcast_port
373
365
  else
374
- raw=MqttSN::send_packet p,@s,@server,@port
366
+ raw=send_packet p,@s,@server,@port
375
367
  end
376
368
  hash[:debug]=raw if @debug
377
369
  #puts "send:#{@id} #{type},#{hash.to_json}" if @verbose
@@ -396,7 +388,7 @@ class MqttSN
396
388
  break
397
389
  else
398
390
  retries+=1
399
- send_packet p
391
+ send_packet p,@s,@server,@port
400
392
  puts "fail to get ack, retry #{retries} :#{@id} #{type},#{hash.to_json}"
401
393
  #need to set DUP flag !
402
394
  end
@@ -418,18 +410,13 @@ class MqttSN
418
410
  end
419
411
  end
420
412
 
421
- def self.send_packet m,socket,server,port
413
+ def send_packet m,socket,server,port
422
414
  msg=MqttSN::build_packet m
423
415
  MqttSN::send_raw_packet msg,socket,server,port
424
416
  dest="#{server}:#{port}"
425
417
  _,port,_,_ = socket.addr
426
418
  src=":#{port}"
427
- MqttSN::logger "< %-18.18s <- %-18.18s | %s",dest,src,parse_message(msg).to_json
428
- end
429
-
430
-
431
- def send_packet m
432
- MqttSN::send_packet m,@s,@server,@port
419
+ logger "< %-18.18s <- %-18.18s | %s",dest,src,MqttSN::parse_message(msg).to_json
433
420
  end
434
421
 
435
422
  def self.poll_packet socket
@@ -440,6 +427,7 @@ class MqttSN
440
427
  client_port=stuff[1]
441
428
  return [r,client_ip,client_port]
442
429
  rescue IO::WaitReadable
430
+ sleep 0.1
443
431
  rescue => e
444
432
  puts "Error: receive thread died: #{e}"
445
433
  pp e.backtrace
@@ -447,12 +435,20 @@ class MqttSN
447
435
  return nil
448
436
  end
449
437
 
438
+ def self.poll_packet_block socket
439
+ #decide how to get data -- UDP-socket or FM-radio
440
+ r,stuff=socket.recvfrom(200) #get_packet --high level func!
441
+ client_ip=stuff[2]
442
+ client_port=stuff[1]
443
+ return [r,client_ip,client_port]
444
+ end
445
+
450
446
  def self.get_clients
451
- @@clients
447
+ @clients
452
448
  end
453
449
 
454
450
  def self.get_gateways
455
- @@gateways
451
+ @gateways
456
452
  end
457
453
 
458
454
 
@@ -723,7 +719,7 @@ class MqttSN
723
719
  def client_thread socket
724
720
  while true do
725
721
  begin
726
- if pac=MqttSN::poll_packet(socket)
722
+ if pac=MqttSN::poll_packet_block(socket)
727
723
  r,client_ip,client_port=pac
728
724
  m=MqttSN::parse_message r
729
725
  if @debug and m
@@ -732,8 +728,10 @@ class MqttSN
732
728
  dest="#{client_ip}:#{client_port}"
733
729
  _,port,_,_ = @s.addr
734
730
  src=port
735
- MqttSN::logger "> %-18.18s <- %-18.18s | %s",dest,":#{port}",m.to_json
731
+ logger "> %-18.18s -> %-18.18s | %s",dest,":#{port}",m.to_json
736
732
  process_message m
733
+ else
734
+ sleep 0.01
737
735
  end
738
736
  rescue => e
739
737
  puts "Error: receive thread died: #{e}"
@@ -745,41 +743,51 @@ class MqttSN
745
743
  def process_broadcast_message m,client_ip,client_port
746
744
  case m[:type]
747
745
  when :searchgw
748
- MqttSN::logger "hey, someone is looking for gateway..."
746
+ note "hey, someone is looking for gateway..."
749
747
  key="#{client_ip}:#{client_port}"
750
748
  dest="#{MULTICAST_ADDR};#{@bcast_port}"
751
749
  #actually -- send data on all gateways we know...
752
- MqttSN::logger "r %-18.18s -> %-18.18s | %s",key,dest,m.to_json
753
- MqttSN::send_packet [GWINFO_TYPE,0xAB],@bcast_s,MULTICAST_ADDR,@bcast_port
750
+ if @options[:forwarder]
751
+ logger "r %-18.18s -> %-18.18s | %s",key,dest,m.to_json
752
+ send_packet [GWINFO_TYPE,@options[:gw_id]],@bcast_s,MULTICAST_ADDR,@bcast_port
753
+ end
754
754
  when :advertise,:gwinfo
755
- MqttSN::logger "hey, we have gateway there!"
756
- if not @@gateways[client_ip]
757
- @@gateways[client_ip]={stamp: Time.now.to_i}
755
+ note "hey, we have gateway there!"
756
+ if not @gateways[client_ip]
757
+ @gateways[client_ip]={stamp: Time.now.to_i}
758
758
  else
759
- @@gateways[client_ip][:stamp]=Time.now.to_i
759
+ @gateways[client_ip][:stamp]=Time.now.to_i
760
760
  end
761
- @@gateways[client_ip][:gw_id]=m[:gw_id]
762
- @@gateways[client_ip][:duration]=m[:duration]
763
- MqttSN::logger "gw: #{@@gateways.to_json}"
761
+ @gateways[client_ip][:gw_id]=m[:gw_id]
762
+ @gateways[client_ip][:duration]=m[:duration]
763
+ note "gw: #{@gateways.to_json}"
764
764
  end
765
765
  end
766
766
 
767
767
  def roam_thread socket
768
+ @last_bcast=0
769
+ if @options[:forwarder]
770
+ Thread.new do
771
+ while true do
772
+ send_packet [ADVERTISE_TYPE,@options[:gw_id],@bcast_period>>8,@bcast_period&0xff],@bcast_s,MULTICAST_ADDR,@bcast_port
773
+ sleep @bcast_period
774
+ end
775
+ end
776
+ end
768
777
  while true do
769
778
  begin
770
779
  if @bcast
771
- if pac=MqttSN::poll_packet(socket)
772
- r,client_ip,client_port=pac
773
- m=MqttSN::parse_message r
774
- if @debug and m
775
- m[:debug]=MqttSN::hexdump r
776
- end
777
- dest="#{client_ip}:#{client_port}"
778
- _,port,_,_ = @bcast.addr
779
- src=port
780
- MqttSN::logger "R %-18.18s <- %-18.18s | %s",dest,":#{port}",m.to_json
781
- process_broadcast_message m,client_ip,client_port
780
+ pac=MqttSN::poll_packet_block(socket)
781
+ r,client_ip,client_port=pac
782
+ m=MqttSN::parse_message r
783
+ if @debug and m
784
+ m[:debug]=MqttSN::hexdump r
782
785
  end
786
+ dest="#{client_ip}:#{client_port}"
787
+ _,port,_,_ = @bcast.addr
788
+ src=port
789
+ logger "R %-18.18s <- %-18.18s | %s",dest,":#{port}",m.to_json
790
+ process_broadcast_message m,client_ip,client_port
783
791
  end
784
792
  rescue => e
785
793
  puts "Error: receive thread died: #{e}"
@@ -788,12 +796,18 @@ class MqttSN
788
796
  end
789
797
  end
790
798
 
791
- def self.log_thread
799
+ def log_empty?
800
+ @log_q.empty? or not @verbose
801
+ end
802
+
803
+ def log_thread
792
804
  while true do
793
805
  begin
794
- if not @@log_q.empty?
795
- l=@@log_q.pop
806
+ if not @log_q.empty?
807
+ l=@log_q.pop
796
808
  puts l
809
+ else
810
+ sleep 0.01
797
811
  end
798
812
  rescue => e
799
813
  puts "Error: receive thread died: #{e}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mqtt-sn-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Siitonen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-18 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby toolkit for MQTT-SN, compatible with RSMB, command line tools and
14
14
  API