balboa_worldwide_app 1.3.0 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/bwa_client +41 -0
- data/exe/bwa_mqtt_bridge +399 -0
- data/{bin → exe}/bwa_proxy +3 -2
- data/{bin → exe}/bwa_server +3 -2
- data/lib/balboa_worldwide_app.rb +3 -1
- data/lib/bwa/client.rb +123 -91
- data/lib/bwa/crc.rb +3 -1
- data/lib/bwa/discovery.rb +18 -17
- data/lib/bwa/logger.rb +9 -7
- data/lib/bwa/message.rb +67 -53
- data/lib/bwa/messages/configuration.rb +3 -1
- data/lib/bwa/messages/configuration_request.rb +3 -1
- data/lib/bwa/messages/control_configuration.rb +12 -9
- data/lib/bwa/messages/control_configuration_request.rb +13 -11
- data/lib/bwa/messages/filter_cycles.rb +50 -22
- data/lib/bwa/messages/ready.rb +3 -1
- data/lib/bwa/messages/{set_temperature.rb → set_target_temperature.rb} +5 -3
- data/lib/bwa/messages/set_temperature_scale.rb +5 -3
- data/lib/bwa/messages/set_time.rb +4 -2
- data/lib/bwa/messages/status.rb +53 -46
- data/lib/bwa/messages/toggle_item.rb +29 -27
- data/lib/bwa/proxy.rb +17 -18
- data/lib/bwa/server.rb +16 -14
- data/lib/bwa/version.rb +3 -1
- metadata +76 -24
- data/bin/bwa_client +0 -43
- data/bin/bwa_mqtt_bridge +0 -614
data/bin/bwa_mqtt_bridge
DELETED
@@ -1,614 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'mqtt'
|
4
|
-
require 'sd_notify'
|
5
|
-
require 'set'
|
6
|
-
require 'json'
|
7
|
-
|
8
|
-
require 'bwa/logger'
|
9
|
-
require 'bwa/client'
|
10
|
-
require 'bwa/discovery'
|
11
|
-
require 'bwa/version'
|
12
|
-
|
13
|
-
class MQTTBridge
|
14
|
-
def initialize(mqtt_uri, bwa, device_id: "bwa", base_topic: "homie")
|
15
|
-
@base_topic = "#{base_topic}/#{device_id}"
|
16
|
-
@mqtt = MQTT::Client.new(mqtt_uri)
|
17
|
-
@mqtt.set_will("#{@base_topic}/$state", "lost", true)
|
18
|
-
@mqtt.connect
|
19
|
-
@bwa = bwa
|
20
|
-
@attributes = {}
|
21
|
-
@things = Set.new
|
22
|
-
|
23
|
-
hass_discovery_topic = "homeassistant/"
|
24
|
-
@ha_binary_path = hass_discovery_topic + "binary_sensor/"
|
25
|
-
@ha_sensor_path = hass_discovery_topic + "sensor/"
|
26
|
-
@ha_switch_path = hass_discovery_topic + "switch/"
|
27
|
-
@ha_selects_path = hass_discovery_topic + "select/"
|
28
|
-
@ha_number_path = hass_discovery_topic + "number/"
|
29
|
-
|
30
|
-
@hass_device = {
|
31
|
-
device: {
|
32
|
-
identifiers: [device_id],
|
33
|
-
sw_version: BWA::VERSION,
|
34
|
-
name: "BWA Link"
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
# bwa availability topics (works for all devices)
|
39
|
-
@hass_availability = {
|
40
|
-
availability_topic: "#{@base_topic}/$state",
|
41
|
-
payload_available: "ready",
|
42
|
-
payload_not_available: "lost"
|
43
|
-
}
|
44
|
-
|
45
|
-
publish_basic_attributes
|
46
|
-
publish_filtercycles
|
47
|
-
|
48
|
-
# Home Assistant MQTT Discovery Section
|
49
|
-
publish_hass_discovery
|
50
|
-
|
51
|
-
# Tell systemd we've started up OK. Ignored if systemd not in use.
|
52
|
-
BWA.logger.warn "Balboa MQTT Bridge running (version #{BWA::VERSION})"
|
53
|
-
SdNotify.ready
|
54
|
-
|
55
|
-
bwa_thread = Thread.new do
|
56
|
-
loop do
|
57
|
-
begin
|
58
|
-
message = @bwa.poll
|
59
|
-
next if message.is_a?(BWA::Messages::Ready)
|
60
|
-
|
61
|
-
case message
|
62
|
-
when BWA::Messages::ControlConfiguration
|
63
|
-
publish("spa/$type", message.model)
|
64
|
-
when BWA::Messages::ControlConfiguration2
|
65
|
-
message.pumps.each_with_index do |speed, i|
|
66
|
-
publish_pump(i + 1, speed) if speed != 0
|
67
|
-
end
|
68
|
-
message.lights.each_with_index do |exists, i|
|
69
|
-
publish_thing(:light, i + 1) if exists
|
70
|
-
end
|
71
|
-
message.aux.each_with_index do |exists, i|
|
72
|
-
publish_thing(:aux, i + 1) if exists
|
73
|
-
end
|
74
|
-
publish_mister if message.mister
|
75
|
-
publish_blower(message.blower) if message.blower != 0
|
76
|
-
publish_circpump if message.circ_pump
|
77
|
-
publish("$state", "ready")
|
78
|
-
when BWA::Messages::FilterCycles
|
79
|
-
publish_attribute("spa/filter1hour",message.filter1_hour)
|
80
|
-
publish_attribute("spa/filter1minute",message.filter1_minute)
|
81
|
-
publish_attribute("spa/filter1durationhours",message.filter1_duration_hours)
|
82
|
-
publish_attribute("spa/filter1durationminutes",message.filter1_duration_minutes)
|
83
|
-
publish_attribute("spa/filter2enabled",message.filter2_enabled)
|
84
|
-
publish_attribute("spa/filter2hour",message.filter2_hour)
|
85
|
-
publish_attribute("spa/filter2minute",message.filter2_minute)
|
86
|
-
publish_attribute("spa/filter2durationhours",message.filter2_duration_hours)
|
87
|
-
publish_attribute("spa/filter2durationminutes",message.filter2_duration_minutes)
|
88
|
-
when BWA::Messages::Status
|
89
|
-
@bwa.request_control_info unless @bwa.last_control_configuration
|
90
|
-
@bwa.request_control_info2 unless @bwa.last_control_configuration2
|
91
|
-
@bwa.request_filter_configuration unless @bwa.last_filter_configuration
|
92
|
-
|
93
|
-
# make sure time is in sync
|
94
|
-
now = Time.now
|
95
|
-
now_minutes = now.hour * 60 + now.min
|
96
|
-
spa_minutes = message.hour * 60 + message.minute
|
97
|
-
# check the difference in both directions
|
98
|
-
diff = [(spa_minutes - now_minutes) % 1440, 1440 - (spa_minutes - now_minutes) % 1440].min
|
99
|
-
|
100
|
-
# allow a skew of 1 minute, since the seconds will always be off
|
101
|
-
if diff > 1
|
102
|
-
BWA.logger.info "Spa time #{"%02d:%02d" % [message.hour, message.minute]}, actually #{"%02d:%02d" % [now.hour, now.min]}; correcting difference of #{diff} min"
|
103
|
-
@bwa.set_time(now.hour, now.min, message.twenty_four_hour_time)
|
104
|
-
end
|
105
|
-
publish_attribute("spa/hold", message.hold)
|
106
|
-
publish_attribute("spa/priming", message.priming)
|
107
|
-
publish_attribute("spa/heatingmode", message.heating_mode)
|
108
|
-
publish_attribute("spa/temperaturescale", message.temperature_scale)
|
109
|
-
publish_attribute("spa/24htime", message.twenty_four_hour_time)
|
110
|
-
publish_attribute("spa/heating", message.heating)
|
111
|
-
publish_attribute("spa/temperaturerange", message.temperature_range)
|
112
|
-
publish_attribute("spa/currenttemperature", message.current_temperature)
|
113
|
-
publish_attribute("spa/currenttemperature/$unit", "º#{message.temperature_scale.to_s[0].upcase}")
|
114
|
-
publish_attribute("spa/settemperature", message.set_temperature)
|
115
|
-
publish_attribute("spa/settemperature/$unit", "º#{message.temperature_scale.to_s[0].upcase}")
|
116
|
-
if message.temperature_scale == :celsius
|
117
|
-
publish_attribute("spa/currenttemperature/$format", "0:42")
|
118
|
-
publish_attribute("spa/settemperature/$format", message.temperature_range == :high ? "26:40" : "10:26")
|
119
|
-
publish_hass_discovery_settemp(:celsius)
|
120
|
-
else
|
121
|
-
publish_attribute("spa/currenttemperature/$format", "32:108")
|
122
|
-
publish_attribute("spa/settemperature/$format", message.temperature_range == :high ? "80:106" : "50:99")
|
123
|
-
publish_hass_discovery_settemp(:fahrenheit)
|
124
|
-
end
|
125
|
-
publish_attribute("spa/filter1", message.filter[0])
|
126
|
-
publish_attribute("spa/filter2", message.filter[1])
|
127
|
-
|
128
|
-
publish_attribute("spa/circpump", message.circ_pump) if @bwa.last_control_configuration2&.circ_pump
|
129
|
-
publish_attribute("spa/blower", message.blower) if @bwa.last_control_configuration2&.blower.to_i != 0
|
130
|
-
publish_attribute("spa/mister", message.mister) if @bwa.last_control_configuration2&.mister
|
131
|
-
(0..5).each do |i|
|
132
|
-
publish_attribute("spa/pump#{i + 1}", message.pumps[i]) if @bwa.last_control_configuration2&.pumps&.[](i).to_i != 0
|
133
|
-
end
|
134
|
-
(0..1).each do |i|
|
135
|
-
publish_attribute("spa/light#{i + 1}", message.lights[i]) if @bwa.last_control_configuration2&.lights&.[](i)
|
136
|
-
end
|
137
|
-
(0..1).each do |i|
|
138
|
-
publish_attribute("spa/aux#{i + 1}", message.lights[i]) if @bwa.last_control_configuration2&.aux&.[](i)
|
139
|
-
end
|
140
|
-
|
141
|
-
# Tell systemd we are still alive and kicking. Ignored if systemd not in use.
|
142
|
-
SdNotify.watchdog
|
143
|
-
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
@mqtt.get do |topic, value|
|
150
|
-
BWA.logger.warn "from mqtt: #{value.inspect} at #{topic}"
|
151
|
-
case topic[@base_topic.length + 1..-1]
|
152
|
-
when "spa/hold/set"
|
153
|
-
next @bwa.toggle_hold if value == 'toggle'
|
154
|
-
next unless %w{true false}.include?(value)
|
155
|
-
@bwa.set_hold(value == 'true')
|
156
|
-
when "spa/heatingmode/set"
|
157
|
-
next @bwa.toggle_heating_mode if value == 'toggle'
|
158
|
-
next unless %w{ready rest}.include?(value)
|
159
|
-
@bwa.set_heating_mode(value.to_sym)
|
160
|
-
when "spa/temperaturescale/set"
|
161
|
-
next unless %w{fahrenheit celsius}.include?(value)
|
162
|
-
@bwa.set_temperature_scale(value.to_sym)
|
163
|
-
when "spa/24htime/set"
|
164
|
-
next unless %w{true false}.include?(value)
|
165
|
-
now = Time.now
|
166
|
-
@bwa.set_time(now.hour, now.min, value == 'true')
|
167
|
-
when "spa/temperaturerange/set"
|
168
|
-
next @bwa.toggle_temperature_range if value == 'toggle'
|
169
|
-
next unless %w{low high}.include?(value)
|
170
|
-
@bwa.set_temperature_range(value.to_sym)
|
171
|
-
when %r{^spa/pump([1-6])/set$}
|
172
|
-
next @bwa.toggle_pump($1.to_i) if value == 'toggle'
|
173
|
-
@bwa.set_pump($1.to_i, value.to_i)
|
174
|
-
when %r{^spa/(light|aux)([12])/set$}
|
175
|
-
next @bwa.send(:"toggle_#{$1}", $2.to_i) if value == 'toggle'
|
176
|
-
next unless %w{true false}.include?(value)
|
177
|
-
@bwa.send(:"set_#{$1}", $2.to_i, value == 'true')
|
178
|
-
when "spa/mister/set"
|
179
|
-
next @bwa.toggle_mister if value == 'toggle'
|
180
|
-
next unless %w{true false}.include?(value)
|
181
|
-
@bwa.set_mister(value == 'true')
|
182
|
-
when "spa/blower/set"
|
183
|
-
next @bwa.toggle_blower if value == 'toggle'
|
184
|
-
@bwa.set_blower(value.to_i)
|
185
|
-
when "spa/settemperature/set"
|
186
|
-
@bwa.set_temperature(value.to_f)
|
187
|
-
when %r{^spa/(filter[12](hour|minute|durationhours|durationminutes|enabled))/set$}
|
188
|
-
@bwa.set_filtercycles($1, value)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def publish(topic, value)
|
194
|
-
BWA.logger.debug " to mqtt: #{topic}: #{value}"
|
195
|
-
@mqtt.publish("#{@base_topic}/#{topic}", value, true)
|
196
|
-
end
|
197
|
-
|
198
|
-
def publish_attribute(attr, value)
|
199
|
-
if !@attributes.key?(attr) || @attributes[attr] != value
|
200
|
-
publish(attr, value.to_s)
|
201
|
-
@attributes[attr] = value
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def subscribe(topic)
|
206
|
-
@mqtt.subscribe("#{@base_topic}/#{topic}")
|
207
|
-
end
|
208
|
-
|
209
|
-
def publish_hass_discovery()
|
210
|
-
#Priming
|
211
|
-
priming_config = {
|
212
|
-
name: "Hot Tub Priming",
|
213
|
-
state_topic: "#{@base_topic}/spa/priming",
|
214
|
-
device_class: "running",
|
215
|
-
unique_id: "spa_priming",
|
216
|
-
icon: "mdi:fast-forward"
|
217
|
-
}
|
218
|
-
@mqtt.publish(@ha_binary_path + "priming/config", priming_config
|
219
|
-
.merge(@hass_device)
|
220
|
-
.merge(@hass_availability)
|
221
|
-
.to_json, true)
|
222
|
-
|
223
|
-
#Circulation Pump
|
224
|
-
circ_config = {
|
225
|
-
name: "Hot Tub Circulation Pump",
|
226
|
-
state_topic: "#{@base_topic}/spa/circpump",
|
227
|
-
device_class: "running",
|
228
|
-
unique_id: "spa_circpump",
|
229
|
-
icon: "mdi:sync"
|
230
|
-
}
|
231
|
-
@mqtt.publish(@ha_binary_path + "circpump/config", circ_config
|
232
|
-
.merge(@hass_device)
|
233
|
-
.merge(@hass_availability)
|
234
|
-
.to_json, true)
|
235
|
-
|
236
|
-
# Filter 1 Cycle Running
|
237
|
-
filter1_config = {
|
238
|
-
name: "Hot Tub Filter 1 Cycle Running",
|
239
|
-
state_topic: "#{@base_topic}/spa/filter1",
|
240
|
-
device_class: "running",
|
241
|
-
unique_id: "spa_filtercycle1",
|
242
|
-
icon: "mdi:air-filter"
|
243
|
-
}
|
244
|
-
@mqtt.publish(@ha_binary_path + "filter1/config", filter1_config
|
245
|
-
.merge(@hass_device)
|
246
|
-
.merge(@hass_availability)
|
247
|
-
.to_json, true)
|
248
|
-
|
249
|
-
# Filter 2 Cycle Running
|
250
|
-
filter2_config = {
|
251
|
-
name: "Hot Tub Filter 2 Cycle Running",
|
252
|
-
state_topic: "#{@base_topic}/spa/filter2",
|
253
|
-
device_class: "running",
|
254
|
-
unique_id: "spa_filtercycle2",
|
255
|
-
icon: "mdi:air-filter"
|
256
|
-
}
|
257
|
-
@mqtt.publish(@ha_binary_path + "filter2/config", filter2_config
|
258
|
-
.merge(@hass_device)
|
259
|
-
.merge(@hass_availability)
|
260
|
-
.to_json, true)
|
261
|
-
|
262
|
-
# Heater Running
|
263
|
-
heater_config = {
|
264
|
-
name: "Hot Tub Heater",
|
265
|
-
state_topic: "#{@base_topic}/spa/heating",
|
266
|
-
device_class: "running",
|
267
|
-
unique_id: "spa_heating",
|
268
|
-
icon: "mdi:hot-tub"
|
269
|
-
}
|
270
|
-
@mqtt.publish(@ha_binary_path + "heating/config", heater_config
|
271
|
-
.merge(@hass_device)
|
272
|
-
.merge(@hass_availability)
|
273
|
-
.to_json, true)
|
274
|
-
|
275
|
-
# Heating Mode
|
276
|
-
heatingmode_config = {
|
277
|
-
name: "Hot Tub Heating Mode",
|
278
|
-
state_topic: "#{@base_topic}/spa/heatingmode",
|
279
|
-
command_topic: "#{@base_topic}/spa/heatingmode/set",
|
280
|
-
unique_id: "spa_heating_mode",
|
281
|
-
options: ["ready","rest","ready_in_rest"],
|
282
|
-
icon: "mdi:cog-play"
|
283
|
-
}
|
284
|
-
@mqtt.publish(@ha_selects_path + "heatingmode/config", heatingmode_config
|
285
|
-
.merge(@hass_device)
|
286
|
-
.merge(@hass_availability)
|
287
|
-
.to_json, true)
|
288
|
-
|
289
|
-
# Temperature Range
|
290
|
-
temperaturerange_config = {
|
291
|
-
name: "Hot Tub Temperature Range",
|
292
|
-
state_topic: "#{@base_topic}/spa/temperaturerange",
|
293
|
-
command_topic: "#{@base_topic}/spa/temperaturerange/set",
|
294
|
-
unique_id: "spa_temperaturerange_range",
|
295
|
-
options: ["high","low"],
|
296
|
-
icon: "mdi:thermometer-lines"
|
297
|
-
}
|
298
|
-
@mqtt.publish(@ha_selects_path + "temperaturerange/config", temperaturerange_config
|
299
|
-
.merge(@hass_device)
|
300
|
-
.merge(@hass_availability)
|
301
|
-
.to_json, true)
|
302
|
-
|
303
|
-
# Temperature Scale
|
304
|
-
temperaturescale_config = {
|
305
|
-
name: "Hot Tub Temperature Scale",
|
306
|
-
state_topic: "#{@base_topic}/spa/temperaturescale",
|
307
|
-
unique_id: "spa_temperaturescale"
|
308
|
-
}
|
309
|
-
@mqtt.publish(@ha_sensor_path + "temperaturescale/config", temperaturescale_config
|
310
|
-
.merge(@hass_device)
|
311
|
-
.merge(@hass_availability)
|
312
|
-
.to_json, true)
|
313
|
-
|
314
|
-
# Current Temperature
|
315
|
-
currenttemperature_config = {
|
316
|
-
name: "Hot Tub Current Temperature",
|
317
|
-
state_topic: "#{@base_topic}/spa/currenttemperature",
|
318
|
-
unique_id: "spa_currenttemperature",
|
319
|
-
device_class: "temperature"
|
320
|
-
}
|
321
|
-
@mqtt.publish(@ha_sensor_path + "currenttemperature/config", currenttemperature_config
|
322
|
-
.merge(@hass_device)
|
323
|
-
.merge(@hass_availability)
|
324
|
-
.to_json, true)
|
325
|
-
|
326
|
-
# Set Temperature - Assuming fahrenheit first
|
327
|
-
settemperature_config = {
|
328
|
-
name: "Hot Tub Set Temperature",
|
329
|
-
unique_id: "spa_settemperature",
|
330
|
-
state_topic: "#{@base_topic}/spa/settemperature",
|
331
|
-
command_topic: "#{@base_topic}/spa/settemperature/set",
|
332
|
-
min: 50,
|
333
|
-
max: 106,
|
334
|
-
unit_of_measurement: "°F",
|
335
|
-
icon: "mdi:thermometer"
|
336
|
-
}
|
337
|
-
@mqtt.publish(@ha_number_path + "settemperature/config", settemperature_config
|
338
|
-
.merge(@hass_device)
|
339
|
-
.merge(@hass_availability)
|
340
|
-
.to_json, true)
|
341
|
-
end
|
342
|
-
|
343
|
-
def publish_hass_discovery_settemp(scale)
|
344
|
-
return if scale == @last_scale
|
345
|
-
@last_scale = scale
|
346
|
-
|
347
|
-
# Update temp ranges when scale changes
|
348
|
-
settemperature_config = {
|
349
|
-
name: "Hot Tub Set Temperature",
|
350
|
-
unique_id: "spa_settemperature",
|
351
|
-
state_topic: "#{@base_topic}/spa/settemperature",
|
352
|
-
command_topic: "#{@base_topic}/spa/settemperature/set",
|
353
|
-
min: 50,
|
354
|
-
max: 106,
|
355
|
-
unit_of_measurement: "°F",
|
356
|
-
icon: "mdi:thermometer"
|
357
|
-
}
|
358
|
-
|
359
|
-
if scale == :celsius
|
360
|
-
settemperature_config[:min] = 10
|
361
|
-
settemperature_config[:max] = 40
|
362
|
-
settemperature_config[:unit_of_measurement] = "°C"
|
363
|
-
else
|
364
|
-
settemperature_config[:min] = 50
|
365
|
-
settemperature_config[:max] = 106
|
366
|
-
settemperature_config[:unit_of_measurement] = "°F"
|
367
|
-
end
|
368
|
-
|
369
|
-
@mqtt.publish(@ha_number_path + "settemperature/config", settemperature_config
|
370
|
-
.merge(@hass_device)
|
371
|
-
.merge(@hass_availability)
|
372
|
-
.to_json, true)
|
373
|
-
end
|
374
|
-
|
375
|
-
def publish_hass_discovery_pumps(i, speeds)
|
376
|
-
pump_config = {
|
377
|
-
name: "Hot Tub Pump #{i}",
|
378
|
-
unique_id: "spa_pump#{i}",
|
379
|
-
state_topic: "#{@base_topic}/spa/pump#{i}",
|
380
|
-
command_topic: "#{@base_topic}/spa/pump#{i}/set",
|
381
|
-
payload_on: "toggle",
|
382
|
-
payload_off: "toggle",
|
383
|
-
state_on: "2",
|
384
|
-
state_off: "0",
|
385
|
-
icon: "mdi:chart-bubble"
|
386
|
-
}
|
387
|
-
@mqtt.publish(@ha_switch_path + "pump#{i}/config", pump_config
|
388
|
-
.merge(@hass_device)
|
389
|
-
.merge(@hass_availability)
|
390
|
-
.to_json, true)
|
391
|
-
end
|
392
|
-
|
393
|
-
def publish_hass_discovery_things(type, i)
|
394
|
-
#Things - Lights and such
|
395
|
-
thing_config = {
|
396
|
-
name: "Hot Tub #{type} #{i}",
|
397
|
-
unique_id: "spa_#{type}#{i}",
|
398
|
-
state_topic: "#{@base_topic}/spa/#{type}#{i}",
|
399
|
-
command_topic: "#{@base_topic}/spa/#{type}#{i}/set",
|
400
|
-
payload_on: "true",
|
401
|
-
payload_off: "false",
|
402
|
-
state_on: "true",
|
403
|
-
state_off: "false"
|
404
|
-
}
|
405
|
-
case type
|
406
|
-
when :light
|
407
|
-
thing_config[:icon] = "mdi:car-parking-lights"
|
408
|
-
when :mister
|
409
|
-
thing_config[:icon] = "mdi:sprinkler-fire"
|
410
|
-
when :blower
|
411
|
-
thing_config[:icon] = "mdi:chart-bubble"
|
412
|
-
end
|
413
|
-
@mqtt.publish(@ha_switch_path+ "#{type}#{i}/config", thing_config
|
414
|
-
.merge(@hass_device)
|
415
|
-
.merge(@hass_availability)
|
416
|
-
.to_json, true)
|
417
|
-
end
|
418
|
-
|
419
|
-
def publish_basic_attributes
|
420
|
-
publish("$homie", "4.0.0")
|
421
|
-
publish("$name", "BWA Spa")
|
422
|
-
publish("$state", "init")
|
423
|
-
publish("$nodes", "spa")
|
424
|
-
|
425
|
-
publish("spa/$name", "BWA Spa")
|
426
|
-
publish("spa/$type", "spa")
|
427
|
-
publish_nodes
|
428
|
-
|
429
|
-
publish("spa/hold/$name", "In Hold mode")
|
430
|
-
publish("spa/hold/$datatype", "boolean")
|
431
|
-
publish("spa/hold/$settable", "true")
|
432
|
-
subscribe("spa/hold/set")
|
433
|
-
|
434
|
-
publish("spa/priming/$name", "Is the pump priming")
|
435
|
-
publish("spa/priming/$datatype", "boolean")
|
436
|
-
|
437
|
-
publish("spa/heatingmode/$name", "Current heating mode")
|
438
|
-
publish("spa/heatingmode/$datatype", "enum")
|
439
|
-
publish("spa/heatingmode/$format", "ready,rest,ready_in_rest")
|
440
|
-
publish("spa/heatingmode/$settable", "true")
|
441
|
-
subscribe("spa/heatingmode/set")
|
442
|
-
|
443
|
-
publish("spa/temperaturescale/$name", "Temperature scale")
|
444
|
-
publish("spa/temperaturescale/$datatype", "enum")
|
445
|
-
publish("spa/temperaturescale/$format", "fahrenheit,celsius")
|
446
|
-
publish("spa/temperaturescale/$settable", "true")
|
447
|
-
subscribe("spa/temperaturescale/set")
|
448
|
-
|
449
|
-
publish("spa/24htime/$name", "Clock is 24 hour time")
|
450
|
-
publish("spa/24htime/$datatype", "boolean")
|
451
|
-
publish("spa/24htime/$settable", "true")
|
452
|
-
subscribe("spa/24htime/set")
|
453
|
-
|
454
|
-
publish("spa/heating/$name", "Heater is currently running")
|
455
|
-
publish("spa/heating/$datatype", "boolean")
|
456
|
-
|
457
|
-
publish("spa/temperaturerange/$name", "Current temperature range")
|
458
|
-
publish("spa/temperaturerange/$datatype", "enum")
|
459
|
-
publish("spa/temperaturerange/$format", "high,low")
|
460
|
-
publish("spa/temperaturerange/$settable", "true")
|
461
|
-
subscribe("spa/temperaturerange/set")
|
462
|
-
|
463
|
-
publish("spa/currenttemperature/$name", "Current temperature")
|
464
|
-
publish("spa/currenttemperature/$datatype", "float")
|
465
|
-
|
466
|
-
publish("spa/settemperature/$name", "Set Temperature")
|
467
|
-
publish("spa/settemperature/$datatype", "float")
|
468
|
-
publish("spa/settemperature/$settable", "true")
|
469
|
-
subscribe("spa/settemperature/set")
|
470
|
-
|
471
|
-
publish("spa/filter1/$name", "Filter cycle 1 is currently running")
|
472
|
-
publish("spa/filter1/$datatype", "boolean")
|
473
|
-
|
474
|
-
publish("spa/filter2/$name", "Filter cycle 2 is currently running")
|
475
|
-
publish("spa/filter2/$datatype", "boolean")
|
476
|
-
end
|
477
|
-
|
478
|
-
def publish_pump(i, speeds)
|
479
|
-
publish("spa/pump#{i}/$name", "Pump #{i} speed")
|
480
|
-
publish("spa/pump#{i}/$datatype", "integer")
|
481
|
-
publish("spa/pump#{i}/$format", "0:#{speeds}")
|
482
|
-
publish("spa/pump#{i}/$settable", "true")
|
483
|
-
subscribe("spa/pump#{i}/set")
|
484
|
-
|
485
|
-
@things << "pump#{i}"
|
486
|
-
publish_hass_discovery_pumps(i, speeds)
|
487
|
-
publish_nodes
|
488
|
-
end
|
489
|
-
|
490
|
-
def publish_thing(type, i)
|
491
|
-
publish("spa/#{type}#{i}/$name", "#{type} #{i}")
|
492
|
-
publish("spa/#{type}#{i}/$datatype", "boolean")
|
493
|
-
publish("spa/#{type}#{i}/$settable", "true")
|
494
|
-
subscribe("spa/#{type}#{i}/set")
|
495
|
-
|
496
|
-
@things << "#{type}#{i}"
|
497
|
-
publish_hass_discovery_things(type, i)
|
498
|
-
publish_nodes
|
499
|
-
end
|
500
|
-
|
501
|
-
def publish_mister
|
502
|
-
publish("spa/mister/$name", type)
|
503
|
-
publish("spa/mister/$datatype", "boolean")
|
504
|
-
publish("spa/mister/$settable", "true")
|
505
|
-
subscribe("spa/mister/set")
|
506
|
-
|
507
|
-
@things << "mister"
|
508
|
-
publish_nodes
|
509
|
-
end
|
510
|
-
|
511
|
-
def publish_blower(speeds)
|
512
|
-
publish("spa/blower/$name", "Blower speed")
|
513
|
-
publish("spa/blower/$datatype", "integer")
|
514
|
-
publish("spa/blower/$format", "0:#{speeds}")
|
515
|
-
publish("spa/blower/$settable", "true")
|
516
|
-
subscribe("spa/blower/set")
|
517
|
-
|
518
|
-
@things << "blower"
|
519
|
-
publish_nodes
|
520
|
-
end
|
521
|
-
|
522
|
-
def publish_circpump
|
523
|
-
publish("spa/circpump/$name", "Circ pump is currently running")
|
524
|
-
publish("spa/circpump/$datatype", "boolean")
|
525
|
-
@things << "circpump"
|
526
|
-
|
527
|
-
publish_nodes
|
528
|
-
end
|
529
|
-
|
530
|
-
def publish_filtercycles
|
531
|
-
publish("spa/filter1hour/$name", "Filter Cycle 1 Start Hour")
|
532
|
-
publish("spa/filter1hour/$datatype", "integer")
|
533
|
-
publish("spa/filter1hour/$format", "0:24")
|
534
|
-
publish("spa/filter1hour/$settable", "true")
|
535
|
-
|
536
|
-
publish("spa/filter1minute/$name", "Filter Cycle 1 Start Minutes")
|
537
|
-
publish("spa/filter1minute/$datatype", "integer")
|
538
|
-
publish("spa/filter1minute/$format", "0:59")
|
539
|
-
publish("spa/filter1minute/$settable", "true")
|
540
|
-
|
541
|
-
publish("spa/filter1durationhours/$name", "Filter Cycle 1 Duration Hours")
|
542
|
-
publish("spa/filter1durationhours/$datatype", "integer")
|
543
|
-
publish("spa/filter1durationhours/$format", "0:24")
|
544
|
-
publish("spa/filter1durationhours/$settable", "true")
|
545
|
-
|
546
|
-
publish("spa/filter1durationminutes/$name", "Filter Cycle 1 Duration Minutes")
|
547
|
-
publish("spa/filter1durationminutes/$datatype", "integer")
|
548
|
-
publish("spa/filter1durationminutes/$format", "0:59")
|
549
|
-
publish("spa/filter1durationminutes/$settable", "true")
|
550
|
-
|
551
|
-
publish("spa/filter2enabled/$name", "Filter Cycle 2 Enabled")
|
552
|
-
publish("spa/filter2enabled/$datatype", "boolean")
|
553
|
-
publish("spa/filter2enabled/$settable", "true")
|
554
|
-
|
555
|
-
publish("spa/filter2hour/$name", "Filter Cycle 2 Start Hour")
|
556
|
-
publish("spa/filter2hour/$datatype", "integer")
|
557
|
-
publish("spa/filter2hour/$format", "0:24")
|
558
|
-
publish("spa/filter2hour/$settable", "true")
|
559
|
-
|
560
|
-
publish("spa/filter2minute/$name", "Filter Cycle 2 Start Minutes")
|
561
|
-
publish("spa/filter2minute/$datatype", "integer")
|
562
|
-
publish("spa/filter2minute/$format", "0:59")
|
563
|
-
publish("spa/filter2minute/$settable", "true")
|
564
|
-
|
565
|
-
publish("spa/filter2durationhours/$name", "Filter Cycle 2 Duration Hours")
|
566
|
-
publish("spa/filter2durationhours/$datatype", "integer")
|
567
|
-
publish("spa/filter2durationhours/$format", "0:24")
|
568
|
-
publish("spa/filter2durationhours/$settable", "true")
|
569
|
-
|
570
|
-
publish("spa/filter2durationminutes/$name", "Filter Cycle 2 Duration Minutes")
|
571
|
-
publish("spa/filter2durationminutes/$datatype", "integer")
|
572
|
-
publish("spa/filter2durationminutes/$format", "0:59")
|
573
|
-
publish("spa/filter2durationminutes/$settable", "true")
|
574
|
-
|
575
|
-
subscribe("spa/filter1hour/set")
|
576
|
-
subscribe("spa/filter1minute/set")
|
577
|
-
subscribe("spa/filter1durationhours/set")
|
578
|
-
subscribe("spa/filter1durationminutes/set")
|
579
|
-
subscribe("spa/filter2enabled/set")
|
580
|
-
subscribe("spa/filter2hour/set")
|
581
|
-
subscribe("spa/filter2minute/set")
|
582
|
-
subscribe("spa/filter2durationhours/set")
|
583
|
-
subscribe("spa/filter2durationminutes/set")
|
584
|
-
|
585
|
-
@things.merge(["filter1hour,filter1minute,filter1durationhours,filter1durationminutes,filter2enabled,filter2hour,filter2minute,filter2durationhours,filter2durationminutes"])
|
586
|
-
|
587
|
-
publish_nodes
|
588
|
-
end
|
589
|
-
|
590
|
-
def publish_nodes
|
591
|
-
publish("spa/$properties", (["hold,priming,heatingmode,temperaturescale,24htime,heating,temperaturerange,currenttemperature,settemperature,filter1,filter2"] + @things.to_a).join(','))
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
mqtt_uri = ARGV.shift
|
596
|
-
|
597
|
-
if ARGV.empty?
|
598
|
-
spas = BWA::Discovery.discover
|
599
|
-
if spas.empty?
|
600
|
-
BWA.logger.fatal "Could not find spa!"
|
601
|
-
$stderr.puts "Could not find spa!"
|
602
|
-
exit 1
|
603
|
-
end
|
604
|
-
spa_ip = "tcp://#{spas.first.first}/"
|
605
|
-
else
|
606
|
-
spa_ip = ARGV[0]
|
607
|
-
end
|
608
|
-
|
609
|
-
spa = BWA::Client.new(spa_ip)
|
610
|
-
|
611
|
-
spa.request_configuration
|
612
|
-
spa.request_filter_configuration
|
613
|
-
|
614
|
-
MQTTBridge.new(mqtt_uri, spa)
|