somfy_sdn 1.0.12 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/somfy_sdn +60 -0
- data/lib/sdn.rb +16 -1
- data/lib/sdn/cli/mqtt.rb +369 -0
- data/lib/sdn/cli/mqtt/group.rb +31 -0
- data/lib/sdn/cli/mqtt/motor.rb +103 -0
- data/lib/sdn/cli/mqtt/read.rb +154 -0
- data/lib/sdn/cli/mqtt/subscriptions.rb +156 -0
- data/lib/sdn/cli/mqtt/write.rb +93 -0
- data/lib/sdn/cli/provisioner.rb +234 -0
- data/lib/sdn/cli/simulator.rb +197 -0
- data/lib/sdn/client.rb +84 -0
- data/lib/sdn/message.rb +81 -30
- data/lib/sdn/{messages → message}/control.rb +79 -38
- data/lib/sdn/{messages → message}/get.rb +48 -40
- data/lib/sdn/{messages → message}/helpers.rb +33 -3
- data/lib/sdn/message/ilt2/get.rb +48 -0
- data/lib/sdn/message/ilt2/master_control.rb +35 -0
- data/lib/sdn/message/ilt2/post.rb +127 -0
- data/lib/sdn/message/ilt2/set.rb +192 -0
- data/lib/sdn/{messages → message}/post.rb +127 -61
- data/lib/sdn/{messages → message}/set.rb +99 -84
- data/lib/sdn/version.rb +1 -1
- metadata +53 -16
- data/bin/sdn_mqtt_bridge +0 -5
- data/lib/sdn/messages/ilt2/get.rb +0 -9
- data/lib/sdn/messages/ilt2/post.rb +0 -18
- data/lib/sdn/messages/ilt2/set.rb +0 -59
- data/lib/sdn/mqtt_bridge.rb +0 -711
@@ -1,44 +1,68 @@
|
|
1
1
|
module SDN
|
2
2
|
class Message
|
3
|
-
class
|
4
|
-
MSG =
|
5
|
-
PARAMS_LENGTH =
|
3
|
+
class PostGroupAddr < Message
|
4
|
+
MSG = 0x61
|
5
|
+
PARAMS_LENGTH = 4
|
6
6
|
|
7
|
-
|
7
|
+
def initialize(group_index = nil, group_address = nil, **kwargs)
|
8
|
+
super(**kwargs)
|
9
|
+
self.group_index = group_index
|
10
|
+
self.group_address = group_address
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :group_index, :group_address
|
8
14
|
|
9
15
|
def parse(params)
|
10
16
|
super
|
11
|
-
self.
|
12
|
-
self.
|
13
|
-
self.
|
17
|
+
self.group_index = to_number(params[0]) + 1
|
18
|
+
self.group_address = transform_param(params[1..3])
|
19
|
+
self.group_address = nil if group_address == [0, 0, 0] || group_address == [0x01, 0x01, 0xff]
|
20
|
+
end
|
21
|
+
|
22
|
+
def params
|
23
|
+
from_number(group_index - 1) + transform_param(group_address || [0, 0, 0])
|
24
|
+
end
|
25
|
+
|
26
|
+
def class_inspect
|
27
|
+
", group_index=#{group_index.inspect}, group_address=#{group_address ? print_address(group_address) : 'nil'}"
|
14
28
|
end
|
15
29
|
end
|
16
30
|
|
17
|
-
class
|
18
|
-
MSG =
|
31
|
+
class PostMotorDirection < Message
|
32
|
+
MSG = 0x32
|
33
|
+
PARAMS_LENGTH = 1
|
34
|
+
DIRECTION = { standard: 0x00, reversed: 0x01 }.freeze
|
35
|
+
|
36
|
+
attr_accessor :direction
|
37
|
+
|
38
|
+
def parse(params)
|
39
|
+
super
|
40
|
+
self.direction = DIRECTION.invert[to_number(params[0])]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class PostMotorIP < Message
|
45
|
+
MSG = 0x35
|
19
46
|
PARAMS_LENGTH = 4
|
20
|
-
STATE = { stopped: 0x00, running: 0x01, blocked: 0x02, locked: 0x03 }.freeze
|
21
|
-
DIRECTION = { down: 0x00, up: 0x01 }.freeze
|
22
|
-
SOURCE = { internal: 0x00, network: 0x01, dct: 0x02 }.freeze
|
23
|
-
CAUSE = { target_reached: 0x00,
|
24
|
-
explicit_command: 0x01,
|
25
|
-
wink: 0x02,
|
26
|
-
limits_not_set: 0x10,
|
27
|
-
ip_not_set: 0x11,
|
28
|
-
polarity_not_checked: 0x12,
|
29
|
-
in_configuration_mode: 0x13,
|
30
|
-
obstacle_detection: 0x20,
|
31
|
-
over_current_protection: 0x21,
|
32
|
-
thermal_protection: 0x22 }.freeze
|
33
47
|
|
34
|
-
attr_accessor :
|
48
|
+
attr_accessor :ip, :position_pulses, :position_percent
|
49
|
+
|
50
|
+
def initialize(ip = nil, position_pulses = nil, position_percent = nil, **kwargs)
|
51
|
+
super(**kwargs)
|
52
|
+
self.ip = ip
|
53
|
+
self.position_pulses = position_pulses
|
54
|
+
self.position_percent = position_percent
|
55
|
+
end
|
35
56
|
|
36
57
|
def parse(params)
|
37
58
|
super
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
self.
|
41
|
-
|
59
|
+
self.ip = to_number(params[0])
|
60
|
+
self.position_pulses = to_number(params[1..2], nillable: true)
|
61
|
+
self.position_percent = to_number(params[3], nillable: true)
|
62
|
+
end
|
63
|
+
|
64
|
+
def params
|
65
|
+
from_number(ip) + from_number(position_pulses, 2) + from_number(position_percent)
|
42
66
|
end
|
43
67
|
end
|
44
68
|
|
@@ -48,23 +72,45 @@ module SDN
|
|
48
72
|
|
49
73
|
attr_accessor :up_limit, :down_limit
|
50
74
|
|
75
|
+
def initialize(up_limit = nil, down_limit = nil, **kwargs)
|
76
|
+
super(**kwargs)
|
77
|
+
self.up_limit = up_limit
|
78
|
+
self.down_limit = down_limit
|
79
|
+
end
|
80
|
+
|
51
81
|
def parse(params)
|
52
82
|
super
|
53
83
|
self.up_limit = to_number(params[0..1], nillable: true)
|
54
84
|
self.down_limit = to_number(params[2..3], nillable: true)
|
55
85
|
end
|
86
|
+
|
87
|
+
def params
|
88
|
+
from_number(up_limit, 2) + from_number(down_limit, 2)
|
89
|
+
end
|
56
90
|
end
|
57
91
|
|
58
|
-
class
|
59
|
-
MSG =
|
60
|
-
PARAMS_LENGTH =
|
61
|
-
DIRECTION = { standard: 0x00, reversed: 0x01 }.freeze
|
92
|
+
class PostMotorPosition < Message
|
93
|
+
MSG = 0x0d
|
94
|
+
PARAMS_LENGTH = 5
|
62
95
|
|
63
|
-
attr_accessor :
|
96
|
+
attr_accessor :position_pulses, :position_percent, :ip
|
97
|
+
|
98
|
+
def initialize(position_pulses = nil, position_percent = nil, ip = nil, **kwargs)
|
99
|
+
super(**kwargs)
|
100
|
+
self.position_pulses = position_pulses
|
101
|
+
self.position_percent = position_percent
|
102
|
+
self.ip = ip
|
103
|
+
end
|
64
104
|
|
65
105
|
def parse(params)
|
66
106
|
super
|
67
|
-
self.
|
107
|
+
self.position_pulses = to_number(params[0..1], nillable: true)
|
108
|
+
self.position_percent = to_number(params[2], nillable: true)
|
109
|
+
self.ip = to_number(params[4], nillable: true)
|
110
|
+
end
|
111
|
+
|
112
|
+
def params
|
113
|
+
from_number(position_pulses, 2) + from_number(position_percent) + from_number(ip)
|
68
114
|
end
|
69
115
|
end
|
70
116
|
|
@@ -83,17 +129,40 @@ module SDN
|
|
83
129
|
end
|
84
130
|
end
|
85
131
|
|
86
|
-
class
|
87
|
-
MSG =
|
132
|
+
class PostMotorStatus < Message
|
133
|
+
MSG = 0x0f
|
88
134
|
PARAMS_LENGTH = 4
|
135
|
+
STATE = { stopped: 0x00, running: 0x01, blocked: 0x02, locked: 0x03 }.freeze
|
136
|
+
DIRECTION = { down: 0x00, up: 0x01 }.freeze
|
137
|
+
SOURCE = { internal: 0x00, network: 0x01, dct: 0x02 }.freeze
|
138
|
+
CAUSE = { target_reached: 0x00,
|
139
|
+
explicit_command: 0x01,
|
140
|
+
wink: 0x02,
|
141
|
+
limits_not_set: 0x10,
|
142
|
+
ip_not_set: 0x11,
|
143
|
+
polarity_not_checked: 0x12,
|
144
|
+
in_configuration_mode: 0x13,
|
145
|
+
obstacle_detection: 0x20,
|
146
|
+
over_current_protection: 0x21,
|
147
|
+
thermal_protection: 0x22 }.freeze
|
89
148
|
|
90
|
-
attr_accessor :
|
149
|
+
attr_accessor :state, :last_direction, :last_action_source, :last_action_cause
|
150
|
+
|
151
|
+
def parse(params)
|
152
|
+
super
|
153
|
+
self.state = STATE.invert[to_number(params[0])]
|
154
|
+
self.last_direction = DIRECTION.invert[to_number(params[1])]
|
155
|
+
self.last_action_source = SOURCE.invert[to_number(params[2])]
|
156
|
+
self.last_action_cause = CAUSE.invert[to_number(params[3])]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class PostNetworkLock < UnknownMessage
|
161
|
+
MSG = 0x36
|
162
|
+
PARAMS_LENGTH = 5
|
91
163
|
|
92
164
|
def parse(params)
|
93
165
|
super
|
94
|
-
self.ip = to_number(params[0])
|
95
|
-
self.position_pulses = to_number(params[1..2], nillable: true)
|
96
|
-
self.position_percent = to_number(params[3], nillable: true)
|
97
166
|
end
|
98
167
|
end
|
99
168
|
|
@@ -102,32 +171,39 @@ module SDN
|
|
102
171
|
PARAMS_LENGTH = 0
|
103
172
|
end
|
104
173
|
|
105
|
-
class
|
106
|
-
MSG =
|
107
|
-
PARAMS_LENGTH =
|
174
|
+
class PostNodeAppVersion < Message
|
175
|
+
MSG = 0x75
|
176
|
+
PARAMS_LENGTH = 6
|
108
177
|
|
109
|
-
attr_accessor :
|
178
|
+
attr_accessor :reference, :index_letter, :index_number, :profile
|
110
179
|
|
111
180
|
def parse(params)
|
112
181
|
super
|
113
|
-
self.
|
114
|
-
self.
|
115
|
-
self.
|
116
|
-
|
117
|
-
|
118
|
-
def class_inspect
|
119
|
-
", group_index=#{group_index.inspect}, group_address=#{group_address ? print_address(group_address) : 'nil'}"
|
182
|
+
self.reference = to_number(params[0..2])
|
183
|
+
self.index_letter = to_string(params[3..3])
|
184
|
+
self.index_number = transform_param(params[4])
|
185
|
+
self.profile = transform_param(params[5])
|
120
186
|
end
|
121
187
|
end
|
122
188
|
|
123
189
|
class PostNodeLabel < Message
|
124
190
|
MSG = 0x65
|
191
|
+
MAX_LENGTH = 16
|
125
192
|
|
126
193
|
attr_accessor :label
|
127
194
|
|
195
|
+
def initialize(label = nil, **kwargs)
|
196
|
+
super(**kwargs)
|
197
|
+
self.label = label
|
198
|
+
end
|
199
|
+
|
128
200
|
def parse(params)
|
129
201
|
@label = to_string(params)
|
130
202
|
end
|
203
|
+
|
204
|
+
def params
|
205
|
+
from_string(label, self.class::MAX_LENGTH)
|
206
|
+
end
|
131
207
|
end
|
132
208
|
|
133
209
|
class PostNodeSerialNumber < Message
|
@@ -145,18 +221,8 @@ module SDN
|
|
145
221
|
end
|
146
222
|
end
|
147
223
|
|
148
|
-
class PostNodeStackVersion <
|
224
|
+
class PostNodeStackVersion < PostNodeAppVersion
|
149
225
|
MSG = 0x71
|
150
|
-
|
151
|
-
attr_accessor :params
|
152
|
-
|
153
|
-
def parse(params)
|
154
|
-
# I don't know how to interpret this yet
|
155
|
-
# I get b6 bc b2 be fc fe, and UAI+ shows 5063497A3
|
156
|
-
super
|
157
|
-
end
|
158
|
-
|
159
|
-
def msg; MSG; end
|
160
226
|
end
|
161
227
|
end
|
162
228
|
end
|
@@ -1,46 +1,67 @@
|
|
1
1
|
module SDN
|
2
2
|
class Message
|
3
|
-
class
|
4
|
-
MSG =
|
5
|
-
PARAMS_LENGTH =
|
6
|
-
|
7
|
-
TARGET = { down: 0x00, up: 0x01 }
|
3
|
+
class SetFactoryDefault < Message
|
4
|
+
MSG = 0x1f
|
5
|
+
PARAMS_LENGTH = 1
|
6
|
+
RESET = { all_settings: 0x00, group_addresses: 0x01, limits: 0x11, rotation: 0x12, rolling_speed: 0x13, ips: 0x15, locks: 0x17 }
|
8
7
|
|
9
|
-
attr_reader :
|
8
|
+
attr_reader :reset
|
10
9
|
|
11
|
-
def initialize(dest = nil,
|
12
|
-
kwargs[:dest]
|
10
|
+
def initialize(dest = nil, reset = :all_settings, **kwargs)
|
11
|
+
kwargs[:dest] ||= dest
|
13
12
|
super(**kwargs)
|
14
|
-
self.
|
15
|
-
self.target = target
|
16
|
-
self.value = value
|
13
|
+
self.reset = reset
|
17
14
|
end
|
18
15
|
|
19
16
|
def parse(params)
|
20
17
|
super
|
21
|
-
self.
|
22
|
-
self.target = TARGET.invert[to_number(params[1])]
|
23
|
-
self.value = to_number(params[2..3])
|
18
|
+
self.reset = RESET.invert[to_number(params)]
|
24
19
|
end
|
25
20
|
|
26
|
-
def
|
27
|
-
raise ArgumentError, "
|
28
|
-
@
|
21
|
+
def reset=(value)
|
22
|
+
raise ArgumentError, "reset must be one of :all_settings, :group_addresses, :limits, :rotation, :rolling_speed, :ips, :locks" unless RESET.keys.include?(value)
|
23
|
+
@reset = value
|
29
24
|
end
|
30
25
|
|
31
|
-
def
|
32
|
-
|
33
|
-
@target = value
|
26
|
+
def params
|
27
|
+
transform_param(RESET[reset])
|
34
28
|
end
|
29
|
+
end
|
35
30
|
|
36
|
-
|
37
|
-
|
31
|
+
class SetGroupAddr < Message
|
32
|
+
MSG = 0x51
|
33
|
+
PARAMS_LENGTH = 4
|
34
|
+
|
35
|
+
attr_reader :group_index, :group_address
|
36
|
+
|
37
|
+
def initialize(dest = nil, group_index = 1, group_address = nil, **kwargs)
|
38
|
+
kwargs[:dest] ||= dest
|
39
|
+
super(**kwargs)
|
40
|
+
self.group_index = group_index
|
41
|
+
self.group_address = group_address
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse(params)
|
45
|
+
super
|
46
|
+
self.group_index = to_number(params[0]) + 1
|
47
|
+
self.group_address = transform_param(params[1..3])
|
48
|
+
end
|
49
|
+
|
50
|
+
def group_index=(value)
|
51
|
+
raise ArgumentError, "group_index is out of range" unless (1..16).include?(value)
|
52
|
+
@group_index = value
|
53
|
+
end
|
54
|
+
|
55
|
+
def group_address=(value)
|
56
|
+
@group_address = value
|
38
57
|
end
|
39
58
|
|
40
59
|
def params
|
41
|
-
|
42
|
-
|
43
|
-
|
60
|
+
transform_param(group_index - 1) + transform_param(group_address || [0, 0, 0])
|
61
|
+
end
|
62
|
+
|
63
|
+
def class_inspect
|
64
|
+
", group_index=#{group_index.inspect}, group_address=#{group_address ? print_address(group_address) : 'nil'}"
|
44
65
|
end
|
45
66
|
end
|
46
67
|
|
@@ -72,31 +93,6 @@ module SDN
|
|
72
93
|
end
|
73
94
|
end
|
74
95
|
|
75
|
-
class SetMotorRollingSpeed < Message
|
76
|
-
MSG = 0x13
|
77
|
-
PARAMS_LENGTH = 3
|
78
|
-
|
79
|
-
attr_accessor :up_speed, :down_speed, :slow_speed
|
80
|
-
def initialize(dest = nil, up_speed: nil, down_speed: nil, slow_speed: nil, **kwargs)
|
81
|
-
kwargs[:dest] ||= dest
|
82
|
-
super(**kwargs)
|
83
|
-
self.up_speed = up_speed
|
84
|
-
self.down_speed = down_speed
|
85
|
-
self.slow_speed = slow_speed
|
86
|
-
end
|
87
|
-
|
88
|
-
def parse(params)
|
89
|
-
super
|
90
|
-
self.up_speed = to_number(params[0])
|
91
|
-
self.down_speed = to_number(params[1])
|
92
|
-
self.slow_speed = to_number(params[2])
|
93
|
-
end
|
94
|
-
|
95
|
-
def params
|
96
|
-
transform_param(up_speed || 0xff) + transform_param(down_speed || 0xff) + transform_param(slow_speed || 0xff)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
96
|
class SetMotorIP < Message
|
101
97
|
MSG = 0x15
|
102
98
|
PARAMS_LENGTH = 4
|
@@ -141,74 +137,93 @@ module SDN
|
|
141
137
|
end
|
142
138
|
end
|
143
139
|
|
144
|
-
class
|
145
|
-
MSG =
|
146
|
-
PARAMS_LENGTH =
|
147
|
-
|
140
|
+
class SetMotorLimits < Message
|
141
|
+
MSG = 0x11
|
142
|
+
PARAMS_LENGTH = 4
|
143
|
+
TYPE = { delete: 0x00, current_position: 0x01, specified_position: 0x02, jog_ms: 0x04, jog_pulses: 0x05 }
|
144
|
+
TARGET = { down: 0x00, up: 0x01 }
|
148
145
|
|
149
|
-
attr_reader :
|
146
|
+
attr_reader :type, :target, :value
|
150
147
|
|
151
|
-
def initialize(dest = nil,
|
148
|
+
def initialize(dest = nil, type = :delete, target = :up, value = nil, **kwargs)
|
152
149
|
kwargs[:dest] ||= dest
|
153
150
|
super(**kwargs)
|
154
|
-
self.
|
151
|
+
self.type = type
|
152
|
+
self.target = target
|
153
|
+
self.value = value
|
155
154
|
end
|
156
155
|
|
157
156
|
def parse(params)
|
158
157
|
super
|
159
|
-
self.
|
158
|
+
self.type = TYPE.invert[to_number(params[0])]
|
159
|
+
self.target = TARGET.invert[to_number(params[1])]
|
160
|
+
self.value = to_number(params[2..3])
|
160
161
|
end
|
161
162
|
|
162
|
-
def
|
163
|
-
raise ArgumentError, "
|
164
|
-
@
|
163
|
+
def type=(value)
|
164
|
+
raise ArgumentError, "type must be one of :delete, :current_position, :specified_position, :jog_ms, :jog_pulses" unless TYPE.keys.include?(value)
|
165
|
+
@type = value
|
166
|
+
end
|
167
|
+
|
168
|
+
def target=(value)
|
169
|
+
raise ArgumentError, "target must be one of :up, :down" unless TARGET.keys.include?(value)
|
170
|
+
@target = value
|
171
|
+
end
|
172
|
+
|
173
|
+
def value=(value)
|
174
|
+
@value = value&. & 0xffff
|
165
175
|
end
|
166
176
|
|
167
177
|
def params
|
168
|
-
|
178
|
+
param = value || 0
|
179
|
+
param /= 10 if target == :jog_ms
|
180
|
+
transform_param(TYPE[type]) + transform_param(TARGET[target]) + from_number(param, 2)
|
169
181
|
end
|
170
182
|
end
|
171
183
|
|
172
|
-
class
|
173
|
-
MSG =
|
174
|
-
PARAMS_LENGTH =
|
175
|
-
|
176
|
-
attr_reader :group_index, :group_address
|
184
|
+
class SetMotorRollingSpeed < Message
|
185
|
+
MSG = 0x13
|
186
|
+
PARAMS_LENGTH = 3
|
177
187
|
|
178
|
-
|
188
|
+
attr_accessor :up_speed, :down_speed, :slow_speed
|
189
|
+
def initialize(dest = nil, up_speed: nil, down_speed: nil, slow_speed: nil, **kwargs)
|
179
190
|
kwargs[:dest] ||= dest
|
180
191
|
super(**kwargs)
|
181
|
-
self.
|
182
|
-
self.
|
192
|
+
self.up_speed = up_speed
|
193
|
+
self.down_speed = down_speed
|
194
|
+
self.slow_speed = slow_speed
|
183
195
|
end
|
184
196
|
|
185
197
|
def parse(params)
|
186
198
|
super
|
187
|
-
self.
|
188
|
-
self.
|
199
|
+
self.up_speed = to_number(params[0])
|
200
|
+
self.down_speed = to_number(params[1])
|
201
|
+
self.slow_speed = to_number(params[2])
|
189
202
|
end
|
190
203
|
|
191
|
-
def
|
192
|
-
|
193
|
-
@group_index = value
|
204
|
+
def params
|
205
|
+
transform_param(up_speed || 0xff) + transform_param(down_speed || 0xff) + transform_param(slow_speed || 0xff)
|
194
206
|
end
|
207
|
+
end
|
195
208
|
|
196
|
-
|
197
|
-
|
198
|
-
end
|
209
|
+
class SetNetworkLock < Message
|
210
|
+
MSG = 0x16
|
199
211
|
|
200
|
-
|
201
|
-
|
212
|
+
attr_accessor :locked, :priority
|
213
|
+
|
214
|
+
def parse(params)
|
215
|
+
self.locked = to_number(params[0]) == 1 ? true : false
|
216
|
+
self.priority = to_number(params[1])
|
202
217
|
end
|
203
218
|
|
204
|
-
def
|
205
|
-
|
219
|
+
def params
|
220
|
+
transform_param(locked ? 1 : 0) + transform_param(priority)
|
206
221
|
end
|
207
222
|
end
|
208
223
|
|
209
224
|
class SetNodeLabel < Message
|
210
225
|
MSG = 0x55
|
211
|
-
|
226
|
+
MAX_LENGTH = 16
|
212
227
|
|
213
228
|
attr_accessor :label
|
214
229
|
|
@@ -223,7 +238,7 @@ module SDN
|
|
223
238
|
end
|
224
239
|
|
225
240
|
def params
|
226
|
-
from_string(label,
|
241
|
+
from_string(label, self.class::MAX_LENGTH)
|
227
242
|
end
|
228
243
|
end
|
229
244
|
end
|