lora-rb 0.14.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d9ae8b46b9a42db2037a2fa8982464bb9752af1
4
- data.tar.gz: 9035bc787caaeb5d2ed80c2fca7bc4d59bcfebce
3
+ metadata.gz: e64d803226daebe33886346c591fe64547de3222
4
+ data.tar.gz: f8bbfa9765e0b8e59e1a5d31cd393bd162ca599f
5
5
  SHA512:
6
- metadata.gz: fb96d0297ecdde1cdd73c92ba9af09184cec57a558b50e7ab625abc32942c3dec8f0a5280eedbac23e12fbeb55f2ae813ea5096bf3e4c0abab0c37fe33133f4d
7
- data.tar.gz: 8eb4548eee426a26c629cb3a9a19214c2efff3daab9d20f5976200bf959ba67cc8125da44e570e19d7be7ea6c184f2604d21583289de91a235248dd1920692a8
6
+ metadata.gz: '02503788daa2ca41e53219162fbba9062060d491058cc9f72f5ba639ffd23341b4ce7573c4b0769c0a7bcdd97fbe261601280b7de7c0248ea0c8f55daabee7b1'
7
+ data.tar.gz: 38a51544561b73924783012f69118e0916950dacb3fc3ad8a7500a10e3b47d8f1cc47fb7937a01d8c68fc483168202e8b0fdc233e09158ec821e3a8999a0aefd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ v0.15.0 [☰](https://bitbucket.org/fractalgarden/loriot-rb/branches/compare/v0.14.0..v0.15.0) November 1th, 2017
2
+ ------------------------------
3
+ * Added new parameter "provider" to connection's configuration
4
+ * Added provider fractalgarden as new provider which support mqtt protocol. It offers free service, try it!
5
+ * LoraClient class is now extended by the provider's methods on the initialization. In the future, this will make it easier
6
+ to connect to multiple network servers.
7
+ * Several improvements
8
+
1
9
  v0.14.1 October 20th, 2017
2
10
  ------------------------------
3
11
  * Mqtt: method all_enqueued_downlink_id raise the custom exception EuiNotFound
data/lib/config/config.rb CHANGED
@@ -7,6 +7,8 @@ LoraRb.configure do |config|
7
7
  # config.host = 'localhost'
8
8
  # config.protocol = :http
9
9
  # config.host = 'eu72.resiot.io'
10
+ # A2a
11
+ config.provider = :a2a
10
12
  config.protocol = :mqtt
11
13
  config.host = 'ptnetsuite.a2asmartcity.io'
12
14
  config.port = 8883
@@ -23,4 +25,18 @@ LoraRb.configure do |config|
23
25
  ]
24
26
  config.ssl = true
25
27
  config.ssl_file = 'ssl_certificates/mqtt_ca.crt'
28
+ # Fractalgarden Free Network Server
29
+ # config.provider = :fractalgarden
30
+ # config.protocol = :mqtt
31
+ # config.host = '192.168.1.106'
32
+ # config.port = 1883
33
+ # config.uplink_url = 'application/{appid}/node/+/rx'
34
+ # config.downlink_url = 'application/{appid}/node/{deveui}/tx'
35
+ # config.timeout = 30.0
36
+ # # If you expect more than one response in a topic, ad a item with url=nil to not subscribe it newly
37
+ # config.downlink_response_urls = [
38
+ # { name: :queued, url: 'reply/{clientid}/id/{requestid}'},
39
+ # ]
40
+ # config.ssl = false
41
+ # # config.ssl_file = "#{Rails.root}/vendor/ssl_certificates/a2a_mqtt_ca.crt"
26
42
  end
@@ -8,12 +8,16 @@ defaults: &defaults
8
8
  #connector_id: "69643d32"
9
9
  # A2a
10
10
  #appid: "a1b2c3d4e5f60001"
11
- appid: "9956" # SSG dev
12
11
  token: "2B7E151628AED2A6ABF7158809CF4F3C"
12
+ appid: "9957"
13
13
  username: "fractalgarden"
14
14
  password: "fr4ctalg4rden"
15
+ # Fractalgarden
16
+ # appid: "1"
17
+ # username: "loraserver_gw"
18
+ # password: "loraserver_gw"
15
19
 
16
- test_eui: "be7a0000000010cf"
20
+ test_eui: "be7a00000000123c"
17
21
  #foo: add every variable you need and use it with => LoraRb::Settings.foo
18
22
  # bar: sub variable are accessible with hash => LoraRb::Settings.foo[:bar]
19
23
 
@@ -2,11 +2,12 @@ module LoraRb
2
2
  class Configuration
