somfy_sdn 1.0.6 → 1.0.7
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/mqtt_bridge.rb +66 -9
- data/lib/sdn/version.rb +1 -1
- metadata +22 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4edace9439651dd89a2c7618a03ae5b6ac9d4ccdf8101ac597eca8f5e66bacf9
|
4
|
+
data.tar.gz: 4ecefc5e15483f4b97169f3a0e8939297c1bdd4cdbe909a2388806feaa0bbac7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e515961e3b633fd7d02879b4d907d76a7bacde2e91f20ddb90893d676e88657f89f912dd645a7e32f9cc166641ae86b816f2dbe96ea1eb702922c51a3bc1b697
|
7
|
+
data.tar.gz: 5825179cad7e2dd32af3a9bbca82cf706dbd0e38b10fe0a756241f8e28e954b414a37fe1a80fa0a84e0586f515b379d27a6b0ab013e9a77a71519924ae68e4a0
|
data/lib/sdn/mqtt_bridge.rb
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
require 'mqtt'
|
2
|
-
require 'serialport'
|
3
|
-
require 'socket'
|
4
2
|
require 'uri'
|
5
3
|
require 'set'
|
6
4
|
|
7
5
|
module SDN
|
6
|
+
Group = Struct.new(:bridge, :addr, :positionpercent, :state) do
|
7
|
+
def initialize(*)
|
8
|
+
members.each { |k| self[k] = :nil }
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def publish(attribute, value)
|
13
|
+
if self[attribute] != value
|
14
|
+
bridge.publish("#{addr}/#{attribute}", value.to_s)
|
15
|
+
self[attribute] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def printed_addr
|
20
|
+
Message.print_address(Message.parse_address(addr))
|
21
|
+
end
|
22
|
+
|
23
|
+
def motors
|
24
|
+
bridge.motors.select { |addr, motor| motor.groups_string.include?(printed_addr) }.values
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
8
28
|
Motor = Struct.new(:bridge,
|
9
29
|
:addr,
|
10
30
|
:label,
|
@@ -91,12 +111,18 @@ module SDN
|
|
91
111
|
def groups_string
|
92
112
|
@groups.compact.map { |g| SDN::Message.print_address(g) }.sort.uniq.join(',')
|
93
113
|
end
|
94
|
-
|
114
|
+
|
115
|
+
def group_objects
|
116
|
+
groups_string.split(',').map { |addr| bridge.groups[addr.gsub('.', '')] }
|
117
|
+
end
|
118
|
+
end
|
95
119
|
|
96
120
|
class MQTTBridge
|
97
121
|
WAIT_TIME = 0.25
|
98
122
|
BROADCAST_WAIT = 5.0
|
99
123
|
|
124
|
+
attr_reader :motors, :groups
|
125
|
+
|
100
126
|
def initialize(mqtt_uri, port, device_id: "somfy", base_topic: "homie")
|
101
127
|
@base_topic = "#{base_topic}/#{device_id}"
|
102
128
|
@mqtt = MQTT::Client.new(mqtt_uri)
|
@@ -104,7 +130,7 @@ module SDN
|
|
104
130
|
@mqtt.connect
|
105
131
|
|
106
132
|
@motors = {}
|
107
|
-
@groups =
|
133
|
+
@groups = {}
|
108
134
|
|
109
135
|
@mutex = Mutex.new
|
110
136
|
@cond = ConditionVariable.new
|
@@ -117,8 +143,16 @@ module SDN
|
|
117
143
|
|
118
144
|
uri = URI.parse(port)
|
119
145
|
if uri.scheme == "tcp"
|
146
|
+
require 'socket'
|
120
147
|
@sdn = TCPSocket.new(uri.host, uri.port)
|
148
|
+
elsif uri.scheme == "telnet" || uri.scheme == "rfc2217"
|
149
|
+
require 'net/telnet/rfc2217'
|
150
|
+
@sdn = Net::Telnet::RFC2217.new('Host' => uri.host,
|
151
|
+
'Port' => uri.port || 23,
|
152
|
+
'baud' => 4800,
|
153
|
+
'parity' => Net::Telnet::RFC2217::ODD)
|
121
154
|
else
|
155
|
+
require 'serialport'
|
122
156
|
@sdn = SerialPort.open(port, "baud" => 4800, "parity" => SerialPort::ODD)
|
123
157
|
end
|
124
158
|
|
@@ -129,11 +163,11 @@ module SDN
|
|
129
163
|
message, bytes_read = SDN::Message.parse(buffer.bytes)
|
130
164
|
unless message
|
131
165
|
begin
|
132
|
-
buffer.concat(@sdn.read_nonblock(
|
166
|
+
buffer.concat(@sdn.read_nonblock(64 * 1024))
|
133
167
|
next
|
134
168
|
rescue IO::WaitReadable
|
135
169
|
wait = buffer.empty? ? nil : WAIT_TIME
|
136
|
-
if
|
170
|
+
if @sdn.wait_readable(wait).nil?
|
137
171
|
# timed out; just discard everything
|
138
172
|
puts "timed out reading; discarding buffer: #{buffer.unpack('H*').first}"
|
139
173
|
buffer = ""
|
@@ -162,6 +196,17 @@ module SDN
|
|
162
196
|
motor.publish(:positionpercent, message.position_percent)
|
163
197
|
motor.publish(:positionpulses, message.position_pulses)
|
164
198
|
motor.publish(:ip, message.ip)
|
199
|
+
motor.group_objects.each do |group|
|
200
|
+
positions = group.motors.map(&:positionpercent)
|
201
|
+
position = nil
|
202
|
+
# calculate an average, but only if we know a position for
|
203
|
+
# every shade
|
204
|
+
if !positions.include?(:nil) && !positions.include?(nil)
|
205
|
+
position = positions.inject(&:+) / positions.length
|
206
|
+
end
|
207
|
+
|
208
|
+
group.publish(:positionpercent, position)
|
209
|
+
end
|
165
210
|
when SDN::Message::PostMotorStatus
|
166
211
|
if message.state == :running || motor.state == :running
|
167
212
|
follow_ups << SDN::Message::GetMotorStatus.new(message.src)
|
@@ -172,6 +217,11 @@ module SDN
|
|
172
217
|
motor.publish(:last_direction, message.last_direction)
|
173
218
|
motor.publish(:last_action_source, message.last_action_source)
|
174
219
|
motor.publish(:last_action_cause, message.last_action_cause)
|
220
|
+
motor.group_objects.each do |group|
|
221
|
+
states = group.motors.map(&:state).uniq
|
222
|
+
state = states.length == 1 ? states.first : 'mixed'
|
223
|
+
group.publish(:state, state)
|
224
|
+
end
|
175
225
|
when SDN::Message::PostMotorLimits
|
176
226
|
motor.publish(:uplimit, message.up_limit)
|
177
227
|
motor.publish(:downlimit, message.down_limit)
|
@@ -194,6 +244,9 @@ module SDN
|
|
194
244
|
@request_queue.concat(follow_ups)
|
195
245
|
@cond.signal if signal
|
196
246
|
end
|
247
|
+
rescue EOFError
|
248
|
+
puts "EOF reading"
|
249
|
+
exit 2
|
197
250
|
rescue SDN::MalformedMessage => e
|
198
251
|
puts "ignoring malformed message: #{e}" unless e.to_s =~ /issing data/
|
199
252
|
rescue => e
|
@@ -527,7 +580,7 @@ module SDN
|
|
527
580
|
|
528
581
|
motor = Motor.new(self, addr)
|
529
582
|
@motors[addr] = motor
|
530
|
-
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.to_a).join(","))
|
583
|
+
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.keys.sort.to_a).join(","))
|
531
584
|
|
532
585
|
sdn_addr = SDN::Message.parse_address(addr)
|
533
586
|
@mutex.synchronize do
|
@@ -547,7 +600,7 @@ module SDN
|
|
547
600
|
|
548
601
|
def add_group(addr)
|
549
602
|
addr = addr.gsub('.', '')
|
550
|
-
return if @groups.
|
603
|
+
return if @groups.key?(addr)
|
551
604
|
|
552
605
|
publish("#{addr}/$name", addr)
|
553
606
|
publish("#{addr}/$type", "Shade Group")
|
@@ -590,7 +643,11 @@ module SDN
|
|
590
643
|
publish("#{addr}/wink/$settable", "true")
|
591
644
|
publish("#{addr}/wink/$retained", "false")
|
592
645
|
|
593
|
-
|
646
|
+
publish("#{addr}/state/$name", "State of the motors; only set if all motors are in the same state")
|
647
|
+
publish("#{addr}/state/$datatype", "enum")
|
648
|
+
publish("#{addr}/state/$format", SDN::Message::PostMotorStatus::STATE.keys.join(','))
|
649
|
+
|
650
|
+
@groups[addr] = Group.new(self, addr)
|
594
651
|
publish("$nodes", (["discovery"] + @motors.keys.sort + @groups.to_a).join(","))
|
595
652
|
end
|
596
653
|
end
|
data/lib/sdn/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
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.7
|
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-05-
|
11
|
+
date: 2020-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: mqtt
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.5.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.5.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: net-telnet-rfc2217
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.0.2
|
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.
|
40
|
+
version: 0.0.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: serialport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.1
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: byebug
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|