lora-rb 0.8.0 → 0.9.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: 2e741ccd715377f07a8ffbbb22fe91f833ccec4a
4
- data.tar.gz: 4d02bcf8d4b566e6c182ed2f63cb6a99080a8cc2
3
+ metadata.gz: 213844df0c3f518068ec280585bcd4c3a8d6b5df
4
+ data.tar.gz: 6ab538fa6d2dfdccc730908be73c580793900894
5
5
  SHA512:
6
- metadata.gz: c37b0380a04d8bc486e5269d4910c416564ab2c35b8838f35ff4d649cbf90661980a40c22ae16c4b8c0c7932ac92abee486058853e606a569e37e68bfe296423
7
- data.tar.gz: 7d2d70038ada006a99eeefd2322905c756c4adb9f0b6e48160c104724263fdb0eea5a479127b9c2e758c6d1c8e00fcad2b1ae0011d894b85fb8f67bd406984c7
6
+ metadata.gz: f726dc55bed3ee0c18a15e62132216161aa55506a2eddaec0a0025c15c899016724d1fc8d000573f1090ac8f91ff5b28700f32f04d796287a0e3f561b104280c
7
+ data.tar.gz: b87fca2f73d4e4d5a5092bf197f4fcbaa83c2ee8f12c65537a9d472a97cb3ff8c91de8b8e000d270e840929ffa7373efde4290bec4718f1a44904b6f8bab6dad
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ v0.9.0 [☰](https://bitbucket.org/fractalgarden/loriot-rb/branches/compare/v0.8.0..v0.9.0) August 7th, 2017
2
+ ------------------------------
3
+ * Mqtt protocol renamed to Rabbitmq and new generic mqtt protocol added
4
+ * Mqtt protocol now support tls
5
+ * Now support the italian lora network A2a Smart City
6
+ * Configuration params updated to meet the mqtt requirements
7
+ * Updated readme
8
+
1
9
  v0.8.0 [☰](https://bitbucket.org/fractalgarden/loriot-rb/branches/compare/v0.7.0..v0.8.0) July 11th, 2017
2
10
  ------------------------------
3
11
  * Send_cmd now accept param confirmed true/false
data/README.md CHANGED
@@ -23,7 +23,94 @@ To use it in a bundle, add to gem file `gem 'lora-rb'` and run `bundle install`
23
23
 
24
24
  Establish a secure connection to your `Lora Application` on the cloud.
25
25
 
26
- This version only support the TLS protocol.
26
+ This version supports:
27
+ 1. TLS protocol with [Loriot](http://loriot.io)
28
+ 1. Http push with [Resiot](http://resiot.io)
29
+ 1. MQTT with [A2aSmartCity](http://www.a2asmartcity.io/)
30
+
31
+ ## Configuration
32
+
33
+ Insert private information in the yaml:
34
+
35
+ lib/config/private.yml
36
+
37
+ and the configuration's parameter in the config file.
38
+
39
+ lib/config/config.rb
40
+
41
+ If you are using rails you can use the generator:
42
+
43
+ bundle exec rails generate lora_rb:install
44
+
45
+ Every provider assign you a token and an appkey or an appid. Insert your secret data in the yaml:
46
+
47
+ ```yaml
48
+ defaults:
49
+ appid:
50
+ token:
51
+ # Some provider may use it
52
+ username:
53
+ password:
54
+ connector_id:
55
+ ```
56
+
57
+ If you are using Rails 5.1 you can do something like this:
58
+
59
+ ```yaml
60
+ defaults: &defaults
61
+ appid: <%= Rails.application.secrets.lora_appid %>
62
+ token: <%= Rails.application.secrets.lora_token %>
63
+ # etc ...
64
+ ```
65
+
66
+ ### TLS (with Loriot)
67
+
68
+ ```ruby
69
+ LoraRb.configure do |config|
70
+ # These informations are shared for all environments
71
+ config.protocol = :tls
72
+ config.host = 'eu1.loriot.io'
73
+ config.port = 737
74
+ end
75
+ ```
76
+
77
+ ### HTTP (with Resiot)
78
+
79
+ ```ruby
80
+ LoraRb.configure do |config|
81
+ # These informations are shared for all environments
82
+ config.protocol = :http
83
+ config.host = 'eu72.resiot.io'
84
+ config.port = 80
85
+ end
86
+ ```
87
+
88
+ ### RABBITMQ
89
+
90
+ ```ruby
91
+ LoraRb.configure do |config|
92
+ # These informations are shared for all environments
93
+ config.protocol = :rabbitmq
94
+ config.host = 'localhost'
95
+ end
96
+ ```
97
+
98
+ ### MQTT (with A2a)
99
+
100
+ ```ruby
101
+ LoraRb.configure do |config|
102
+ # These informations are shared for all environments
103
+ config.protocol = :mqtt
104
+ config.host = 'ptnetsuite.a2asmartcity.io'
105
+ config.port = 8883
106
+ config.uplink_url = '/sub/v1/users/{username}/apps/{appid}/devices/+/uplink/+'
107
+ config.downlink_url = '/api/v1/users/{username}/apps/{appid}/devices/{deveui}/downlink/post/reply/{clientid}/id/{requestid}'
108
+ config.ssl = true
109
+ config.ssl_file = 'ssl_certificates/mqtt_ca.crt'
110
+ end
111
+ ```
112
+
113
+ ## Usage
27
114
 
28
115
  From irb require the library:
29
116
 
@@ -37,10 +124,10 @@ then create an instance
37
124
  lora = LoraClient.new
38
125
  ```
39
126
 
40
- if you are in debug mode you should also receive a json:
127
+ you should receive the instance with variables depending on protocol:
41
128
 
42
- ```json
43
- { "hello":"LORIOT.io TLS Server", "version":"1.0.4" }
129
+ ```
130
+ #<LoraClient:0x0056318ad8e048 ...
44
131
  ```
45
132
 
46
133
  ### Send data to a device
@@ -102,6 +189,9 @@ To use it in a bundle, add to gem file `gem 'lora-rb'` and run `bundle install`
102
189
  - [x] Organization in modules to support new protocols `v0.2.0`
103
190
  - [x] Add a configuration `v0.3.0`
104
191
  - [x] Add a rails generator `v0.3.0`
192
+ - [x] Add http push support `v0.5.0`
193
+ - [x] Add RabbitMq support `v0.6.0`
194
+ - [x] Add Mqtt support `v0.9.0`
105
195
  - [ ] Test with many devices
106
196
 
107
197
  ## Contributing
data/lib/config/config.rb CHANGED
@@ -3,8 +3,15 @@ LoraRb.configure do |config|
3
3
  # config.protocol = :tls
4
4
  # config.host = 'eu1.loriot.io'
5
5
  # config.port = 737
6
- # config.protocol = :mqtt
6
+ # config.protocol = :rabbitmq
7
7
  # config.host = 'localhost'
8
- config.protocol = :http
9
- config.host = 'eu72.resiot.io'
8
+ # config.protocol = :http
9
+ # config.host = 'eu72.resiot.io'
10
+ config.protocol = :mqtt
11
+ config.host = 'ptnetsuite.a2asmartcity.io'
12
+ config.port = 8883
13
+ config.uplink_url = '/sub/v1/users/{username}/apps/{appid}/devices/+/uplink/+'
14
+ config.downlink_url = '/api/v1/users/{username}/apps/{appid}/devices/{deveui}/downlink/post/reply/{clientid}/id/{requestid}'
15
+ config.ssl = true
16
+ config.ssl_file = 'ssl_certificates/mqtt_ca.crt'
10
17
  end
@@ -1,11 +1,19 @@
1
1
  defaults: &defaults
2
+ # Loriot
2
3
  #appid: "BE7A02C1"
3
- appid: "a1b2c3d4e5f60001"
4
4
  #token: "zHcD-1ouz3ytyOLE6SMhwA"
5
- token: "17e3ce759c444b3977f4adbf9dd0e010"
6
- # Some provider may use it
7
- connector_id: "69643d32"
8
- test_eui: "BE7A00000000123C"
5
+ # Resiot
6
+ #appid: "a1b2c3d4e5f60001"
7
+ #token: "17e3ce759c444b3977f4adbf9dd0e010"
8
+ #connector_id: "69643d32"
9
+ # A2a
10
+ #appid: "a1b2c3d4e5f60001"
11
+ appid: "9955"
12
+ token: "2B7E151628AED2A6ABF7158809CF4F3C"
13
+ username: "fractalgarden"
14
+ password: "fr4ctalg4rden"
15
+
16
+ test_eui: "be7a00000000123c"
9
17
  #foo: add every variable you need and use it with => LoraRb::Settings.foo
10
18
  # bar: sub variable are accessible with hash => LoraRb::Settings.foo[:bar]
11
19
 
@@ -3,6 +3,8 @@ defaults: &defaults
3
3
  appid:
4
4
  token:
5
5
  # Some provider may use it
6
+ username:
7
+ password:
6
8
  connector_id:
7
9
  # Insert your device for test purpose
8
10
  test_eui:
data/lib/core/base.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'json'
2
2
  require 'socket'
3
3
  require 'openssl'
4
- require 'http'
5
- require 'bunny'
6
4
 
7
5
  require_relative 'configuration'
8
6
  require_relative 'configuration_dynamic'
@@ -2,12 +2,15 @@ module LoraRb
2
2
  class Configuration
3
3
  # attr_writer :allow_sign_up
4
4
 
5
- attr_accessor :protocol, :host, :port, :env
5
+ attr_accessor :protocol, :host, :port, :uplink_url, :downlink_url, :ssl, :ssl_file, :env
6
6
 
7
7
  def initialize
8
8
  @protocol = nil
9
9
  @host = nil
10
10
  @port = nil
11
+ @url = nil
12
+ @ssl = nil # True if uses tls
13
+ @ssl_file = nil # The certificate's path
11
14
  @env = 'development'
12
15
  end
13
16
 
data/lib/core/protocol.rb CHANGED
@@ -5,7 +5,7 @@ module LoraRb
5
5
 
6
6
  # Show tips on usage
7
7
  def self.supported_protocols
8
- %w(tls http mqtt)
8
+ %w(tls http rabbitmq mqtt)
9
9
  end
10
10
  end
11
11
  end
@@ -16,7 +16,7 @@ module LoraRb
16
16
  <<-FILE.gsub(/^ /, '')
17
17
  connection_protocol = LoraRb.configuration.protocol
18
18
  raise 'Define your protocol in the configuration file!' unless connection_protocol
19
- raise "Connection protocol #{connection_protocol} not recognized!" unless %w(tls).include?(connection_protocol.to_s)
19
+ raise "Connection protocol #{connection_protocol} not recognized!" unless LoraRb::Protocol.supported_protocols.include?(connection_protocol.to_s)
20
20
  require "lora-rb/#{connection_protocol}/call"
21
21
  LoraClient.include LoraRb::Call
22
22
 
data/lib/lora-rb/base.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'help'
2
+ require_relative 'utility'
2
3
 
3
4
  ###################################
4
5
  # An interface to Lora Service from Ruby
@@ -8,11 +9,16 @@ class LoraClient
8
9
 
9
10
  # Establish a secure connection to your account on the cloud
10
11
  def initialize(options = {})
11
- options = { debug: false,
12
- token: LoraRb::Settings.token,
13
- appid: LoraRb::Settings.appid,
14
- host: LoraRb.configuration.host,
15
- port: LoraRb.configuration.port }.merge(options)
12
+ options = {debug: false,
13
+ token: LoraRb::Settings.token,
14
+ appid: LoraRb::Settings.appid,
15
+ host: LoraRb.configuration.host,
16
+ port: LoraRb.configuration.port,
17
+ uplink_url: LoraRb.configuration.uplink_url,
18
+ downlink_url: LoraRb.configuration.downlink_url,
19
+ ssl: LoraRb.configuration.ssl,
20
+ ssl_file: LoraRb.configuration.ssl_file
21
+ }.merge(options)
16
22
  @debug = options[:debug]
17
23
  @token = options[:token]
18
24
  @appid = options[:appid]
@@ -54,7 +60,7 @@ class LoraClient
54
60
  def listen(options = {}, &block)
55
61
  options = { debug: @debug }.merge(options)
56
62
 
57
- puts "#{Time.now} Starting Listen #{@appid}. To exit press CTRL+C" if options[:debug]
63
+ puts "#{Time.now} Starting Listen app #{@appid}. To exit press CTRL+C" if options[:debug]
58
64
  sub_listen(options)
59
65
  end
60
66
 
@@ -6,6 +6,7 @@ module LoraRb
6
6
  private
7
7
 
8
8
  def sub_initialize(options={})
9
+ require 'http'
9
10
  @host = options[:host]
10
11
  {'hello' => 'Lora-Rb: Ready to start!'}
11
12
  end
@@ -8,48 +8,117 @@ module LoraRb
8
8
  private
9
9
 
10
10
  def sub_initialize(options={})
11
- @connection = Bunny.new(hostname: options[:host])
12
- @connection.start
13
- @channel = @connection.create_channel
14
- @queue = @channel.queue(options[:queue])
11
+ require 'mqtt'
12
+
13
+ raise 'Specify aaa to continue!' unless options[:uplink_url]
14
+ raise 'Specify aaa to continue!' unless options[:downlink_url]
15
+ raise 'Specify aaa to continue!' unless options[:host]
16
+ raise 'Specify aaa to continue!' unless options[:port]
17
+ raise 'Specify ssl_file to continue!' if options[:ssl] && !options[:ssl_file]
18
+
19
+ @username = LoraRb::Settings.username
20
+ password = LoraRb::Settings.password
21
+ @client_id = "#{@username}::ssg#{generate_request_id}"
22
+
23
+ @client = MQTT::Client.connect(
24
+ host: options[:host],
25
+ port: options[:port],
26
+ ssl: options[:ssl],
27
+ cert_file: options[:ssl_file],
28
+ username: @username,
29
+ password: password,
30
+ client_id: @client_id
31
+ )
32
+
33
+ @topic = merge_tags_to_url(options[:uplink_url],
34
+ { username: @username,
35
+ appid: @appid },
36
+ { debug: options[:debug] })
37
+
38
+ @downlink_url = merge_tags_to_url(options[:downlink_url])
15
39
  {'hello' => 'Lora-Rb: Ready to start!'}
16
40
  end
17
41
 
18
42
  # Send the request to device
19
43
  def sub_send_cmd(options={})
20
- str_request = "{\"cmd\":\"#{options[:cmd]}\",\"EUI\":\"#{options[:eui]}\",\"port\":#{options[:port]},\"confirmed\":#{options[:confirmed]},\"data\":\"#{options[:data]}\"} "
21
- puts "#{Time.now} Cmq request: #{str_request}" if options[:debug]
22
- response = @channel.default_exchange.publish(str_request, routing_key: @queue.name)
23
- puts " [x] Sent '#{str_request}'" if options[:debug]
44
+ h_request = {
45
+ "port": options[:port], # Port where the message should be sent
46
+ "payload": options[:data], # Message payload
47
+ "confirmed": options[:confirmed], # (Optional) Tells whether a confirmed downlink is requested. Default: false
48
+ "window": options[:window] || "BOTH", # (Optional) Specifies which rx window should be used: RX1, RX2 or any(BOTH). Default: BOTH
49
+ "priority": options[:priority] || 0, # (Optional) Message priority, used to sort messages in the queue. Default: 0
50
+ "qos": options[:qos] || 1 # (Optional) Quality Of Service:
51
+ # 0 - Best effort. The message will be transmitted to the devices
52
+ # of the group that satisfy the multicast profile requirements
53
+ # (they should have been activated and have sent at least one
54
+ # uplink, they should be class C devices, etc..).
55
+ # 1 - Transmission guaranteed. No message will be transmitted if
56
+ # some devices do not satisfy the multicast profile requirements.
57
+ # Default: 1 */
58
+ }
59
+ request_id = generate_request_id
60
+ publish_url = merge_tags_to_url(@downlink_url,
61
+ username: @username,
62
+ appid: @appid,
63
+ deveui: options[:eui],
64
+ clientid: @client_id,
65
+ requestid: request_id)
66
+
67
+ puts "#{Time.now} publish #{h_request.to_json} to #{publish_url}" if options[:debug]
68
+
69
+ response = @client.publish(publish_url, h_request.to_json, false)
70
+ puts " [x] publish response: #{response}" if options[:debug]
71
+
72
+ if options[:confirmed]
73
+ response_topic = "reply/#{@client_id}/id/#{request_id}"
74
+ puts " [x] Waiting response on #{response_topic} ..." if options[:debug]
75
+ response_topic, response = sub_read_data(topic: response_topic)
76
+ puts " [x] Topic response: #{response}" if options[:debug]
77
+ end
24
78
  response
25
79
  end
26
80
 
27
81
  # Receive the payload from the network
28
82
  def sub_read_data(options={})
29
- delivery_info, metadata, payload = @queue.pop
30
- puts " [x] Received #{delivery_info} #{metadata} #{payload}" if options[:debug]
83
+ topic = options[:topic] || @topic
84
+ puts " [x] Reading topic #{topic}..." if options[:debug]
85
+ topic, message = @client.get(topic)
86
+ message = JSON.parse(message)
87
+ message['EUI'] ||= get_eui_from_topic(topic) if message.respond_to? '[]'
88
+ puts " [x] #{topic}: #{message}" if options[:debug]
89
+ return topic, message
31
90
  end
32
91
 
33
92
  # Waiting for message in the queue
34
93
  def sub_listen(options={}, &block)
35
- puts " [*] Waiting for messages in #{@queue.name}. To exit press CTRL+C" if options[:debug]
36
- @queue.subscribe(block: true) do |delivery_info, properties, body|
37
- puts " [x] Received #{body}" if options[:debug]
38
- block.call(delivery_info, properties, body) if block
39
- # cancel the consumer to exit
40
- delivery_info.consumer.cancel
94
+ topic = options[:topic] || @topic
95
+ puts " [*] Waiting for messages in #{topic}. To exit press CTRL+C" if options[:debug]
96
+
97
+ @client.get(topic) do |topic, message|
98
+ # Block is executed for every message received
99
+ puts " [x] #{topic}: #{message}" if options[:debug]
100
+ message = JSON.parse(message)
101
+ message['EUI'] ||= get_eui_from_topic(topic) if message.respond_to? '[]'
102
+ puts " [x] after rework: #{message}" if options[:debug]
103
+ block.call(topic, message) if block
104
+ break if options[:test]
41
105
  end
42
106
  end
43
107
 
44
108
  # Close the connection
45
109
  def sub_quit
46
- @connection.close
110
+ @client.disconnect
47
111
  end
48
112
 
49
- end
50
- end
113
+ private
114
+
115
+ def get_eui_from_topic(topic)
116
+ topic&.match(/(?!devices\/)\w{16}/)&.to_s
117
+ end
118
+
119
+ def generate_request_id
120
+ Time.now.strftime('%y%m%d%H%M%S')
121
+ end
51
122
 
52
- # Monkey patch since Bunny use the rails method .empty?
53
- class NilClass
54
- def empty?; true end
123
+ end
55
124
  end
@@ -0,0 +1,57 @@
1
+ # LoraRb calling methods
2
+ module LoraRb
3
+ # It contains all the methods for selecting the items
4
+ module Call
5
+
6
+ attr_reader :client
7
+
8
+ private
9
+
10
+ def sub_initialize(options={})
11
+ require 'bunny'
12
+ @connection = Bunny.new(hostname: options[:host])
13
+ @connection.start
14
+ @channel = @connection.create_channel
15
+ @queue = @channel.queue(options[:queue])
16
+ {'hello' => 'Lora-Rb: Ready to start!'}
17
+ end
18
+
19
+ # Send the request to device
20
+ def sub_send_cmd(options={})
21
+ str_request = "{\"cmd\":\"#{options[:cmd]}\",\"EUI\":\"#{options[:eui]}\",\"port\":#{options[:port]},\"confirmed\":#{options[:confirmed]},\"data\":\"#{options[:data]}\"} "
22
+ puts "#{Time.now} Cmq request: #{str_request}" if options[:debug]
23
+ response = @channel.default_exchange.publish(str_request, routing_key: @queue.name)
24
+ puts " [x] Sent '#{str_request}'" if options[:debug]
25
+ response
26
+ end
27
+
28
+ # Receive the payload from the network
29
+ def sub_read_data(options={})
30
+ delivery_info, metadata, payload = @queue.pop
31
+ puts " [x] Received #{delivery_info} #{metadata} #{payload}" if options[:debug]
32
+ return delivery_info, metadata, payload
33
+ end
34
+
35
+ # Waiting for message in the queue
36
+ def sub_listen(options={}, &block)
37
+ puts " [*] Waiting for messages in #{@queue.name}. To exit press CTRL+C" if options[:debug]
38
+ @queue.subscribe(block: true) do |delivery_info, properties, body|
39
+ puts " [x] Received #{body}" if options[:debug]
40
+ block.call(delivery_info, properties, body) if block
41
+ # cancel the consumer to exit
42
+ delivery_info.consumer.cancel
43
+ end
44
+ end
45
+
46
+ # Close the connection
47
+ def sub_quit
48
+ @connection.close
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ # Monkey patch since Bunny use the rails method .empty?
55
+ class NilClass
56
+ def empty?; true end
57
+ end
@@ -0,0 +1,18 @@
1
+ # LoraRb methods
2
+ module LoraRb
3
+ # It contains generic methods
4
+ module Base
5
+ private
6
+
7
+ # Show tips on usage
8
+ def merge_tags_to_url(url, tags={}, options={})
9
+ puts "merge_tags_to_url: #{url}" if options[:debug]
10
+ tags.each do |tag, value|
11
+ puts " replace {#{tag}} with #{value}" if options[:debug]
12
+ url.gsub!("{#{tag}}", value.to_s)
13
+ end
14
+ puts "merge_tags_to_url: completed #{url}" if options[:debug]
15
+ url
16
+ end
17
+ end
18
+ end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module LoraRb
2
2
  def self.version
3
- "0.8.0"
3
+ "0.9.0"
4
4
  end
5
5
  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.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Mastrodonato
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-06-29 00:00:00.000000000 Z
13
+ date: 2017-08-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -26,48 +26,6 @@ dependencies:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
28
  version: '2.1'
29
- - !ruby/object:Gem::Dependency
30
- name: openssl
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - "~>"
34
- - !ruby/object:Gem::Version
35
- version: '2.0'
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - "~>"
41
- - !ruby/object:Gem::Version
42
- version: '2.0'
43
- - !ruby/object:Gem::Dependency
44
- name: http
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '2.2'
50
- type: :runtime
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - "~>"
55
- - !ruby/object:Gem::Version
56
- version: '2.2'
57
- - !ruby/object:Gem::Dependency
58
- name: bunny
59
- requirement: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - "~>"
62
- - !ruby/object:Gem::Version
63
- version: '2.7'
64
- type: :runtime
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - "~>"
69
- - !ruby/object:Gem::Version
70
- version: '2.7'
71
29
  - !ruby/object:Gem::Dependency
72
30
  name: test-unit
73
31
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +66,9 @@ files:
108
66
  - lib/lora-rb/help.rb
109
67
  - lib/lora-rb/http/call.rb
110
68
  - lib/lora-rb/mqtt/call.rb
69
+ - lib/lora-rb/rabbitmq/call.rb
111
70
  - lib/lora-rb/tls/call.rb
71
+ - lib/lora-rb/utility.rb
112
72
  - lib/vendor/deep_symbolize.rb
113
73
  - lib/version.rb
114
74
  homepage: https://github.com/marcomd/lora-rb