aws_iot_device 0.1.0
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 +7 -0
- data/.gitignore +51 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/README.md +175 -0
- data/Rakefile +6 -0
- data/aws_iot_device.gemspec +39 -0
- data/bin/console +11 -0
- data/bin/setup +7 -0
- data/lib/aws_iot_device.rb +7 -0
- data/lib/aws_iot_device/mqtt_adapter.rb +32 -0
- data/lib/aws_iot_device/mqtt_adapter/client.rb +139 -0
- data/lib/aws_iot_device/mqtt_adapter/mqtt_adapter.rb +139 -0
- data/lib/aws_iot_device/mqtt_adapter/ruby_mqtt_adapter.rb +176 -0
- data/lib/aws_iot_device/mqtt_shadow_client.rb +6 -0
- data/lib/aws_iot_device/mqtt_shadow_client/json_payload_parser.rb +34 -0
- data/lib/aws_iot_device/mqtt_shadow_client/mqtt_manager.rb +135 -0
- data/lib/aws_iot_device/mqtt_shadow_client/shadow_action_manager.rb +235 -0
- data/lib/aws_iot_device/mqtt_shadow_client/shadow_client.rb +60 -0
- data/lib/aws_iot_device/mqtt_shadow_client/shadow_topic_manager.rb +50 -0
- data/lib/aws_iot_device/mqtt_shadow_client/token_creator.rb +32 -0
- data/lib/aws_iot_device/mqtt_shadow_client/topic_builder.rb +50 -0
- data/lib/aws_iot_device/version.rb +3 -0
- data/samples/mqtt_client_samples/mqtt_client_samples.rb +90 -0
- data/samples/shadow_action_samples/sample_shadow_action_update.rb +79 -0
- data/samples/shadow_client_samples/samples_shadow_client_delete.rb +73 -0
- data/samples/shadow_client_samples/samples_shadow_client_get.rb +74 -0
- data/samples/shadow_client_samples/samples_shadow_client_update.rb +81 -0
- data/samples/shadow_topic_samples/sample_topic_manager.rb +77 -0
- metadata +186 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'aws_iot_device/mqtt_shadow_client/topic_builder'
|
2
|
+
|
3
|
+
module AwsIotDevice
|
4
|
+
module MqttShadowClient
|
5
|
+
class ShadowTopicManager
|
6
|
+
|
7
|
+
def initialize(mqtt_manager)
|
8
|
+
if mqtt_manager.nil?
|
9
|
+
raise "TopicAction_error: TopicAction should be initialized with a mqtt_manager but was undefined"
|
10
|
+
end
|
11
|
+
@mqtt_manager = mqtt_manager
|
12
|
+
@sub_unsub_mutex = Mutex.new()
|
13
|
+
end
|
14
|
+
|
15
|
+
def client_id
|
16
|
+
@mqtt_manager.client_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def shadow_topic_publish(shadow_name, shadow_action, payload)
|
20
|
+
topic = TopicBuilder.new(shadow_name, shadow_action)
|
21
|
+
@mqtt_manager.publish(topic.get_topic_general, payload, false, 0)
|
22
|
+
end
|
23
|
+
|
24
|
+
def shadow_topic_subscribe(shadow_name, shadow_action, callback=nil)
|
25
|
+
@sub_unsub_mutex.synchronize(){
|
26
|
+
topic = TopicBuilder.new(shadow_name, shadow_action)
|
27
|
+
if topic.is_delta?(shadow_action)
|
28
|
+
@mqtt_manager.subscribe(topic.get_topic_delta, 0, callback)
|
29
|
+
else
|
30
|
+
@mqtt_manager.subscribe(topic.get_topic_accepted, 0, callback)
|
31
|
+
@mqtt_manager.subscribe(topic.get_topic_rejected, 0, callback)
|
32
|
+
end
|
33
|
+
}
|
34
|
+
sleep 2
|
35
|
+
end
|
36
|
+
|
37
|
+
def shadow_topic_unsubscribe(shadow_name, shadow_action)
|
38
|
+
@sub_unsub_mutex.synchronize(){
|
39
|
+
topic = TopicBuilder.new(shadow_name, shadow_action)
|
40
|
+
if topic.is_delta?(shadow_name)
|
41
|
+
@mqtt_manager.unsubscribe(topic.get_topic_delta)
|
42
|
+
else
|
43
|
+
@mqtt_manager.unsubscribe(topic.get_topic_accepted)
|
44
|
+
@mqtt_manager.unsubscribe(topic.get_topic_rejected)
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'timers'
|
3
|
+
require 'thread'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module AwsIotDevice
|
7
|
+
module MqttShadowClient
|
8
|
+
class TokenCreator
|
9
|
+
### This class manage the clients token.
|
10
|
+
### Every actions receive a token for a certian interval, meaning that action is waiting to be proceed.
|
11
|
+
### When token time run out or the actions have been treated token should deleted.
|
12
|
+
|
13
|
+
def initialize(shadow_name, client_id)
|
14
|
+
@shadow_name = shadow_name
|
15
|
+
@client_id = client_id
|
16
|
+
@sequence_number = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_next_token
|
20
|
+
token = ""
|
21
|
+
token << "#{@client_id}" << "_" << "#{@shadow_name}" << "_" << "#{@sequence_number}" << "_" << "#{random_token_string(5)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def random_token_string(lenght)
|
27
|
+
charset = Array('A'..'Z') + Array('a'..'z') + Array('0'..'9')
|
28
|
+
Array.new(lenght) { charset.sample }.join
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module AwsIotDevice
|
2
|
+
module MqttShadowClient
|
3
|
+
class TopicBuilder
|
4
|
+
ACTION_NAME = %w(get update delete delta).freeze
|
5
|
+
|
6
|
+
def initialize(shadow_name, action_name)
|
7
|
+
unless ACTION_NAME.include?(action_name)
|
8
|
+
raise "action_name_error: unreconized action_name \"#{action_name}\""
|
9
|
+
end
|
10
|
+
|
11
|
+
if shadow_name.nil?
|
12
|
+
raise "shadow_name_error: shadow_name is required but undefined"
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
@shadow_name = shadow_name
|
17
|
+
@action_name = action_name
|
18
|
+
|
19
|
+
### The case of delta's action
|
20
|
+
if is_delta?(action_name)
|
21
|
+
@topic_delta = "$aws/things/#{shadow_name}/shadow/update/delta"
|
22
|
+
else
|
23
|
+
@topic_general = "$aws/things/#{shadow_name}/shadow/#{action_name}"
|
24
|
+
@topic_accepted = "$aws/things/#{shadow_name}/shadow/#{action_name}/accepted"
|
25
|
+
@topic_rejected = "$aws/things/#{shadow_name}/shadow/#{action_name}/rejected"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def is_delta?(action_name)
|
30
|
+
action_name == ACTION_NAME[3]
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_topic_general
|
34
|
+
@topic_general
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_topic_accepted
|
38
|
+
@topic_accepted
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_topic_rejected
|
42
|
+
@topic_rejected
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_topic_delta
|
46
|
+
@topic_delta
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'aws_iot_device'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
options = {}
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Basic usage basic_greeting.rb -c \"YOUR_CERTIFICATE_PATH\" -k \"YOUR_KEY_FILE_PATH\" -ca \"YOUR_ROOT_CA_PATH -H \"YOUR_ENDPOINT\" -p 8883\n"
|
8
|
+
|
9
|
+
opts.separator ""
|
10
|
+
opts.separator "Common options"
|
11
|
+
opts.on_tail("-h", "--help", "--usage", "Show this message") do
|
12
|
+
puts opts
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on("-H", "--host [END_POINT]", "The endpoint where you want to connect") do |host|
|
17
|
+
options[:host] = host
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-p", "--port [MQTT_PORT]", "The port used for the connection Default is 8883") do |port|
|
21
|
+
options[:port] = port
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-c", "--cert [CERT_FILE_PATH]", "The path to the certificate file of the private key.") do |cert|
|
25
|
+
options[:cert] = cert
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-k", "--key [KEY_FILE_PATH]", "The path to private key file that would be used for encryption") do |key|
|
29
|
+
options[:key] = key
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-a", "--root_ca [ROOT_CA_PATH]", "The path to the authority certification file") do |root_ca|
|
33
|
+
options[:root_ca] = root_ca
|
34
|
+
end
|
35
|
+
end.parse!(ARGV)
|
36
|
+
|
37
|
+
|
38
|
+
host = options[:host]
|
39
|
+
port = options[:port] || 8883
|
40
|
+
cert_file_path = options[:cert]
|
41
|
+
key_file_path = options[:key]
|
42
|
+
ca_file_path = options[:root_ca]
|
43
|
+
|
44
|
+
client = AwsIotDevice::MqttShadowClient::MqttManager.new(host: host,
|
45
|
+
port: port,
|
46
|
+
ssl: true,
|
47
|
+
cert_file: cert_file_path,
|
48
|
+
key_file: key_file_path,
|
49
|
+
ca_file: ca_file_path)
|
50
|
+
|
51
|
+
client2 = AwsIotDevice::MqttShadowClient::MqttManager.new
|
52
|
+
|
53
|
+
client2.config_endpoint(host, port)
|
54
|
+
client2.ssl = true
|
55
|
+
client2.config_ssl_context(ca_file_path, key_file_path, cert_file_path)
|
56
|
+
|
57
|
+
client.connect()
|
58
|
+
client2.connect()
|
59
|
+
|
60
|
+
callback = Proc.new do |message|
|
61
|
+
p " Client1 catch message event"
|
62
|
+
p "--- Topic: #{message.topic}"
|
63
|
+
p "--- Payload: #{message.payload}"
|
64
|
+
end
|
65
|
+
|
66
|
+
callback2 = Proc.new do |message|
|
67
|
+
p " Client2 catch message event"
|
68
|
+
p "--- Topic: #{message.topic}"
|
69
|
+
p "--- Payload: #{message.payload}"
|
70
|
+
end
|
71
|
+
|
72
|
+
client.subscribe("topic_2", 0, callback)
|
73
|
+
client2.subscribe("topic_1", 0,callback2)
|
74
|
+
|
75
|
+
|
76
|
+
puts "# STARTING EXAMPLE #"
|
77
|
+
sleep 2
|
78
|
+
client.publish("topic_1", "Hello Sir. My name is client 1. How do you do? ")
|
79
|
+
sleep 2
|
80
|
+
client2.publish("topic_2", "Hello Mister Client 1. My name is client 2. How do you do?")
|
81
|
+
|
82
|
+
2.times do
|
83
|
+
client.publish("topic_1", "How do you do?")
|
84
|
+
sleep 1
|
85
|
+
client2.publish("topic_2", "How do you do?")
|
86
|
+
sleep 1
|
87
|
+
end
|
88
|
+
|
89
|
+
client.disconnect
|
90
|
+
client2.disconnect
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'aws_iot_device'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
options = {}
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Basic usage basic_greeting.rb -c \"YOUR_CERTIFICATE_PATH\" -k \"YOUR_KEY_FILE_PATH\" -ca \"YOUR_ROOT_CA_PATH -H \"YOUR_ENDPOINT\" -p 8883\n"
|
8
|
+
opts.separator ""
|
9
|
+
opts.separator "Common options"
|
10
|
+
opts.on_tail("-h", "--help", "--usage", "Show this message") do
|
11
|
+
puts opts
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on("-H", "--host [END_POINT]", "The endpoint where you want to connect") do |host|
|
16
|
+
options[:host] = host
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-p", "--port [MQTT_PORT]", "The port used for the connection Default is 8883") do |port|
|
20
|
+
options[:port] = port
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-c", "--cert [CERT_FILE_PATH]", "The path to the certificate file of the private key.") do |cert|
|
24
|
+
options[:cert] = cert
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-k", "--key [KEY_FILE_PATH]", "The path to private key file that would be used for encryption") do |key|
|
28
|
+
options[:key] = key
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-a", "--root_ca [ROOT_CA_PATH]", "The path to the authority certification file") do |root_ca|
|
32
|
+
options[:root_ca] = root_ca
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-t", "--thing [THING_NAME]", "The Thing name on which the action would be done") do |thing|
|
36
|
+
options[:things] = thing
|
37
|
+
end
|
38
|
+
end.parse!(ARGV)
|
39
|
+
|
40
|
+
|
41
|
+
host = options[:host]
|
42
|
+
port = options[:port] || 8883
|
43
|
+
cert_file_path = options[:cert]
|
44
|
+
key_file_path = options[:key]
|
45
|
+
ca_file_path = options[:root_ca]
|
46
|
+
thing = options[:things]
|
47
|
+
|
48
|
+
mqtt_client = AwsIotDevice::MqttShadowClient::MqttManager.new(host: host,
|
49
|
+
port: port,
|
50
|
+
ssl: true,
|
51
|
+
cert_file: cert_file_path,
|
52
|
+
key_file: key_file_path,
|
53
|
+
ca_file: ca_file_path)
|
54
|
+
|
55
|
+
mqtt_client.connect
|
56
|
+
|
57
|
+
filter_callback = Proc.new do |message|
|
58
|
+
puts "Executing the specific callback for topic: #{message.topic}\n##########################################\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
timeout = 5
|
62
|
+
|
63
|
+
topic_manager = AwsIotDevice::MqttShadowClient::ShadowTopicManager.new(mqtt_client)
|
64
|
+
|
65
|
+
client = AwsIotDevice::MqttShadowClient::ShadowActionManager.new(thing, topic_manager, false)
|
66
|
+
|
67
|
+
client.register_shadow_delta_callback(filter_callback)
|
68
|
+
|
69
|
+
n = 1
|
70
|
+
|
71
|
+
5.times do
|
72
|
+
json_payload = "{\"state\":{\"desired\":{\"property\":\"RubySDK\",\"count\":#{n}}}}"
|
73
|
+
client.shadow_update(json_payload, filter_callback, timeout)
|
74
|
+
n += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
sleep timeout
|
78
|
+
|
79
|
+
mqtt_client.disconnect
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'aws_iot_device'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
options = {}
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Basic usage basic_greeting.rb -c \"YOUR_CERTIFICATE_PATH\" -k \"YOUR_KEY_FILE_PATH\" -ca \"YOUR_ROOT_CA_PATH -H \"YOUR_ENDPOINT\" -p 8883\n"
|
8
|
+
|
9
|
+
opts.separator ""
|
10
|
+
opts.separator "Common options"
|
11
|
+
opts.on_tail("-h", "--help", "--usage", "Show this message") do
|
12
|
+
puts opts
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on("-H", "--host [END_POINT]", "The endpoint where you want to connect") do |host|
|
17
|
+
options[:host] = host
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-p", "--port [MQTT_PORT]", "The port used for the connection Default is 8883") do |port|
|
21
|
+
options[:port] = port
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-c", "--cert [CERT_FILE_PATH]", "The path to the certificate file of the private key.") do |cert|
|
25
|
+
options[:cert] = cert
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-k", "--key [KEY_FILE_PATH]", "The path to private key file that would be used for encryption") do |key|
|
29
|
+
options[:key] = key
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-a", "--root_ca [ROOT_CA_PATH]", "The path to the authority certification file") do |root_ca|
|
33
|
+
options[:root_ca] = root_ca
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-t", "--thing [THING_NAME]", "The Thing name on which the action would be done") do |thing|
|
37
|
+
options[:things] = thing
|
38
|
+
end
|
39
|
+
end.parse!(ARGV)
|
40
|
+
|
41
|
+
|
42
|
+
host = options[:host]
|
43
|
+
port = options[:port] || 8883
|
44
|
+
certificate_path = options[:cert]
|
45
|
+
private_key_path = options[:key]
|
46
|
+
root_ca_path = options[:root_ca]
|
47
|
+
thing = options[:things]
|
48
|
+
|
49
|
+
my_shadow_client = AwsIotDevice::MqttShadowClient::ShadowClient.new
|
50
|
+
my_shadow_client.configure_endpoint(host, port)
|
51
|
+
my_shadow_client.configure_credentials(root_ca_path, private_key_path, certificate_path)
|
52
|
+
|
53
|
+
my_shadow_client.connect
|
54
|
+
|
55
|
+
my_shadow_client.create_shadow_handler_with_name(thing ,false)
|
56
|
+
|
57
|
+
filter_callback = Proc.new do |message|
|
58
|
+
puts "Executing the specific callback for topic: #{message.topic}\n##########################################\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
n = 1
|
62
|
+
|
63
|
+
3.times do
|
64
|
+
puts "Start shadow_delete\n"
|
65
|
+
my_shadow_client.delete_shadow(filter_callback, 5)
|
66
|
+
json_payload = '{"state":{"desired":{"property":"RubySDK"}}}'
|
67
|
+
my_shadow_client.update_shadow(json_payload, nil, 5)
|
68
|
+
n += 1
|
69
|
+
end
|
70
|
+
|
71
|
+
sleep 5
|
72
|
+
|
73
|
+
my_shadow_client.disconnect
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'aws_iot_device'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
options = {}
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Basic usage basic_greeting.rb -c \"YOUR_CERTIFICATE_PATH\" -k \"YOUR_KEY_FILE_PATH\" -ca \"YOUR_ROOT_CA_PATH -H \"YOUR_ENDPOINT\" -p 8883\n"
|
8
|
+
|
9
|
+
opts.separator ""
|
10
|
+
opts.separator "Common options"
|
11
|
+
opts.on_tail("-h", "--help", "--usage", "Show this message") do
|
12
|
+
puts opts
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on("-H", "--host [END_POINT]", "The endpoint where you want to connect") do |host|
|
17
|
+
options[:host] = host
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-p", "--port [MQTT_PORT]", "The port used for the connection Default is 8883") do |port|
|
21
|
+
options[:port] = port
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-c", "--cert [CERT_FILE_PATH]", "The path to the certificate file of the private key.") do |cert|
|
25
|
+
options[:cert] = cert
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-k", "--key [KEY_FILE_PATH]", "The path to private key file that would be used for encryption") do |key|
|
29
|
+
options[:key] = key
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-a", "--root_ca [ROOT_CA_PATH]", "The path to the authority certification file") do |root_ca|
|
33
|
+
options[:root_ca] = root_ca
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-t", "--thing [THING_NAME]", "The Thing name on which the action would be done") do |thing|
|
37
|
+
options[:things] = thing
|
38
|
+
end
|
39
|
+
end.parse!(ARGV)
|
40
|
+
|
41
|
+
|
42
|
+
host = options[:host]
|
43
|
+
port = options[:port] || 8883
|
44
|
+
certificate_path = options[:cert]
|
45
|
+
private_key_path = options[:key]
|
46
|
+
root_ca_path = options[:root_ca]
|
47
|
+
thing = options[:things]
|
48
|
+
|
49
|
+
my_shadow_client = AwsIotDevice::MqttShadowClient::ShadowClient.new
|
50
|
+
my_shadow_client.configure_endpoint(host, port)
|
51
|
+
my_shadow_client.configure_credentials(root_ca_path, private_key_path, certificate_path)
|
52
|
+
|
53
|
+
my_shadow_client.connect
|
54
|
+
|
55
|
+
my_shadow_client.create_shadow_handler_with_name(thing ,false)
|
56
|
+
|
57
|
+
|
58
|
+
filter_callback = Proc.new do |message|
|
59
|
+
puts "Executing the specific callback for topic: #{message.topic}\n##########################################\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
puts "##### Starting test_shadow_client_get ######"
|
63
|
+
my_shadow_client.get_shadow(filter_callback, 4)
|
64
|
+
sleep 5
|
65
|
+
|
66
|
+
puts "##### Starting test_shadow_client_get ######"
|
67
|
+
my_shadow_client.get_shadow(nil, 4)
|
68
|
+
sleep 5
|
69
|
+
|
70
|
+
puts "##### Starting test_shadow_client_get ######"
|
71
|
+
my_shadow_client.get_shadow(filter_callback, 4)
|
72
|
+
sleep 5
|
73
|
+
|
74
|
+
my_shadow_client.disconnect
|