somfy_sdn 2.4.1 → 2.5.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 +4 -4
- data/exe/somfy_sdn +1 -0
- data/lib/sdn/cli/mqtt/group.rb +11 -0
- data/lib/sdn/cli/mqtt/motor.rb +25 -1
- data/lib/sdn/cli/mqtt/p_queue.rb +6 -0
- data/lib/sdn/cli/mqtt/read.rb +46 -47
- data/lib/sdn/cli/mqtt/subscriptions.rb +8 -0
- data/lib/sdn/cli/mqtt/write.rb +67 -27
- data/lib/sdn/cli/mqtt.rb +256 -198
- data/lib/sdn/cli/provisioner.rb +34 -1
- data/lib/sdn/cli/simulator.rb +78 -11
- data/lib/sdn/cli.rb +6 -0
- data/lib/sdn/client.rb +42 -2
- data/lib/sdn/message/control.rb +136 -12
- data/lib/sdn/message/get.rb +57 -0
- data/lib/sdn/message/helpers.rb +64 -0
- data/lib/sdn/message/ilt2/get.rb +24 -0
- data/lib/sdn/message/ilt2/master_control.rb +10 -0
- data/lib/sdn/message/ilt2/post.rb +79 -13
- data/lib/sdn/message/ilt2/set.rb +112 -7
- data/lib/sdn/message/post.rb +181 -20
- data/lib/sdn/message/set.rb +166 -8
- data/lib/sdn/message.rb +121 -14
- data/lib/sdn/version.rb +2 -1
- data/lib/sdn.rb +13 -5
- metadata +5 -18
data/lib/sdn/cli/mqtt.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
require "mqtt"
|
|
4
4
|
require "mqtt-homeassistant"
|
|
5
5
|
require "uri"
|
|
6
|
-
require "set"
|
|
7
6
|
|
|
8
7
|
require "sdn/cli/mqtt/group"
|
|
9
8
|
require "sdn/cli/mqtt/motor"
|
|
@@ -15,18 +14,40 @@ require "sdn/version"
|
|
|
15
14
|
|
|
16
15
|
module SDN
|
|
17
16
|
module CLI
|
|
17
|
+
# @!visibility private
|
|
18
18
|
class MQTT
|
|
19
|
+
# Queue entry wrapper containing an SDN message, retry budget, and scheduling priority.
|
|
19
20
|
MessageAndRetries = Struct.new(:message, :remaining_retries, :priority)
|
|
20
21
|
|
|
21
22
|
include Read
|
|
22
23
|
include Write
|
|
23
24
|
include Subscriptions
|
|
24
25
|
|
|
26
|
+
# Time to wait, in seconds, for a direct response before retrying.
|
|
25
27
|
WAIT_TIME = 0.25
|
|
28
|
+
# Time to wait, in seconds, for broadcast or group discovery responses.
|
|
26
29
|
BROADCAST_WAIT = 5.0
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
# Discovered motors keyed by normalized address.
|
|
32
|
+
#
|
|
33
|
+
# @return [{String => SDN::CLI::MQTT::Motor}]
|
|
34
|
+
attr_reader :motors
|
|
35
|
+
|
|
36
|
+
# Discovered groups keyed by normalized address.
|
|
37
|
+
#
|
|
38
|
+
# @return [{String => SDN::CLI::MQTT::Group}]
|
|
39
|
+
attr_reader :groups
|
|
40
|
+
|
|
41
|
+
# Creates the MQTT bridge, publishes discovery metadata, and starts read/write loops.
|
|
42
|
+
#
|
|
43
|
+
# @param sdn [SDN::Client]
|
|
44
|
+
# @param mqtt_uri [String]
|
|
45
|
+
# @param device_id [String] Homie bridge device identifier
|
|
46
|
+
# @param base_topic [String] Homie base MQTT topic
|
|
47
|
+
# @param auto_discover [true, false] whether to periodically discover motors
|
|
48
|
+
# @param known_motors [<String>] motor addresses to seed discovery
|
|
49
|
+
# @param homie [true, false] whether to publish Homie metadata
|
|
50
|
+
# @param home_assistant [true, false] whether to publish Home Assistant discovery data
|
|
30
51
|
def initialize(sdn,
|
|
31
52
|
mqtt_uri,
|
|
32
53
|
device_id: "somfy",
|
|
@@ -81,10 +102,214 @@ module SDN
|
|
|
81
102
|
@mqtt.publish("#{@base_topic}/#{topic}", value, retain: true, qos: 1)
|
|
82
103
|
end
|
|
83
104
|
|
|
105
|
+
# Refreshes a group's published motor membership when one of its members changes.
|
|
106
|
+
#
|
|
107
|
+
# @param group_addr [(Integer, Integer, Integer))] group address bytes
|
|
108
|
+
#
|
|
109
|
+
# @return [void]
|
|
110
|
+
def touch_group(group_addr)
|
|
111
|
+
group = @groups[Message.print_address(group_addr).delete(".")]
|
|
112
|
+
group&.publish(:motors, group.motors_string)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Publishes MQTT metadata for a group, creating it if necessary.
|
|
116
|
+
#
|
|
117
|
+
# @param addr [String] printable group address
|
|
118
|
+
#
|
|
119
|
+
# @return [SDN::CLI::MQTT::Group]
|
|
120
|
+
def add_group(addr)
|
|
121
|
+
addr = addr.delete(".")
|
|
122
|
+
group = @groups[addr]
|
|
123
|
+
return group if group
|
|
124
|
+
|
|
125
|
+
@mqtt.batch_publish do
|
|
126
|
+
hass_device = {
|
|
127
|
+
identifiers: addr,
|
|
128
|
+
model: "Shade Group",
|
|
129
|
+
name: addr,
|
|
130
|
+
via_device: @device_id
|
|
131
|
+
}.freeze
|
|
132
|
+
node_id = "#{@device_id}_#{addr}"
|
|
133
|
+
|
|
134
|
+
if @homie
|
|
135
|
+
publish("#{addr}/$name", addr)
|
|
136
|
+
publish("#{addr}/$type", "Shade Group")
|
|
137
|
+
publish("#{addr}/$properties",
|
|
138
|
+
"discover,control,jog-ms,jog-pulses,position-pulses,position-percent," \
|
|
139
|
+
"ip,reset,state,last-direction,motors")
|
|
140
|
+
|
|
141
|
+
publish("#{addr}/discover/$name", "Trigger Motor Discovery")
|
|
142
|
+
publish("#{addr}/discover/$datatype", "enum")
|
|
143
|
+
publish("#{addr}/discover/$format", "discover")
|
|
144
|
+
publish("#{addr}/discover/$settable", "true")
|
|
145
|
+
publish("#{addr}/discover/$retained", "false")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
if @home_assistant
|
|
149
|
+
@mqtt.publish_hass_button("discover",
|
|
150
|
+
command_topic: "#{@base_topic}/#{addr}/discover/set",
|
|
151
|
+
device: hass_device,
|
|
152
|
+
icon: "mdi:search-add",
|
|
153
|
+
name: "Rediscover",
|
|
154
|
+
node_id:,
|
|
155
|
+
object_id: "discover",
|
|
156
|
+
payload_press: "discover",
|
|
157
|
+
unique_id: "#{node_id}_discover",
|
|
158
|
+
availability: @availability)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if @homie
|
|
162
|
+
publish("#{addr}/control/$name", "Control motors")
|
|
163
|
+
publish("#{addr}/control/$datatype", "enum")
|
|
164
|
+
publish("#{addr}/control/$format", "up,down,stop,wink,next_ip,previous_ip,refresh")
|
|
165
|
+
publish("#{addr}/control/$settable", "true")
|
|
166
|
+
publish("#{addr}/control/$retained", "false")
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if @home_assistant
|
|
170
|
+
@mqtt.publish_hass_cover("group",
|
|
171
|
+
command_topic: "#{@base_topic}/#{addr}/control/set",
|
|
172
|
+
device: hass_device,
|
|
173
|
+
icon: "mdi:roller-shade",
|
|
174
|
+
name: "Group",
|
|
175
|
+
node_id:,
|
|
176
|
+
payload_close: "down",
|
|
177
|
+
payload_open: "up",
|
|
178
|
+
payload_stop: "stop",
|
|
179
|
+
position_open: 0,
|
|
180
|
+
position_closed: 100,
|
|
181
|
+
position_topic: "#{@base_topic}/#{addr}/position-percent",
|
|
182
|
+
set_position_topic: "#{@base_topic}/#{addr}/position-percent/set",
|
|
183
|
+
state_topic: "#{@base_topic}/#{addr}/hass-state",
|
|
184
|
+
unique_id: "#{node_id}_group",
|
|
185
|
+
availability: @availability)
|
|
186
|
+
{
|
|
187
|
+
Wink: "mdi:emoticon-wink",
|
|
188
|
+
Next_IP: "mdi:skip-next",
|
|
189
|
+
Previous_IP: "mdi:skip-previous",
|
|
190
|
+
Refresh: "mdi:refresh"
|
|
191
|
+
}.each do |command, icon|
|
|
192
|
+
@mqtt.publish_hass_button(command.to_s.downcase,
|
|
193
|
+
command_topic: "#{@base_topic}/#{addr}/control/set",
|
|
194
|
+
device: hass_device,
|
|
195
|
+
icon:,
|
|
196
|
+
name: command.to_s.sub("_", " "),
|
|
197
|
+
node_id:,
|
|
198
|
+
payload_press: command.to_s.downcase,
|
|
199
|
+
unique_id: "#{node_id}_#{command.to_s.downcase}",
|
|
200
|
+
availability: @availability)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if @homie
|
|
205
|
+
publish("#{addr}/jog-ms/$name", "Jog motors by ms")
|
|
206
|
+
publish("#{addr}/jog-ms/$datatype", "integer")
|
|
207
|
+
publish("#{addr}/jog-ms/$format", "-65535:65535")
|
|
208
|
+
publish("#{addr}/jog-ms/$unit", "ms")
|
|
209
|
+
publish("#{addr}/jog-ms/$settable", "true")
|
|
210
|
+
publish("#{addr}/jog-ms/$retained", "false")
|
|
211
|
+
|
|
212
|
+
publish("#{addr}/jog-pulses/$name", "Jog motors by pulses")
|
|
213
|
+
publish("#{addr}/jog-pulses/$datatype", "integer")
|
|
214
|
+
publish("#{addr}/jog-pulses/$format", "-65535:65535")
|
|
215
|
+
publish("#{addr}/jog-pulses/$unit", "pulses")
|
|
216
|
+
publish("#{addr}/jog-pulses/$settable", "true")
|
|
217
|
+
publish("#{addr}/jog-pulses/$retained", "false")
|
|
218
|
+
|
|
219
|
+
publish("#{addr}/position-pulses/$name", "Position from up limit (in pulses)")
|
|
220
|
+
publish("#{addr}/position-pulses/$datatype", "integer")
|
|
221
|
+
publish("#{addr}/position-pulses/$format", "0:65535")
|
|
222
|
+
publish("#{addr}/position-pulses/$unit", "pulses")
|
|
223
|
+
publish("#{addr}/position-pulses/$settable", "true")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
if @home_assistant
|
|
227
|
+
@mqtt.publish_hass_number("position-pulses",
|
|
228
|
+
command_topic: "#{@base_topic}/#{addr}/position-pulses/set",
|
|
229
|
+
device: hass_device,
|
|
230
|
+
enabled_by_default: false,
|
|
231
|
+
max: 65_536,
|
|
232
|
+
min: 0,
|
|
233
|
+
name: "Position (Pulses)",
|
|
234
|
+
node_id:,
|
|
235
|
+
object_id: "position-pulses",
|
|
236
|
+
state_topic: "#{@base_topic}/#{addr}/position-pulses",
|
|
237
|
+
step: 10,
|
|
238
|
+
unit_of_measurement: "pulses",
|
|
239
|
+
unique_id: "#{node_id}_position-pulses",
|
|
240
|
+
availability: @availability)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
if @homie
|
|
244
|
+
publish("#{addr}/position-percent/$name", "Position (in %)")
|
|
245
|
+
publish("#{addr}/position-percent/$datatype", "integer")
|
|
246
|
+
publish("#{addr}/position-percent/$format", "0:100")
|
|
247
|
+
publish("#{addr}/position-percent/$unit", "%")
|
|
248
|
+
publish("#{addr}/position-percent/$settable", "true")
|
|
249
|
+
|
|
250
|
+
publish("#{addr}/ip/$name", "Intermediate Position")
|
|
251
|
+
publish("#{addr}/ip/$datatype", "integer")
|
|
252
|
+
publish("#{addr}/ip/$format", "1:16")
|
|
253
|
+
publish("#{addr}/ip/$settable", "true")
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
if @home_assistant
|
|
257
|
+
@mqtt.publish_hass_number("ip",
|
|
258
|
+
command_topic: "#{@base_topic}/#{addr}/ip/set",
|
|
259
|
+
device: hass_device,
|
|
260
|
+
name: "Intermediate Position",
|
|
261
|
+
max: 16,
|
|
262
|
+
min: 0,
|
|
263
|
+
node_id:,
|
|
264
|
+
object_id: "ip",
|
|
265
|
+
payload_reset: "",
|
|
266
|
+
state_topic: "#{@base_topic}/#{addr}/ip",
|
|
267
|
+
unique_id: "#{node_id}_ip",
|
|
268
|
+
availability: @availability)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
if @homie
|
|
272
|
+
publish("#{addr}/state/$name", "State of the motors")
|
|
273
|
+
publish("#{addr}/state/$datatype", "enum")
|
|
274
|
+
publish("#{addr}/state/$format", "#{Message::PostMotorStatus::STATE.keys.join(",")},mixed")
|
|
275
|
+
|
|
276
|
+
publish("#{addr}/last-direction/$name", "Direction of last motion")
|
|
277
|
+
publish("#{addr}/last-direction/$datatype", "enum")
|
|
278
|
+
publish("#{addr}/last-direction/$format", "#{Message::PostMotorStatus::DIRECTION.keys.join(",")},mixed")
|
|
279
|
+
|
|
280
|
+
publish("#{addr}/motors/$name", "Comma separated motor addresses that are members of this group")
|
|
281
|
+
publish("#{addr}/motors/$datatype", "string")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
group = @groups[addr] = Group.new(self, addr)
|
|
285
|
+
publish("$nodes", (["FFFFFF"] + @motors.keys.sort + @groups.keys.sort).join(",")) if @homie
|
|
286
|
+
end
|
|
287
|
+
group
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
private
|
|
291
|
+
|
|
292
|
+
def motor_hass_state(state, direction, position_percent)
|
|
293
|
+
if state == :running
|
|
294
|
+
(direction == :down) ? :closing : :opening
|
|
295
|
+
elsif position_percent&.zero?
|
|
296
|
+
:open
|
|
297
|
+
elsif position_percent == 100
|
|
298
|
+
:closed
|
|
299
|
+
else
|
|
300
|
+
:stopped
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
84
304
|
def subscribe(topic)
|
|
85
305
|
@mqtt.subscribe("#{@base_topic}/#{topic}")
|
|
86
306
|
end
|
|
87
307
|
|
|
308
|
+
# Adds a message to the prioritized write queue if it is not already present.
|
|
309
|
+
#
|
|
310
|
+
# @param message [Message]
|
|
311
|
+
#
|
|
312
|
+
# @return [void]
|
|
88
313
|
def enqueue(message)
|
|
89
314
|
@mutex.synchronize do
|
|
90
315
|
break if @queue.include?(message)
|
|
@@ -127,7 +352,7 @@ module SDN
|
|
|
127
352
|
name: "Somfy SDN Bridge",
|
|
128
353
|
identifiers: @device_id,
|
|
129
354
|
sw_version: SDN::VERSION
|
|
130
|
-
}
|
|
355
|
+
}.freeze
|
|
131
356
|
@mqtt.publish_hass_button("discover",
|
|
132
357
|
command_topic: "#{@base_topic}/FFFFFF/discover/set",
|
|
133
358
|
device: hass_device,
|
|
@@ -175,6 +400,12 @@ module SDN
|
|
|
175
400
|
end
|
|
176
401
|
end
|
|
177
402
|
|
|
403
|
+
# Publishes MQTT metadata for a motor and schedules follow-up SDN discovery queries.
|
|
404
|
+
#
|
|
405
|
+
# @param addr [String] printable motor address without separators
|
|
406
|
+
# @param node_type [Symbol, Integer] detected motor node type
|
|
407
|
+
#
|
|
408
|
+
# @return [SDN::CLI::MQTT::Motor]
|
|
178
409
|
def publish_motor(addr, node_type)
|
|
179
410
|
motor = nil
|
|
180
411
|
|
|
@@ -184,7 +415,7 @@ module SDN
|
|
|
184
415
|
model_id: node_type,
|
|
185
416
|
name: addr,
|
|
186
417
|
via_device: @device_id
|
|
187
|
-
}
|
|
418
|
+
}.freeze
|
|
188
419
|
node_id = "#{@device_id}_#{addr}"
|
|
189
420
|
|
|
190
421
|
if @homie
|
|
@@ -233,7 +464,7 @@ module SDN
|
|
|
233
464
|
device: hass_device,
|
|
234
465
|
icon: "mdi:search-add",
|
|
235
466
|
name: "Rediscover",
|
|
236
|
-
node_id
|
|
467
|
+
node_id:,
|
|
237
468
|
object_id: "discover",
|
|
238
469
|
payload_press: "true",
|
|
239
470
|
unique_id: "#{node_id}_discover",
|
|
@@ -254,7 +485,7 @@ module SDN
|
|
|
254
485
|
icon: "mdi:rename",
|
|
255
486
|
max: 16,
|
|
256
487
|
name: "Label",
|
|
257
|
-
node_id
|
|
488
|
+
node_id:,
|
|
258
489
|
unique_id: "#{node_id}_label",
|
|
259
490
|
availability: @availability)
|
|
260
491
|
end
|
|
@@ -297,7 +528,7 @@ module SDN
|
|
|
297
528
|
device: hass_device,
|
|
298
529
|
icon: "mdi:roller-shade",
|
|
299
530
|
name: "Motor",
|
|
300
|
-
node_id
|
|
531
|
+
node_id:,
|
|
301
532
|
payload_close: "down",
|
|
302
533
|
payload_open: "up",
|
|
303
534
|
payload_stop: "stop",
|
|
@@ -317,9 +548,9 @@ module SDN
|
|
|
317
548
|
@mqtt.publish_hass_button(command.to_s.downcase,
|
|
318
549
|
command_topic: "#{@base_topic}/#{addr}/control/set",
|
|
319
550
|
device: hass_device,
|
|
320
|
-
icon
|
|
551
|
+
icon:,
|
|
321
552
|
name: command.to_s.sub("_", " "),
|
|
322
|
-
node_id
|
|
553
|
+
node_id:,
|
|
323
554
|
payload_press: command.to_s.downcase,
|
|
324
555
|
unique_id: "#{node_id}_#{command.to_s.downcase}",
|
|
325
556
|
availability: @availability)
|
|
@@ -342,7 +573,7 @@ module SDN
|
|
|
342
573
|
max: 65_536,
|
|
343
574
|
min: 0,
|
|
344
575
|
name: "Position (Pulses)",
|
|
345
|
-
node_id
|
|
576
|
+
node_id:,
|
|
346
577
|
object_id: "position-pulses",
|
|
347
578
|
state_topic: "#{@base_topic}/#{addr}/position-pulses",
|
|
348
579
|
step: 10,
|
|
@@ -366,7 +597,7 @@ module SDN
|
|
|
366
597
|
name: "Intermediate Position",
|
|
367
598
|
max: 16,
|
|
368
599
|
min: 0,
|
|
369
|
-
node_id
|
|
600
|
+
node_id:,
|
|
370
601
|
object_id: "ip",
|
|
371
602
|
payload_reset: "",
|
|
372
603
|
state_topic: "#{@base_topic}/#{addr}/ip",
|
|
@@ -390,7 +621,7 @@ module SDN
|
|
|
390
621
|
icon: "mdi:roller-shade-closed",
|
|
391
622
|
max: 65_536,
|
|
392
623
|
min: 0,
|
|
393
|
-
node_id
|
|
624
|
+
node_id:,
|
|
394
625
|
payload_reset: "",
|
|
395
626
|
state_topic: "#{@base_topic}/#{addr}/down-limit",
|
|
396
627
|
step: 10,
|
|
@@ -422,7 +653,7 @@ module SDN
|
|
|
422
653
|
enabled_by_default: false,
|
|
423
654
|
entity_category: :config,
|
|
424
655
|
name: "Reset #{key.to_s.sub("_", " ")}",
|
|
425
|
-
node_id
|
|
656
|
+
node_id:,
|
|
426
657
|
payload_press: key,
|
|
427
658
|
unique_id: "#{node_id}_#{key}",
|
|
428
659
|
availability: @availability)
|
|
@@ -432,7 +663,8 @@ module SDN
|
|
|
432
663
|
if @homie
|
|
433
664
|
publish("#{addr}/last-action-source/$name", "Source of last action")
|
|
434
665
|
publish("#{addr}/last-action-source/$datatype", "enum")
|
|
435
|
-
publish("#{addr}/last-action-source/$format",
|
|
666
|
+
publish("#{addr}/last-action-source/$format",
|
|
667
|
+
(Message::PostMotorStatus::SOURCE.keys + [:bridge]).join(","))
|
|
436
668
|
end
|
|
437
669
|
|
|
438
670
|
if @home_assistant
|
|
@@ -441,7 +673,7 @@ module SDN
|
|
|
441
673
|
device_class: :enum,
|
|
442
674
|
entity_category: :diagnostic,
|
|
443
675
|
name: "Source of last action",
|
|
444
|
-
node_id
|
|
676
|
+
node_id:,
|
|
445
677
|
object_id: "last-action-source",
|
|
446
678
|
options: Message::PostMotorStatus::SOURCE.keys,
|
|
447
679
|
state_topic: "#{@base_topic}/#{addr}/last-action-source",
|
|
@@ -452,7 +684,8 @@ module SDN
|
|
|
452
684
|
if @homie
|
|
453
685
|
publish("#{addr}/last-action-cause/$name", "Cause of last action")
|
|
454
686
|
publish("#{addr}/last-action-cause/$datatype", "enum")
|
|
455
|
-
publish("#{addr}/last-action-cause/$format",
|
|
687
|
+
publish("#{addr}/last-action-cause/$format",
|
|
688
|
+
(Message::PostMotorStatus::CAUSE.keys + [:timeout]).join(","))
|
|
456
689
|
end
|
|
457
690
|
|
|
458
691
|
if @home_assistant
|
|
@@ -461,7 +694,7 @@ module SDN
|
|
|
461
694
|
device_class: :enum,
|
|
462
695
|
entity_category: :diagnostic,
|
|
463
696
|
name: "Cause of last action",
|
|
464
|
-
node_id
|
|
697
|
+
node_id:,
|
|
465
698
|
object_id: "last-action-cause",
|
|
466
699
|
options: Message::PostMotorStatus::CAUSE.keys,
|
|
467
700
|
state_topic: "#{@base_topic}/#{addr}/last-action-cause",
|
|
@@ -486,7 +719,7 @@ module SDN
|
|
|
486
719
|
max: 65_536,
|
|
487
720
|
min: 0,
|
|
488
721
|
name: "Up Limit",
|
|
489
|
-
node_id
|
|
722
|
+
node_id:,
|
|
490
723
|
payload_reset: "",
|
|
491
724
|
state_topic: "#{@base_topic}/#{addr}/up-limit",
|
|
492
725
|
step: 10,
|
|
@@ -509,7 +742,7 @@ module SDN
|
|
|
509
742
|
entity_category: :config,
|
|
510
743
|
icon: "mdi:circle-arrows",
|
|
511
744
|
name: "Motor rotation direction",
|
|
512
|
-
node_id
|
|
745
|
+
node_id:,
|
|
513
746
|
object_id: "direction",
|
|
514
747
|
options: %w[standard reversed],
|
|
515
748
|
state_topic: "#{@base_topic}/#{addr}/direction",
|
|
@@ -547,7 +780,7 @@ module SDN
|
|
|
547
780
|
max: 28,
|
|
548
781
|
min: 6,
|
|
549
782
|
name: "#{speed_type} speed",
|
|
550
|
-
node_id
|
|
783
|
+
node_id:,
|
|
551
784
|
state_topic: "#{@base_topic}/#{addr}/#{speed_type.downcase}-speed",
|
|
552
785
|
unit_of_measurement: "RPM",
|
|
553
786
|
unique_id: "#{node_id}_#{speed_type.downcase}-speed",
|
|
@@ -580,7 +813,7 @@ module SDN
|
|
|
580
813
|
max: 65_536,
|
|
581
814
|
min: 0,
|
|
582
815
|
name: "Intermediation Position #{ip} (Pulses)",
|
|
583
|
-
node_id
|
|
816
|
+
node_id:,
|
|
584
817
|
object_id: "ip#{ip}-pulses",
|
|
585
818
|
payload_reset: "",
|
|
586
819
|
state_topic: "#{@base_topic}/#{addr}/ip#{ip}-pulses",
|
|
@@ -607,7 +840,7 @@ module SDN
|
|
|
607
840
|
max: 100,
|
|
608
841
|
min: 0,
|
|
609
842
|
name: "Intermediation Position #{ip} (Percent)",
|
|
610
|
-
node_id
|
|
843
|
+
node_id:,
|
|
611
844
|
object_id: "ip#{ip}-percent",
|
|
612
845
|
payload_reset: "",
|
|
613
846
|
state_topic: "#{@base_topic}/#{addr}/ip#{ip}-percent",
|
|
@@ -665,181 +898,6 @@ module SDN
|
|
|
665
898
|
|
|
666
899
|
motor
|
|
667
900
|
end
|
|
668
|
-
|
|
669
|
-
def touch_group(group_addr)
|
|
670
|
-
group = @groups[Message.print_address(group_addr).delete(".")]
|
|
671
|
-
group&.publish(:motors, group.motors_string)
|
|
672
|
-
end
|
|
673
|
-
|
|
674
|
-
def add_group(addr)
|
|
675
|
-
addr = addr.delete(".")
|
|
676
|
-
group = @groups[addr]
|
|
677
|
-
return group if group
|
|
678
|
-
|
|
679
|
-
@mqtt.batch_publish do
|
|
680
|
-
hass_device = {
|
|
681
|
-
identifiers: addr,
|
|
682
|
-
model: "Shade Group",
|
|
683
|
-
name: addr,
|
|
684
|
-
via_device: @device_id
|
|
685
|
-
}
|
|
686
|
-
node_id = "#{@device_id}_#{addr}"
|
|
687
|
-
|
|
688
|
-
if @homie
|
|
689
|
-
publish("#{addr}/$name", addr)
|
|
690
|
-
publish("#{addr}/$type", "Shade Group")
|
|
691
|
-
publish("#{addr}/$properties",
|
|
692
|
-
"discover,control,jog-ms,jog-pulses,position-pulses,position-percent," \
|
|
693
|
-
"ip,reset,state,last-direction,motors")
|
|
694
|
-
|
|
695
|
-
publish("#{addr}/discover/$name", "Trigger Motor Discovery")
|
|
696
|
-
publish("#{addr}/discover/$datatype", "enum")
|
|
697
|
-
publish("#{addr}/discover/$format", "discover")
|
|
698
|
-
publish("#{addr}/discover/$settable", "true")
|
|
699
|
-
publish("#{addr}/discover/$retained", "false")
|
|
700
|
-
end
|
|
701
|
-
|
|
702
|
-
if @home_assistant
|
|
703
|
-
@mqtt.publish_hass_button("discover",
|
|
704
|
-
command_topic: "#{@base_topic}/#{addr}/discover/set",
|
|
705
|
-
device: hass_device,
|
|
706
|
-
icon: "mdi:search-add",
|
|
707
|
-
name: "Rediscover",
|
|
708
|
-
node_id: node_id,
|
|
709
|
-
object_id: "discover",
|
|
710
|
-
payload_press: "discover",
|
|
711
|
-
unique_id: "#{node_id}_discover",
|
|
712
|
-
availability: @availability)
|
|
713
|
-
end
|
|
714
|
-
|
|
715
|
-
if @homie
|
|
716
|
-
publish("#{addr}/control/$name", "Control motors")
|
|
717
|
-
publish("#{addr}/control/$datatype", "enum")
|
|
718
|
-
publish("#{addr}/control/$format", "up,down,stop,wink,next_ip,previous_ip,refresh")
|
|
719
|
-
publish("#{addr}/control/$settable", "true")
|
|
720
|
-
publish("#{addr}/control/$retained", "false")
|
|
721
|
-
end
|
|
722
|
-
|
|
723
|
-
if @home_assistant
|
|
724
|
-
@mqtt.publish_hass_cover("group",
|
|
725
|
-
command_topic: "#{@base_topic}/#{addr}/control/set",
|
|
726
|
-
device: hass_device,
|
|
727
|
-
icon: "mdi:roller-shade",
|
|
728
|
-
name: "Group",
|
|
729
|
-
node_id: node_id,
|
|
730
|
-
payload_close: "down",
|
|
731
|
-
payload_open: "up",
|
|
732
|
-
payload_stop: "stop",
|
|
733
|
-
position_open: 0,
|
|
734
|
-
position_closed: 100,
|
|
735
|
-
position_topic: "#{@base_topic}/#{addr}/position-percent",
|
|
736
|
-
set_position_topic: "#{@base_topic}/#{addr}/position-percent/set",
|
|
737
|
-
state_topic: "#{@base_topic}/#{addr}/hass-state",
|
|
738
|
-
unique_id: "#{node_id}_group",
|
|
739
|
-
availability: @availability)
|
|
740
|
-
{
|
|
741
|
-
Wink: "mdi:emoticon-wink",
|
|
742
|
-
Next_IP: "mdi:skip-next",
|
|
743
|
-
Previous_IP: "mdi:skip-previous",
|
|
744
|
-
Refresh: "mdi:refresh"
|
|
745
|
-
}.each do |command, icon|
|
|
746
|
-
@mqtt.publish_hass_button(command.to_s.downcase,
|
|
747
|
-
command_topic: "#{@base_topic}/#{addr}/control/set",
|
|
748
|
-
device: hass_device,
|
|
749
|
-
icon: icon,
|
|
750
|
-
name: command.to_s.sub("_", " "),
|
|
751
|
-
node_id: node_id,
|
|
752
|
-
payload_press: command.to_s.downcase,
|
|
753
|
-
unique_id: "#{node_id}_#{command.to_s.downcase}",
|
|
754
|
-
availability: @availability)
|
|
755
|
-
end
|
|
756
|
-
end
|
|
757
|
-
|
|
758
|
-
if @homie
|
|
759
|
-
publish("#{addr}/jog-ms/$name", "Jog motors by ms")
|
|
760
|
-
publish("#{addr}/jog-ms/$datatype", "integer")
|
|
761
|
-
publish("#{addr}/jog-ms/$format", "-65535:65535")
|
|
762
|
-
publish("#{addr}/jog-ms/$unit", "ms")
|
|
763
|
-
publish("#{addr}/jog-ms/$settable", "true")
|
|
764
|
-
publish("#{addr}/jog-ms/$retained", "false")
|
|
765
|
-
|
|
766
|
-
publish("#{addr}/jog-pulses/$name", "Jog motors by pulses")
|
|
767
|
-
publish("#{addr}/jog-pulses/$datatype", "integer")
|
|
768
|
-
publish("#{addr}/jog-pulses/$format", "-65535:65535")
|
|
769
|
-
publish("#{addr}/jog-pulses/$unit", "pulses")
|
|
770
|
-
publish("#{addr}/jog-pulses/$settable", "true")
|
|
771
|
-
publish("#{addr}/jog-pulses/$retained", "false")
|
|
772
|
-
|
|
773
|
-
publish("#{addr}/position-pulses/$name", "Position from up limit (in pulses)")
|
|
774
|
-
publish("#{addr}/position-pulses/$datatype", "integer")
|
|
775
|
-
publish("#{addr}/position-pulses/$format", "0:65535")
|
|
776
|
-
publish("#{addr}/position-pulses/$unit", "pulses")
|
|
777
|
-
publish("#{addr}/position-pulses/$settable", "true")
|
|
778
|
-
end
|
|
779
|
-
|
|
780
|
-
if @home_assistant
|
|
781
|
-
@mqtt.publish_hass_number("position-pulses",
|
|
782
|
-
command_topic: "#{@base_topic}/#{addr}/position-pulses/set",
|
|
783
|
-
device: hass_device,
|
|
784
|
-
enabled_by_default: false,
|
|
785
|
-
max: 65_536,
|
|
786
|
-
min: 0,
|
|
787
|
-
name: "Position (Pulses)",
|
|
788
|
-
node_id: node_id,
|
|
789
|
-
object_id: "position-pulses",
|
|
790
|
-
state_topic: "#{@base_topic}/#{addr}/position-pulses",
|
|
791
|
-
step: 10,
|
|
792
|
-
unit_of_measurement: "pulses",
|
|
793
|
-
unique_id: "#{node_id}_position-pulses",
|
|
794
|
-
availability: @availability)
|
|
795
|
-
end
|
|
796
|
-
|
|
797
|
-
if @homie
|
|
798
|
-
publish("#{addr}/position-percent/$name", "Position (in %)")
|
|
799
|
-
publish("#{addr}/position-percent/$datatype", "integer")
|
|
800
|
-
publish("#{addr}/position-percent/$format", "0:100")
|
|
801
|
-
publish("#{addr}/position-percent/$unit", "%")
|
|
802
|
-
publish("#{addr}/position-percent/$settable", "true")
|
|
803
|
-
|
|
804
|
-
publish("#{addr}/ip/$name", "Intermediate Position")
|
|
805
|
-
publish("#{addr}/ip/$datatype", "integer")
|
|
806
|
-
publish("#{addr}/ip/$format", "1:16")
|
|
807
|
-
publish("#{addr}/ip/$settable", "true")
|
|
808
|
-
end
|
|
809
|
-
|
|
810
|
-
if @home_assistant
|
|
811
|
-
@mqtt.publish_hass_number("ip",
|
|
812
|
-
command_topic: "#{@base_topic}/#{addr}/ip/set",
|
|
813
|
-
device: hass_device,
|
|
814
|
-
name: "Intermediate Position",
|
|
815
|
-
max: 16,
|
|
816
|
-
min: 0,
|
|
817
|
-
node_id: node_id,
|
|
818
|
-
object_id: "ip",
|
|
819
|
-
payload_reset: "",
|
|
820
|
-
state_topic: "#{@base_topic}/#{addr}/ip",
|
|
821
|
-
unique_id: "#{node_id}_ip",
|
|
822
|
-
availability: @availability)
|
|
823
|
-
end
|
|
824
|
-
|
|
825
|
-
if @homie
|
|
826
|
-
publish("#{addr}/state/$name", "State of the motors")
|
|
827
|
-
publish("#{addr}/state/$datatype", "enum")
|
|
828
|
-
publish("#{addr}/state/$format", "#{Message::PostMotorStatus::STATE.keys.join(",")},mixed")
|
|
829
|
-
|
|
830
|
-
publish("#{addr}/last-direction/$name", "Direction of last motion")
|
|
831
|
-
publish("#{addr}/last-direction/$datatype", "enum")
|
|
832
|
-
publish("#{addr}/last-direction/$format", "#{Message::PostMotorStatus::DIRECTION.keys.join(",")},mixed")
|
|
833
|
-
|
|
834
|
-
publish("#{addr}/motors/$name", "Comma separated motor addresses that are members of this group")
|
|
835
|
-
publish("#{addr}/motors/$datatype", "string")
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
group = @groups[addr] = Group.new(self, addr)
|
|
839
|
-
publish("$nodes", (["FFFFFF"] + @motors.keys.sort + @groups.keys.sort).join(",")) if @homie
|
|
840
|
-
end
|
|
841
|
-
group
|
|
842
|
-
end
|
|
843
901
|
end
|
|
844
902
|
end
|
|
845
903
|
end
|