3
3
  # attr_writer :allow_sign_up
4
4
 
5
- attr_accessor :protocol, :host, :port, :uplink_url, :downlink_url, :downlink_response_urls, :ssl, :ssl_file, :env,
6
- :timeout, :enqueued_downlinks_url, :delete_enqueued_downlink_url
5
+ attr_accessor :provider, :protocol, :host, :port, :uplink_url, :downlink_url, :downlink_response_urls,
6
+ :ssl, :ssl_file, :env, :timeout, :enqueued_downlinks_url, :delete_enqueued_downlink_url
7
7
 
8
8
  def initialize
9
- @protocol = nil
9
+ @provider = nil #PROVIDERS.keys.first
10
+ @protocol = nil #PROVIDERS[@provider].first
10
11
  @host = nil
11
12
  @port = nil
12
13
  @uplink_url = nil
@@ -19,7 +20,6 @@ module LoraRb
19
20
  @env = 'development'
20
21
  @timeout = 10.0
21
22
  end
22
-
23
23
  end
24
24
 
25
25
  def self.configuration
data/lib/core/protocol.rb CHANGED
@@ -3,9 +3,19 @@ module LoraRb
3
3
  # It contains protocols methods
4
4
  class Protocol
5
5
 
6
- # Show tips on usage
7
- def self.supported_protocols
8
- %w(tls http rabbitmq mqtt)
6
+ PROVIDERS = { fractalgarden: [:mqtt],
7
+ a2a: [:mqtt],
8
+ loriot: [:tls],
9
+ resiot: [:http]
10
+ }
11
+
12
+ def self.provider_is_valid?(provider: LoraRb.configuration.provider)
13
+ PROVIDERS.has_key? provider
14
+ end
15
+ def self.supported?(provider: LoraRb.configuration.provider,
16
+ protocol: LoraRb.configuration.protocol)
17
+ return unless provider && protocol
18
+ PROVIDERS[provider] && PROVIDERS[provider].include?(protocol.to_sym)
9
19
  end
10
20
  end
11
21
  end
data/lib/lora-rb.rb CHANGED
@@ -26,16 +26,10 @@ require_relative 'lora-rb/base'
26
26
  unless defined?(Rails)
27
27
  require_relative 'config/config'
28
28
 
29
- connection_protocol = LoraRb.configuration.protocol
30
- raise "Define your protocol in the configuration file!" unless connection_protocol
31
- raise "Connection protocol #{connection_protocol} not recognized!" unless LoraRb::Protocol.supported_protocols.include?(connection_protocol.to_s)
32
- require_relative "lora-rb/#{connection_protocol}/call"
33
- LoraClient.include LoraRb::Call
34
-
35
29
  %w(private.yml).each do |file|
36
30
  filepath = File.join(LoraRb.root, 'lib', 'config', file)
37
31
  LoraRb::Settings.load!(filepath, env: LoraRb.configuration.env) if File.exist? filepath
38
32
  end
39
- raise "Insert your secret data to login on the lora cloud!" if LoraRb::Settings.appid.nil? || LoraRb::Settings.token.nil?
33
+ raise "Insert your secret data to login on the lora network server!" if LoraRb::Settings.appid.nil? || LoraRb::Settings.token.nil?
40
34
  end
41
35
 
@@ -10,27 +10,29 @@ module LoraRb
10
10
  def sub_initialize(options={})
11
11
  require 'mqtt'
12
12
 
13
- raise 'Specify uplink_url to continue!' unless options[:uplink_url]
14
- raise 'Specify downlink_url to continue!' unless options[:downlink_url]
13
+ raise 'Specify uplink_url to continue!' unless options[:uplink_url]
14
+ raise 'Specify downlink_url to continue!' unless options[:downlink_url]
15
15
  raise 'Specify downlink_response_urls to continue!' unless options[:downlink_response_urls]
16
- raise 'Specify host to continue!' unless options[:host]
17
- raise 'Specify port to continue!' unless options[:port]
18
- raise 'Specify username to continue!' unless options[:username]
19
- raise 'Specify password to continue!' unless options[:password]
20
- raise 'Specify ssl_file to continue!' if options[:ssl] && !options[:ssl_file]
16
+ raise 'Specify host to continue!' unless options[:host]
17
+ raise 'Specify port to continue!' unless options[:port]
18
+ raise 'Specify username to continue!' unless options[:username]
19
+ raise 'Specify password to continue!' unless options[:password]
20
+ raise 'Specify ssl_file to continue!' if options[:ssl] && !options[:ssl_file]
21
21
 
