somfy_sdn 1.0.7 → 1.0.8
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 +4 -4
- data/lib/sdn.rb +6 -0
- data/lib/sdn/message.rb +14 -6
- data/lib/sdn/messages/control.rb +3 -3
- data/lib/sdn/messages/ilt2/get.rb +9 -0
- data/lib/sdn/messages/ilt2/post.rb +18 -0
- data/lib/sdn/messages/ilt2/set.rb +59 -0
- data/lib/sdn/mqtt_bridge.rb +91 -62
- data/lib/sdn/version.rb +1 -1
- data/lib/somfy_sdn.rb +1 -2
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66516a3bb03695b73075a496a791502683ec12052219a5cf040cfe6e9f82b04f
|
4
|
+
data.tar.gz: bad8e87688534b118e679b4126490f5eab3c6e83ee7288184368e852bf0cc450
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db18252c03d784aeb3461dacffc16dae04aeb176f5b98f3b796d395f95980350576075a434794e16347eef7bfb308eccf7e4307abeceb4675254a3505d74b60d
|
7
|
+
data.tar.gz: e17af388921091abe51a23b6fcef7c3bf0d402ad55446bfc86aa698482a22cca341f7612b73d04e97ad91e060ff13f7573016e4ddb7aca24002c69f1ee9706b9
|
data/lib/sdn.rb
ADDED
data/lib/sdn/message.rb
CHANGED
@@ -3,7 +3,7 @@ require 'sdn/messages/helpers'
|
|
3
3
|
module SDN
|
4
4
|
class MalformedMessage < RuntimeError; end
|
5
5
|
|
6
|
-
class Message
|
6
|
+
class Message
|
7
7
|
class << self
|
8
8
|
def parse(data)
|
9
9
|
offset = -1
|
@@ -11,7 +11,7 @@ module SDN
|
|
11
11
|
# we loop here scanning for a valid message
|
12
12
|
loop do
|
13
13
|
offset += 1
|
14
|
-
return nil if data.length - offset < 11
|
14
|
+
return [nil, 0] if data.length - offset < 11
|
15
15
|
msg = to_number(data[offset])
|
16
16
|
length = to_number(data[offset + 1])
|
17
17
|
ack_requested = length & 0x80 == 0x80
|
@@ -39,9 +39,14 @@ module SDN
|
|
39
39
|
reserved = to_number(data[offset + 2])
|
40
40
|
src = transform_param(data.slice(offset + 3, 3))
|
41
41
|
dest = transform_param(data.slice(offset + 6, 3))
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
begin
|
43
|
+
result = message_class.new(reserved: reserved, ack_requested: ack_requested, src: src, dest: dest)
|
44
|
+
result.parse(data.slice(offset + 9, length - 11))
|
45
|
+
result.msg = msg if message_class == UnknownMessage
|
46
|
+
rescue ArgumentError => e
|
47
|
+
puts "discarding illegal message #{e}"
|
48
|
+
result = nil
|
49
|
+
end
|
45
50
|
[result, offset + length]
|
46
51
|
end
|
47
52
|
end
|
@@ -72,10 +77,13 @@ module SDN
|
|
72
77
|
length |= 0x80 if ack_requested
|
73
78
|
result = transform_param(self.class.const_get(:MSG)) + transform_param(length) + result
|
74
79
|
result.concat(checksum(result))
|
75
|
-
puts "wrote #{result.map { |b| '%02x' % b }.join(' ')}"
|
76
80
|
result.pack("C*")
|
77
81
|
end
|
78
82
|
|
83
|
+
def ==(other)
|
84
|
+
self.serialize == other.serialize
|
85
|
+
end
|
86
|
+
|
79
87
|
def inspect
|
80
88
|
"#<%s @reserved=%02xh, @ack_requested=%s, @src=%s, @dest=%s%s>" % [self.class.name, reserved, ack_requested, print_address(src), print_address(dest), class_inspect]
|
81
89
|
end
|
data/lib/sdn/messages/control.rb
CHANGED
@@ -27,17 +27,17 @@ module SDN
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def direction=(value)
|
30
|
-
raise ArgumentError, "direction must be one of :down, :up, or :cancel" unless DIRECTION.keys.include?(value)
|
30
|
+
raise ArgumentError, "direction must be one of :down, :up, or :cancel (#{value})" unless DIRECTION.keys.include?(value)
|
31
31
|
@direction = value
|
32
32
|
end
|
33
33
|
|
34
34
|
def duration=(value)
|
35
|
-
raise ArgumentError, "duration must be in range 0x0a to 0xff" unless value
|
35
|
+
raise ArgumentError, "duration must be in range 0x0a to 0xff (#{value})" unless value && value >= 0x0a && value <= 0xff
|
36
36
|
@duration = value
|
37
37
|
end
|
38
38
|
|
39
39
|
def speed=(value)
|
40
|
-
raise ArgumentError, "speed must be one of :up, :down, or :slow" unless SPEED.keys.include?(value)
|
40
|
+
raise ArgumentError, "speed must be one of :up, :down, or :slow (#{value})" unless SPEED.keys.include?(value)
|
41
41
|
@speed = speed
|
42
42
|
end
|
43
43
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SDN
|
2
|
+
class Message
|
3
|
+
module ILT2
|
4
|
+
class PostMotorPosition < Message
|
5
|
+
MSG = 0x64
|
6
|
+
PARAMS_LENGTH = 3
|
7
|
+
|
8
|
+
attr_accessor :position_pulses, :position_percent
|
9
|
+
|
10
|
+
def parse(params)
|
11
|
+
super
|
12
|
+
self.position_pulses = to_number(params[0..1])
|
13
|
+
self.position_percent = to_number(params[2]).to_f / 255 * 100
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module SDN
|
2
|
+
class Message
|
3
|
+
module ILT2
|
4
|
+
class SetMotorPosition < Message
|
5
|
+
MSG = 0x54
|
6
|
+
PARAMS_LENGTH = 3
|
7
|
+
TARGET_TYPE = {
|
8
|
+
up_limit: 1,
|
9
|
+
down_limit: 2,
|
10
|
+
stop: 3,
|
11
|
+
ip: 4,
|
12
|
+
next_ip_up: 5,
|
13
|
+
next_ip_down: 6,
|
14
|
+
jog_up: 10,
|
15
|
+
jog_down: 11,
|
16
|
+
position_percent: 16,
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
attr_reader :target_type, :target
|
20
|
+
|
21
|
+
def initialize(dest = nil, target_type = :up_limit, target = 0, **kwargs)
|
22
|
+
kwargs[:dest] ||= dest
|
23
|
+
super(**kwargs)
|
24
|
+
self.target_type = target_type
|
25
|
+
self.target = target
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse(params)
|
29
|
+
super
|
30
|
+
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
31
|
+
target = to_number(params[1..2])
|
32
|
+
if target_type == :position_percent
|
33
|
+
target = target.to_f / 255 * 100
|
34
|
+
end
|
35
|
+
self.target = target
|
36
|
+
end
|
37
|
+
|
38
|
+
def target_type=(value)
|
39
|
+
raise ArgumentError, "target_type must be one of :up_limit, :down_limit, :stop, :ip, :next_ip_up, :next_ip_down, :jog_up, :jog_down, or :position_percent" unless TARGET_TYPE.keys.include?(value)
|
40
|
+
@target_type = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def target=(value)
|
44
|
+
if target_type == :position_percent && value
|
45
|
+
@target = [[0, value].max, 100].min
|
46
|
+
else
|
47
|
+
@target = value&. & 0xffff
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def params
|
52
|
+
param = target
|
53
|
+
param = (param * 255 / 100).to_i if target_type == :position_percent
|
54
|
+
transform_param(TARGET_TYPE[target_type]) + from_number(param, 2)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/sdn/mqtt_bridge.rb
CHANGED
@@ -3,7 +3,7 @@ require 'uri'
|
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
module SDN
|
6
|
-
Group = Struct.new(:bridge, :addr, :positionpercent, :state) do
|
6
|
+
Group = Struct.new(:bridge, :addr, :positionpercent, :state, :motors) do
|
7
7
|
def initialize(*)
|
8
8
|
members.each { |k| self[k] = :nil }
|
9
9
|
super
|
@@ -20,9 +20,13 @@ module SDN
|
|
20
20
|
Message.print_address(Message.parse_address(addr))
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def motor_objects
|
24
24
|
bridge.motors.select { |addr, motor| motor.groups_string.include?(printed_addr) }.values
|
25
25
|
end
|
26
|
+
|
27
|
+
def motors_string
|
28
|
+
motor_objects.map { |m| SDN::Message.print_address(SDN::Message.parse_address(m.addr)) }.sort.join(',')
|
29
|
+
end
|
26
30
|
end
|
27
31
|
|
28
32
|
Motor = Struct.new(:bridge,
|
@@ -74,49 +78,50 @@ module SDN
|
|
74
78
|
:ip16pulses,
|
75
79
|
:ip16percent,
|
76
80
|
:groups) do
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
def groups_string
|
112
|
-
@groups.compact.map { |g| SDN::Message.print_address(g) }.sort.uniq.join(',')
|
113
|
-
end
|
114
|
-
|
115
|
-
def group_objects
|
116
|
-
groups_string.split(',').map { |addr| bridge.groups[addr.gsub('.', '')] }
|
117
|
-
end
|
81
|
+
def initialize(*)
|
82
|
+
members.each { |k| self[k] = :nil }
|
83
|
+
@groups = [].fill(nil, 0, 16)
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
def publish(attribute, value)
|
88
|
+
if self[attribute] != value
|
89
|
+
bridge.publish("#{addr}/#{attribute}", value.to_s)
|
90
|
+
self[attribute] = value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_group(index, address)
|
95
|
+
group = bridge.add_group(SDN::Message.print_address(address)) if address
|
96
|
+
@groups[index] = address
|
97
|
+
group&.publish(:motors, group.motors_string)
|
98
|
+
publish(:groups, groups_string)
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_groups(groups)
|
102
|
+
return unless groups =~ /^(?:\h{2}[:.]?\h{2}[:.]?\h{2}(?:,\h{2}[:.]?\h{2}[:.]?\h{2})*)?$/i
|
103
|
+
groups = groups.split(',').sort.uniq.map { |g| SDN::Message.parse_address(g) }.select { |g| SDN::Message.is_group_address?(g) }
|
104
|
+
groups.fill(nil, groups.length, 16 - groups.length)
|
105
|
+
messages = []
|
106
|
+
sdn_addr = SDN::Message.parse_address(addr)
|
107
|
+
groups.each_with_index do |g, i|
|
108
|
+
if @groups[i] != g
|
109
|
+
messages << SDN::Message::SetGroupAddr.new(sdn_addr, i, g)
|
110
|
+
messages << SDN::Message::GetGroupAddr.new(sdn_addr, i)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
messages
|
118
114
|
end
|
119
115
|
|
116
|
+
def groups_string
|
117
|
+
@groups.compact.map { |g| SDN::Message.print_address(g) }.sort.uniq.join(',')
|
118
|
+
end
|
119
|
+
|
120
|
+
def group_objects
|
121
|
+
groups_string.split(',').map { |addr| bridge.groups[addr.gsub('.', '')] }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
120
125
|
class MQTTBridge
|
121
126
|
WAIT_TIME = 0.25
|
122
127
|
BROADCAST_WAIT = 5.0
|
@@ -161,6 +166,8 @@ module SDN
|
|
161
166
|
loop do
|
162
167
|
begin
|
163
168
|
message, bytes_read = SDN::Message.parse(buffer.bytes)
|
169
|
+
# discard how much we read
|
170
|
+
buffer = buffer[bytes_read..-1]
|
164
171
|
unless message
|
165
172
|
begin
|
166
173
|
buffer.concat(@sdn.read_nonblock(64 * 1024))
|
@@ -175,8 +182,6 @@ module SDN
|
|
175
182
|
end
|
176
183
|
next
|
177
184
|
end
|
178
|
-
# discard how much we read
|
179
|
-
buffer = buffer[bytes_read..-1]
|
180
185
|
|
181
186
|
src = SDN::Message.print_address(message.src)
|
182
187
|
# ignore the UAI Plus and ourselves
|
@@ -197,7 +202,7 @@ module SDN
|
|
197
202
|
motor.publish(:positionpulses, message.position_pulses)
|
198
203
|
motor.publish(:ip, message.ip)
|
199
204
|
motor.group_objects.each do |group|
|
200
|
-
positions = group.
|
205
|
+
positions = group.motor_objects.map(&:positionpercent)
|
201
206
|
position = nil
|
202
207
|
# calculate an average, but only if we know a position for
|
203
208
|
# every shade
|
@@ -218,7 +223,7 @@ module SDN
|
|
218
223
|
motor.publish(:last_action_source, message.last_action_source)
|
219
224
|
motor.publish(:last_action_cause, message.last_action_cause)
|
220
225
|
motor.group_objects.each do |group|
|
221
|
-
states = group.
|
226
|
+
states = group.motor_objects.map(&:state).uniq
|
222
227
|
state = states.length == 1 ? states.first : 'mixed'
|
223
228
|
group.publish(:state, state)
|
224
229
|
end
|
@@ -232,7 +237,7 @@ module SDN
|
|
232
237
|
motor.publish(:downspeed, message.down_speed)
|
233
238
|
motor.publish(:slowspeed, message.slow_speed)
|
234
239
|
when SDN::Message::PostMotorIP
|
235
|
-
motor.publish(:"ip#{message.ip}pulses", message.position_pulses)
|
240
|
+
motor.publish(:"ip#{message.ip}pulses", message.position_pulses)
|
236
241
|
motor.publish(:"ip#{message.ip}percent", message.position_percent)
|
237
242
|
when SDN::Message::PostGroupAddr
|
238
243
|
motor.add_group(message.group_index, message.group_address)
|
@@ -241,7 +246,9 @@ module SDN
|
|
241
246
|
@mutex.synchronize do
|
242
247
|
signal = @response_pending || !follow_ups.empty?
|
243
248
|
@response_pending = @broadcast_pending
|
244
|
-
|
249
|
+
follow_ups.each do |follow_up|
|
250
|
+
@request_queue.push(follow_up) unless @request_queue.include?(follow_up)
|
251
|
+
end
|
245
252
|
@cond.signal if signal
|
246
253
|
end
|
247
254
|
rescue EOFError
|
@@ -281,9 +288,9 @@ module SDN
|
|
281
288
|
message = @request_queue.shift
|
282
289
|
if message
|
283
290
|
@response_pending = Time.now.to_f + WAIT_TIME
|
284
|
-
if message.dest ==
|
291
|
+
if message.dest == BROADCAST_ADDRESS || SDN::Message::is_group_address?(message.src) && message.is_a?(SDN::Message::GetNodeAddr)
|
285
292
|
@broadcast_pending = Time.now.to_f + BROADCAST_WAIT
|
286
|
-
end
|
293
|
+
end
|
287
294
|
end
|
288
295
|
end
|
289
296
|
|
@@ -293,8 +300,10 @@ module SDN
|
|
293
300
|
next unless message
|
294
301
|
|
295
302
|
puts "writing #{message.inspect}"
|
296
|
-
|
303
|
+
serialized = message.serialize
|
304
|
+
@sdn.write(serialized)
|
297
305
|
@sdn.flush
|
306
|
+
puts "wrote #{serialized.unpack("C*").map { |b| '%02x' % b }.join(' ')}"
|
298
307
|
end
|
299
308
|
rescue => e
|
300
309
|
puts "failure writing: #{e}"
|
@@ -310,7 +319,7 @@ module SDN
|
|
310
319
|
@request_queue.push(SDN::Message::GetNodeAddr.new)
|
311
320
|
@cond.signal
|
312
321
|
end
|
313
|
-
elsif (match = topic.match(%r{^#{Regexp.escape(@base_topic)}/(?<addr>\h{6})/(?<property>label|down|up|stop|positionpulses|positionpercent|ip|wink|reset|(?<speed_type>upspeed|downspeed|slowspeed)|uplimit|downlimit|direction|ip(?<ip>\d+)(?<ip_type>pulses|percent)|groups)/set$}))
|
322
|
+
elsif (match = topic.match(%r{^#{Regexp.escape(@base_topic)}/(?<addr>\h{6})/(?<property>discover|label|down|up|stop|positionpulses|positionpercent|ip|wink|reset|(?<speed_type>upspeed|downspeed|slowspeed)|uplimit|downlimit|direction|ip(?<ip>\d+)(?<ip_type>pulses|percent)|groups)/set$}))
|
314
323
|
addr = SDN::Message.parse_address(match[:addr])
|
315
324
|
property = match[:property]
|
316
325
|
# not homie compliant; allows linking the positionpercent property
|
@@ -319,10 +328,15 @@ module SDN
|
|
319
328
|
property = value.downcase
|
320
329
|
value = "true"
|
321
330
|
end
|
322
|
-
|
331
|
+
mqtt_addr = SDN::Message.print_address(addr).gsub('.', '')
|
332
|
+
motor = @motors[mqtt_addr]
|
323
333
|
is_group = SDN::Message.is_group_address?(addr)
|
334
|
+
group = @groups[mqtt_addr]
|
324
335
|
follow_up = SDN::Message::GetMotorStatus.new(addr)
|
325
336
|
message = case property
|
337
|
+
when 'discover'
|
338
|
+
follow_up = nil
|
339
|
+
SDN::Message::GetNodeAddr.new(addr) if value == "true"
|
326
340
|
when 'label'
|
327
341
|
follow_up = SDN::Message::GetNodeLabel.new(addr)
|
328
342
|
SDN::Message::SetNodeLabel.new(addr, value) unless is_group
|
@@ -432,7 +446,7 @@ module SDN
|
|
432
446
|
publish("discovery/discover/$settable", "true")
|
433
447
|
publish("discovery/discover/$retained", "false")
|
434
448
|
|
435
|
-
subscribe("
|
449
|
+
subscribe("+/discover/set")
|
436
450
|
subscribe("+/label/set")
|
437
451
|
subscribe("+/down/set")
|
438
452
|
subscribe("+/up/set")
|
@@ -460,7 +474,12 @@ module SDN
|
|
460
474
|
def publish_motor(addr)
|
461
475
|
publish("#{addr}/$name", addr)
|
462
476
|
publish("#{addr}/$type", "Sonesse 30 Motor")
|
463
|
-
publish("#{addr}/$properties", "label,down,up,stop,positionpulses,positionpercent,ip,wink,reset,state,last_direction,last_action_source,last_action_cause,uplimit,downlimit,direction,upspeed,downspeed,slowspeed,#{(1..16).map { |ip| "ip#{ip}pulses,ip#{ip}percent" }.join(',')},groups")
|
477
|
+
publish("#{addr}/$properties", "discover,label,down,up,stop,positionpulses,positionpercent,ip,wink,reset,state,last_direction,last_action_source,last_action_cause,uplimit,downlimit,direction,upspeed,downspeed,slowspeed,#{(1..16).map { |ip| "ip#{ip}pulses,ip#{ip}percent" }.join(',')},groups")
|
478
|
+
|
479
|
+
publish("#{addr}/discover/$name", "Trigger Motor Discovery")
|
480
|
+
publish("#{addr}/discover/$datatype", "boolean")
|
481
|
+
publish("#{addr}/discover/$settable", "true")
|
482
|
+
publish("#{addr}/discover/$retained", "false")
|
464
483
|
|
465
484
|
publish("#{addr}/label/$name", "Node label")
|
466
485
|
publish("#{addr}/label/$datatype", "string")
|
@@ -580,7 +599,7 @@ module SDN
|
|
580
599
|
|
581
600
|
motor = Motor.new(self, addr)
|
582
601
|
@motors[addr] = motor
|
583
|
-
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.keys.sort
|
602
|
+
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.keys.sort).join(","))
|
584
603
|
|
585
604
|
sdn_addr = SDN::Message.parse_address(addr)
|
586
605
|
@mutex.synchronize do
|
@@ -600,11 +619,17 @@ module SDN
|
|
600
619
|
|
601
620
|
def add_group(addr)
|
602
621
|
addr = addr.gsub('.', '')
|
603
|
-
|
622
|
+
group = @groups[addr]
|
623
|
+
return group if group
|
604
624
|
|
605
625
|
publish("#{addr}/$name", addr)
|
606
626
|
publish("#{addr}/$type", "Shade Group")
|
607
|
-
publish("#{addr}/$properties", "down,up,stop,positionpulses,positionpercent,ip,wink,reset")
|
627
|
+
publish("#{addr}/$properties", "discover,down,up,stop,positionpulses,positionpercent,ip,wink,reset,state,motors")
|
628
|
+
|
629
|
+
publish("#{addr}/discover/$name", "Trigger Motor Discovery")
|
630
|
+
publish("#{addr}/discover/$datatype", "boolean")
|
631
|
+
publish("#{addr}/discover/$settable", "true")
|
632
|
+
publish("#{addr}/discover/$retained", "false")
|
608
633
|
|
609
634
|
publish("#{addr}/down/$name", "Move in down direction")
|
610
635
|
publish("#{addr}/down/$datatype", "boolean")
|
@@ -619,7 +644,7 @@ module SDN
|
|
619
644
|
publish("#{addr}/stop/$name", "Cancel adjustments")
|
620
645
|
publish("#{addr}/stop/$datatype", "boolean")
|
621
646
|
publish("#{addr}/stop/$settable", "true")
|
622
|
-
publish("#{addr}/stop/$retained", "false")
|
647
|
+
publish("#{addr}/stop/$retained", "false")
|
623
648
|
|
624
649
|
publish("#{addr}/positionpulses/$name", "Position from up limit (in pulses)")
|
625
650
|
publish("#{addr}/positionpulses/$datatype", "integer")
|
@@ -647,8 +672,12 @@ module SDN
|
|
647
672
|
publish("#{addr}/state/$datatype", "enum")
|
648
673
|
publish("#{addr}/state/$format", SDN::Message::PostMotorStatus::STATE.keys.join(','))
|
649
674
|
|
650
|
-
|
651
|
-
publish("
|
675
|
+
publish("#{addr}/motors/$name", "Motors that are members of this group")
|
676
|
+
publish("#{addr}/motors/$datatype", "string")
|
677
|
+
|
678
|
+
group = @groups[addr] = Group.new(self, addr)
|
679
|
+
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.keys.sort).join(","))
|
680
|
+
group
|
652
681
|
end
|
653
682
|
end
|
654
683
|
end
|
data/lib/sdn/version.rb
CHANGED
data/lib/somfy_sdn.rb
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
require 'sdn
|
2
|
-
require 'sdn/mqtt_bridge'
|
1
|
+
require 'sdn'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: somfy_sdn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mqtt
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.0.
|
33
|
+
version: 0.0.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.0.
|
40
|
+
version: 0.0.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: serialport
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,10 +88,14 @@ extensions: []
|
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
90
|
- bin/sdn_mqtt_bridge
|
91
|
+
- lib/sdn.rb
|
91
92
|
- lib/sdn/message.rb
|
92
93
|
- lib/sdn/messages/control.rb
|
93
94
|
- lib/sdn/messages/get.rb
|
94
95
|
- lib/sdn/messages/helpers.rb
|
96
|
+
- lib/sdn/messages/ilt2/get.rb
|
97
|
+
- lib/sdn/messages/ilt2/post.rb
|
98
|
+
- lib/sdn/messages/ilt2/set.rb
|
95
99
|
- lib/sdn/messages/post.rb
|
96
100
|
- lib/sdn/messages/set.rb
|
97
101
|
- lib/sdn/mqtt_bridge.rb
|