22
22
  @username = options[:username]
23
23
  @client_id = "#{@username}::ssg#{generate_request_id}"
24
24
 
25
- @client = MQTT::Client.connect(
25
+ connection_attributes = {
26
26
  host: options[:host],
27
27
  port: options[:port],
28
28
  ssl: options[:ssl],
29
- cert_file: options[:ssl_file],
30
29
  username: @username,
31
30
  password: options[:password],
32
31
  client_id: @client_id
33
- )
32
+ }
33
+ connection_attributes[:cert_file] = options[:ssl_file] if connection_attributes[:ssl]
34
+ # The class variable @@mock is set by the stubbed class. The other methods (send_cmd etc.) are entirely stubbed.
35
+ @client = MQTT::Client.connect(connection_attributes) unless defined?(@@mock) && @@mock
34
36
 
35
37
  @topic = merge_tags_to_url(options[:uplink_url],
36
38
  { username: @username,
@@ -56,9 +58,12 @@ module LoraRb
56
58
  "port": options[:port], # Port where the message should be sent
57
59
  "payload": options[:data], # Message payload
58
60
  "confirmed": options[:confirmed], # (Optional) Tells whether a confirmed downlink is requested. Default: false
59
- "window": options[:window] || "BOTH", # (Optional) Specifies which rx window should be used: RX1, RX2 or any(BOTH). Default: BOTH
60
- "priority": options[:priority] || 0, # (Optional) Message priority, used to sort messages in the queue. Default: 0
61
61
  }
62
+ # (Optional) Specifies which rx window should be used: RX1, RX2 or any(BOTH). Default: BOTH
63
+ h_request['window'] = options[:window] if options[:window]
64
+ # (Optional) Message priority, used to sort messages in the queue. Default: 0
65
+ h_request['priority'] = options[:priority] if options[:priority]
66
+
62
67
  request_id = generate_request_id
63
68
  publish_url = merge_tags_to_url(@downlink_url,
64
69
  username: @username,
data/lib/lora-rb/base.rb CHANGED
@@ -30,6 +30,14 @@ class LoraClient
30
30
 
31
31
  require 'philter'
32
32
  require 'securerandom'
33
+
34
+ raise "Specify your provider in the configuration file!" unless LoraRb.configuration.provider
35
+ raise "Specify the protocol in the configuration file!" unless LoraRb.configuration.protocol
36
+ raise "Provider #{LoraRb.configuration.provider} not defined!" unless LoraRb::Protocol.provider_is_valid?
37
+ raise "Connection protocol #{LoraRb.configuration.protocol} not supported by the provider #{LoraRb.configuration.provider}!" unless LoraRb::Protocol.supported?
38
+ require_relative "#{LoraRb.configuration.provider}/#{LoraRb.configuration.protocol}/call"
39
+ self.extend LoraRb::Call
40
+
33
41
  welcome_response = sub_initialize(options)
34
42
 
35
43
  raise("Lora-rb: Cannot connect to host #{options[:host]}:#{options[:port]}") unless welcome_response.key?('hello')
@@ -0,0 +1,187 @@
1
+ # LoraRb calling methods
2
+ module LoraRb
3
+ class EuiNotFound < StandardError; end
4
+ # It contains all the methods for selecting the items
5
+ module Call
6
+ attr_reader :client
7
+
8
+ private
9
+
10
+ def sub_initialize(options={})
11
+ require 'mqtt'
12
+
13
+ raise 'Specify uplink_url to continue!' unless options[:uplink_url]
14
+ raise 'Specify downlink_url to continue!' unless options[:downlink_url]
15
+ raise 'Specify downlink_response_urls to continue!' unless options[:downlink_response_urls]
16
+ raise 'Specify host to continue!' unless options[:host]
17
+ raise 'Specify port to continue!' unless options[:port]
18
+ raise 'Specify username to continue!' unless options[:username]
19
+ raise 'Specify password to continue!' unless options[:password]
20
+ raise 'Specify ssl_file to continue!' if options[:ssl] && !options[:ssl_file]
21
+
22
+ @username = options[:username]
23
+ @client_id = "#{@username}::ssg#{generate_request_id}"
24
+
25
+ connection_attributes = {
26
+ host: options[:host],
27
+ port: options[:port],
28
+ ssl: options[:ssl],
29
+ username: @username,
30
+ password: options[:password],
31
+ client_id: @client_id
32
+ }
33
+ connection_attributes[:cert_file] = options[:ssl_file] if connection_attributes[:ssl]
34
+ # The class variable @@mock is set by the stubbed class. The other methods (send_cmd etc.) are entirely stubbed.
35
+ @client = MQTT::Client.connect(connection_attributes) unless defined?(@@mock) && @@mock
36
+
37
+ @topic = merge_tags_to_url(options[:uplink_url],
38
+ { username: @username,
39
+ appid: @appid },
40
+ { debug: options[:debug] })
41
+
42
+ @downlink_url = options[:downlink_url]
43
+ @downlink_response_urls = options[:downlink_response_urls]
44
+ @enqueued_downlinks_url = options[:enqueued_downlinks_url]
45
+ @delete_enqueued_downlink_url = options[:delete_enqueued_downlink_url]
46
+ @timeout = options[:timeout]
47
+ @wait_response = options.has_key?(:wait_response) ? options[:wait_response] : true
48
+ {'hello' => 'Lora-Rb: Ready to start!'}
49
+ end
50
+
51
+ # Send the request to device
52
+ def sub_send_cmd(options={})
53
+ options = { wait_response: @wait_response }.merge(options)
54
+
55
+ request_id = generate_request_id
56
+ h_request = {
57
+ "fport": options[:port], # Port where the message should be sent
58
+ "data": options[:data], # Message payload
59
+ "confirmed": options[:confirmed], # (Optional) Tells whether a confirmed downlink is requested. Default: false
60
+ "devEUI": options[:eui],
61
+ "reference": request_id
62
+ }
63
+
64
+ publish_url = merge_tags_to_url(@downlink_url,
65
+ username: @username,
66
+ appid: @appid,
67
+ deveui: options[:eui],
68
+ clientid: @client_id,
69
+ requestid: request_id)
70
+
71
+ puts " publish #{h_request.to_json} to #{publish_url}" if options[:debug]
72
+ responses = []
73
+ response_topics = []
74
+ # thr_response = nil
75
+ if options[:wait_response]
76
+ @downlink_response_urls.each do |dru_hash|
77
+ name, response_url = dru_hash[:name], dru_hash[:url]
78
+ next unless response_url
79
+
80
+ # response_topic = "reply/#{@client_id}/id/#{request_id}"
81
+ response_topic = merge_tags_to_url(response_url,
82
+ username: @username,
83
+ appid: @appid,
84
+ deveui: options[:eui],
85
+ clientid: @client_id,
86
+ requestid: request_id)
87
+ puts " Subscribing response #{response_topic}" if options[:debug] == :full
88
+ response_topics << response_topic
89
+ end
90
+
91
+ raise "cannot subscribe without topic, response_topics is empty!" if response_topics.empty?
92
+ @client.subscribe(*response_topics)
93
+ end
94
+
95
+ @client.publish(publish_url, h_request.to_json, false)
96
+
97
+ if options[:wait_response]
98
+ # Waiting for all the responses
99
+ # thr_responses.each { |thr_response| thr_response.join }
100
+ # thr_response.join
101
+ @downlink_response_urls.each do |dru_hash|
102
+ response_topic, response_message = sub_read_data(topic: nil, debug: options[:debug])
103
+ response = { topic: response_topic, json: response_message }
104
+ puts " Found response #{response} " if options[:debug] == :full
105
+ responses << response
106
+ end
107
+
108
+ @client.unsubscribe(*response_topics)
109
+ end
110
+ responses
111
+ end
112
+
113
+ # Receive the payload from the network
114
+ # There is a timeout. Use this method only to retrieve data from the queue. If you have to waiting data
115
+ # please use listen.
116
+ # If topic is nil it uses subscribed topics
117
+ def sub_read_data(options={})
118
+ topic = options.has_key?(:topic) ? options[:topic] : @topic
119
+ if topic
120
+ topic = topic.dup
121
+ puts " Reading topic #{topic}..." if options[:debug]
122
+ end
123
+
124
+ message = nil
125
+ begin
126
+ Timeout.timeout(options[:timeout] || @timeout) do
127
+ topic, message = @client.get(topic)
128
+ end
129
+ rescue Timeout::Error
130
+ message = {error: 'Timeout'}.to_json
131
+ end
132
+
133
+ message = JSON.parse(message)
134
+ if message.respond_to? '[]'
135
+ eui = get_eui_from_topic(topic)
136
+ message['eui'] ||= eui if eui
137
+ port = get_port_from_topic(topic)
138
+ message['port'] ||= port if port
139
+ end
140
+ return topic, message
141
+ end
142
+
143
+ # Waiting for message in the queue
144
+ def sub_listen(options={}, &block)
145
+ topic = options.has_key?(:topic) ? options[:topic] : @topic
146
+ if topic
147
+ topic = topic.dup
148
+ puts " Waiting for messages in #{topic}. To exit press CTRL+C" if options[:debug]
149
+ end
150
+
151
+ @client.get(topic) do |topic, message|
152
+ # Block is executed for every message received
153
+ puts " original json: #{topic}: #{message}" if options[:debug] == :full
154
+ message = JSON.parse(message)
155
+ if message.respond_to? '[]'
156
+ eui = get_eui_from_topic(topic)
157
+ message['eui'] ||= eui if eui
158
+ port = get_port_from_topic(topic)
159
+ message['port'] ||= port if port
160
+ end
161
+ puts " #{message}" if options[:debug] #After reworking
162
+ block.call(topic, message) if block_given?
163
+ break if options[:test]
164
+ end
165
+ end
166
+
167
+ # Close the connection
168
+ def sub_quit
169
+ @client.disconnect
170
+ end
171
+
172
+ def get_eui_from_topic(topic)
173
+ res = topic&.match(/devices\/(\w{16})/)
174
+ res[1] if res
175
+ end
176
+
177
+ def get_port_from_topic(topic)
178
+ res = topic&.match(/uplink\/(\d+)(\/|\Z)/)
179
+ res[1] if res
180
+ end
181
+
182
+ def generate_request_id
183
+ "#{Time.now.strftime('%y%m%d%H%M%S')}#{SecureRandom.hex(1)}"
184
+ end
185
+
186
+ end
187
+ end
File without changes
File without changes
@@ -2,7 +2,6 @@
2
2
  module LoraRb
3
3
  # It contains generic methods
4
4
  module Base
5
- private
6
5
 
7
6
  # Show tips on usage
8
7
  def merge_tags_to_url(url, tags={}, options={})
@@ -17,6 +16,8 @@ module LoraRb
17
16
  end
18
17
  end
19
18
 
19
+ private
20
+
20
21
  def puts(message)
21
22
  Kernel.puts "[#{self.class.name}##{__method__}] #{Time.now} #{message}"
22
23
  end
data/lib/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module LoraRb
2
2
  def self.version
3
- "0.14.1"
3
+ "0.15.0"
4
4
  end
5
5
  def self.updated_at
6
- "2017-10-20"
6
+ "2017-11-01"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lora-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.1
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Mastrodonato
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-10-20 00:00:00.000000000 Z
14
+ date: 2017-11-01 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -32,6 +32,9 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '0.5'
37
+ - - ">="
35
38
  - !ruby/object:Gem::Version
36
39
  version: 0.5.0
37
40
  type: :runtime
@@ -39,6 +42,9 @@ dependencies:
39
42
  version_requirements: !ruby/object:Gem::Requirement
40
43
  requirements:
41
44
  - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.5'
47
+ - - ">="
42
48
  - !ruby/object:Gem::Version
43
49
  version: 0.5.0
44
50
  - !ruby/object:Gem::Dependency
@@ -46,6 +52,9 @@ dependencies:
46
52
  requirement: !ruby/object:Gem::Requirement
47
53
  requirements:
48
54
  - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '1.2'
57
+ - - ">="
49
58
  - !ruby/object:Gem::Version
50
59
  version: 1.2.0
51
60
  type: :runtime
@@ -53,6 +62,9 @@ dependencies:
53
62
  version_requirements: !ruby/object:Gem::Requirement
54
63
  requirements:
55
64
  - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.2'
67
+ - - ">="
56
68
  - !ruby/object:Gem::Version
57
69
  version: 1.2.0
58
70
  - !ruby/object:Gem::Dependency
@@ -91,12 +103,13 @@ files:
91
103
  - lib/core/protocol.rb
92
104
  - lib/generators/install_generator.rb
93
105
  - lib/lora-rb.rb
106
+ - lib/lora-rb/a2a/mqtt/call.rb
94
107
  - lib/lora-rb/base.rb
108
+ - lib/lora-rb/fractalgarden/mqtt/call.rb
109
+ - lib/lora-rb/fractalgarden/rabbitmq/call.rb
95
110
  - lib/lora-rb/help.rb
96
- - lib/lora-rb/http/call.rb
97
- - lib/lora-rb/mqtt/call.rb
98
- - lib/lora-rb/rabbitmq/call.rb
99
- - lib/lora-rb/tls/call.rb
111
+ - lib/lora-rb/loriot/tls/call.rb
112
+ - lib/lora-rb/resiot/http/call.rb
100
113
  - lib/lora-rb/utility.rb
101
114
  - lib/vendor/deep_symbolize.rb
102
115
  - lib/version.rb