waterfurnace_aurora 0.7.7 → 0.8.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/aurora_mqtt_bridge +86 -72
- data/lib/aurora/abc_client.rb +36 -7
- data/lib/aurora/humidistat.rb +2 -0
- data/lib/aurora/mock_abc.rb +17 -1
- data/lib/aurora/pump.rb +2 -2
- data/lib/aurora/registers.rb +2 -2
- data/lib/aurora/thermostat.rb +13 -9
- data/lib/aurora/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 288c8dbc14788d26473f14dcfaf388f75c8aee92c2f3b4d388bfa8326cfd2842
|
4
|
+
data.tar.gz: c06f92936c81e402d08e01ae6b8c6c573acca46a85c9630914cb3c69f125a56a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e64658afee912c8188af6d88bc98e208427b8dc4ef2ce1ea6ff1efcaca15ea2042ed4eef08ccfd764ec59ce0bb82013b0abd82173ec00f9ec61cbde07a66634
|
7
|
+
data.tar.gz: 6deff29644f83c329f1727d0a568c87536618ae63c7a27e58e4054eff187496c6f04bf3b63e2c35e649b2a0eb5b6395d81450a68b0096d1cacee9137c2f53c31
|
data/exe/aurora_mqtt_bridge
CHANGED
@@ -155,14 +155,16 @@ class MQTTBridge
|
|
155
155
|
hass: { sensor: { device_class: :temperature,
|
156
156
|
state_class: :measurement,
|
157
157
|
entity_category: :diagnostic } })
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
158
|
+
if @abc.awl_communicating?
|
159
|
+
node.property("leaving-air-temperature",
|
160
|
+
"Leaving Air Temperature",
|
161
|
+
:float,
|
162
|
+
@abc.leaving_air_temperature,
|
163
|
+
unit: "°F",
|
164
|
+
hass: { sensor: { device_class: :temperature,
|
165
|
+
state_class: :measurement,
|
166
|
+
entity_category: :diagnostic } })
|
167
|
+
end
|
166
168
|
node.property("leaving-water-temperature",
|
167
169
|
"Leaving Water Temperature",
|
168
170
|
:float,
|
@@ -171,7 +173,8 @@ class MQTTBridge
|
|
171
173
|
hass: { sensor: { device_class: :temperature,
|
172
174
|
state_class: :measurement,
|
173
175
|
entity_category: :diagnostic } })
|
174
|
-
|
176
|
+
# TODO: figure out the config if this actually exists
|
177
|
+
if @abc.awl_communicating? && !@abc.outdoor_temperature.zero?
|
175
178
|
node.property("outdoor-temperature",
|
176
179
|
"Outdoor Temperature",
|
177
180
|
:float,
|
@@ -333,15 +336,6 @@ class MQTTBridge
|
|
333
336
|
:boolean,
|
334
337
|
@abc.pump.running,
|
335
338
|
hass: { binary_sensor: { device_class: :running } })
|
336
|
-
node.property("speed",
|
337
|
-
"Speed",
|
338
|
-
:integer,
|
339
|
-
@abc.pump.speed,
|
340
|
-
format: 0..100,
|
341
|
-
unit: "%",
|
342
|
-
hass: { number: { entity_category: :diagnostic } }) do |value, property|
|
343
|
-
@mutex.synchronize { property.value = @abc.pump.speed = value }
|
344
|
-
end
|
345
339
|
node.property("manual-control",
|
346
340
|
"Manual Control",
|
347
341
|
:boolean,
|
@@ -367,6 +361,17 @@ class MQTTBridge
|
|
367
361
|
hass: { number: { entity_category: :config } }) do |value, property|
|
368
362
|
@mutex.synchronize { property.value = @abc.pump.maximum_speed = value }
|
369
363
|
end
|
364
|
+
next unless @abc.awl_axb?
|
365
|
+
|
366
|
+
node.property("speed",
|
367
|
+
"Speed",
|
368
|
+
:integer,
|
369
|
+
@abc.pump.speed,
|
370
|
+
format: 0..100,
|
371
|
+
unit: "%",
|
372
|
+
hass: { number: { entity_category: :diagnostic } }) do |value, property|
|
373
|
+
@mutex.synchronize { property.value = @abc.pump.speed = value }
|
374
|
+
end
|
370
375
|
end
|
371
376
|
|
372
377
|
if @abc.dhw
|
@@ -396,47 +401,41 @@ class MQTTBridge
|
|
396
401
|
@abc.dhw.set_point,
|
397
402
|
format: 100..140,
|
398
403
|
unit: "°F",
|
399
|
-
hass: :
|
404
|
+
hass: { number: { step: 5 } }) do |value, property|
|
400
405
|
@mutex.synchronize { property.value = @abc.dhw.set_point = value }
|
401
406
|
end
|
402
407
|
end
|
403
408
|
end
|
404
409
|
|
405
410
|
@humidistat = @homie.node("humidistat", "Humidistat", "Humidistat") do |node|
|
406
|
-
node.property("relative-humidity",
|
407
|
-
"Relative Humidity",
|
408
|
-
:integer,
|
409
|
-
@abc.humidistat.relative_humidity,
|
410
|
-
unit: "%",
|
411
|
-
format: 0..100,
|
412
|
-
hass: { sensor: { device_class: :humidity,
|
413
|
-
state_class: :measurement } })
|
414
411
|
if @abc.humidistat.humidifier?
|
415
412
|
node.property("humidifier-running",
|
416
413
|
"Humidifier Running",
|
417
414
|
:boolean,
|
418
415
|
@abc.humidistat.humidifier_running?)
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
416
|
+
if @abc.awl_communicating?
|
417
|
+
node.property("humidifier-mode",
|
418
|
+
"Humidifier Mode",
|
419
|
+
:enum,
|
420
|
+
@abc.humidistat.humidifier_mode,
|
421
|
+
format: %i[auto manual]) do |value, property|
|
422
|
+
@mutex.synchronize { property.value = @abc.humidistat.humidifier_mode = value.to_sym }
|
423
|
+
end
|
424
|
+
node.property("humidification-target",
|
425
|
+
"Humidification Target Relative Humidity",
|
426
|
+
:integer,
|
427
|
+
@abc.humidistat.humidification_target,
|
428
|
+
unit: "%",
|
429
|
+
format: 15..50) do |value, property|
|
430
|
+
@mutex.synchronize { property.value = @abc.humidistat.humidification_target = value }
|
431
|
+
end
|
432
|
+
node.hass_humidifier("humidifier-running",
|
433
|
+
target_property: "humidification-target",
|
434
|
+
mode_property: "humidifier-mode",
|
435
|
+
id: "humidifier",
|
436
|
+
name: "Humidifier",
|
437
|
+
device_class: :humidifier)
|
433
438
|
end
|
434
|
-
node.hass_humidifier("humidifier-running",
|
435
|
-
target_property: "humidification-target",
|
436
|
-
mode_property: "humidifier-mode",
|
437
|
-
id: "humidifier",
|
438
|
-
name: "Humidifier",
|
439
|
-
device_class: :humidifier)
|
440
439
|
end
|
441
440
|
|
442
441
|
# VSDrive can perform active dehumidification, even without a dedicated dehumidifier
|
@@ -446,28 +445,40 @@ class MQTTBridge
|
|
446
445
|
"Dehumidifier Running",
|
447
446
|
:boolean,
|
448
447
|
@abc.humidistat.dehumidifier_running?)
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
448
|
+
if @abc.awl_communicating?
|
449
|
+
node.property("dehumidifier-mode",
|
450
|
+
"Dehumidifier Mode",
|
451
|
+
:enum,
|
452
|
+
@abc.humidistat.dehumidifier_mode,
|
453
|
+
format: %i[auto manual]) do |value, property|
|
454
|
+
@mutex.synchronize { property.value = @abc.humidistat.dehumidifier_mode = value.to_sym }
|
455
|
+
end
|
456
|
+
node.property("dehumidification-target",
|
457
|
+
"Dehumidification Target Relative Humidity",
|
458
|
+
:integer,
|
459
|
+
@abc.humidistat.dehumidification_target,
|
460
|
+
unit: "%",
|
461
|
+
format: 35..65) do |value, property|
|
462
|
+
@mutex.synchronize { property.value = @abc.humidistat.dehumidification_target = value }
|
463
|
+
end
|
464
|
+
node.hass_humidifier("dehumidifier-running",
|
465
|
+
target_property: "dehumidification-target",
|
466
|
+
mode_property: "dehumidifier-mode",
|
467
|
+
id: "dehumidifier",
|
468
|
+
name: "Dehumidifier",
|
469
|
+
device_class: :dehumidifier)
|
463
470
|
end
|
464
|
-
node.hass_humidifier("dehumidifier-running",
|
465
|
-
target_property: "dehumidification-target",
|
466
|
-
mode_property: "dehumidifier-mode",
|
467
|
-
id: "dehumidifier",
|
468
|
-
name: "Dehumidifier",
|
469
|
-
device_class: :dehumidifier)
|
470
471
|
end
|
472
|
+
next unless @abc.awl_communicating?
|
473
|
+
|
474
|
+
node.property("relative-humidity",
|
475
|
+
"Relative Humidity",
|
476
|
+
:integer,
|
477
|
+
@abc.humidistat.relative_humidity,
|
478
|
+
unit: "%",
|
479
|
+
format: 0..100,
|
480
|
+
hass: { sensor: { device_class: :humidity,
|
481
|
+
state_class: :measurement } })
|
471
482
|
end
|
472
483
|
|
473
484
|
@faults = @homie.node("faults", "Fault History", "ABC") do |node|
|
@@ -495,6 +506,14 @@ class MQTTBridge
|
|
495
506
|
@abc.zones.each_with_index do |zone, i|
|
496
507
|
type = zone.is_a?(Aurora::IZ2Zone) ? "IntelliZone 2 Zone" : "Thermostat"
|
497
508
|
@homie.node("zone#{i + 1}", "Zone #{i + 1}", type) do |node|
|
509
|
+
node.property("current-mode",
|
510
|
+
"Current Heating/Cooling Mode Requested",
|
511
|
+
:enum,
|
512
|
+
zone.current_mode,
|
513
|
+
format: %w[standby h1 h2 h3 c1 c2])
|
514
|
+
|
515
|
+
next unless @abc.awl_communicating?
|
516
|
+
|
498
517
|
allowed_modes = %w[off auto cool heat]
|
499
518
|
allowed_modes << "eheat" if i.zero?
|
500
519
|
node.property("target-mode",
|
@@ -504,11 +523,6 @@ class MQTTBridge
|
|
504
523
|
format: allowed_modes) do |value, property|
|
505
524
|
@mutex.synchronize { property.value = zone.target_mode = value.to_sym }
|
506
525
|
end
|
507
|
-
node.property("current-mode",
|
508
|
-
"Current Heating/Cooling Mode Requested",
|
509
|
-
:enum,
|
510
|
-
zone.current_mode,
|
511
|
-
format: %w[standby h1 h2 h3 c1 c2])
|
512
526
|
node.property("target-fan-mode",
|
513
527
|
"Target Fan Mode",
|
514
528
|
:enum,
|
data/lib/aurora/abc_client.rb
CHANGED
@@ -86,6 +86,7 @@ module Aurora
|
|
86
86
|
end
|
87
87
|
|
88
88
|
attr_reader :modbus_slave,
|
89
|
+
:abc_version,
|
89
90
|
:model,
|
90
91
|
:serial_number,
|
91
92
|
:zones,
|
@@ -111,14 +112,15 @@ module Aurora
|
|
111
112
|
@modbus_slave = self.class.open_modbus_slave(uri)
|
112
113
|
@modbus_slave.read_retry_timeout = 15
|
113
114
|
@modbus_slave.read_retries = 2
|
114
|
-
raw_registers = @modbus_slave.holding_registers[33, 88...110, 404, 412..413, 1103, 1114]
|
115
|
+
raw_registers = @modbus_slave.holding_registers[2, 33, 88...110, 404, 412..413, 813, 1103, 1114]
|
115
116
|
registers = Aurora.transform_registers(raw_registers.dup)
|
117
|
+
@abc_version = registers[2]
|
116
118
|
@program = registers[88]
|
117
119
|
@model = registers[92]
|
118
120
|
@serial_number = registers[105]
|
119
121
|
@energy_monitor = raw_registers[412]
|
120
122
|
|
121
|
-
@zones = if iz2?
|
123
|
+
@zones = if iz2? && iz2_version >= 2.0
|
122
124
|
iz2_zone_count = @modbus_slave.holding_registers[483]
|
123
125
|
(0...iz2_zone_count).map { |i| IZ2Zone.new(self, i + 1) }
|
124
126
|
else
|
@@ -152,8 +154,9 @@ module Aurora
|
|
152
154
|
|
153
155
|
@faults = []
|
154
156
|
|
155
|
-
@registers_to_read = [6, 19..20, 25, 30, 112, 344,
|
156
|
-
|
157
|
+
@registers_to_read = [6, 19..20, 25, 30, 112, 344, 567, 1104, 1110..1111, 1114, 1150..1153, 1165]
|
158
|
+
@registers_to_read.concat([741, 31_003]) if awl_communicating?
|
159
|
+
@registers_to_read << 900 if awl_axb?
|
157
160
|
zones.each do |z|
|
158
161
|
@registers_to_read.concat(z.registers_to_read)
|
159
162
|
end
|
@@ -178,8 +181,8 @@ module Aurora
|
|
178
181
|
|
179
182
|
outputs = registers[30]
|
180
183
|
|
181
|
-
@entering_air_temperature = registers[
|
182
|
-
@leaving_air_temperature = registers[900]
|
184
|
+
@entering_air_temperature = registers[567]
|
185
|
+
@leaving_air_temperature = registers[900] if awl_axb?
|
183
186
|
@leaving_water_temperature = registers[1110]
|
184
187
|
@entering_water_temperature = registers[1111]
|
185
188
|
@outdoor_temperature = registers[31_003]
|
@@ -270,13 +273,18 @@ module Aurora
|
|
270
273
|
end
|
271
274
|
|
272
275
|
# config aurora system
|
273
|
-
{ thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824 }.each do |(component, register)|
|
276
|
+
{ thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824, awl: 827 }.each do |(component, register)|
|
274
277
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
275
278
|
def #{component}?
|
276
279
|
return @#{component} if instance_variable_defined?(:@#{component})
|
277
280
|
@#{component} = @modbus_slave.holding_registers[#{register}] != 3
|
278
281
|
end
|
279
282
|
|
283
|
+
def #{component}_version
|
284
|
+
return @#{component}_version if instance_variable_defined?(:@#{component}_version)
|
285
|
+
@#{component}_version = @modbus_slave.holding_registers[#{register + 1}].to_f / 100
|
286
|
+
end
|
287
|
+
|
280
288
|
def add_#{component}
|
281
289
|
@modbus_slave.holding_registers[#{register}] = 2
|
282
290
|
end
|
@@ -287,6 +295,27 @@ module Aurora
|
|
287
295
|
RUBY
|
288
296
|
end
|
289
297
|
|
298
|
+
# see https://www.waterfurnace.com/literature/symphony/ig2001ew.pdf
|
299
|
+
# is there a communicating system compliant with AWL?
|
300
|
+
def awl_communicating?
|
301
|
+
awl_thermostat? || awl_iz2?
|
302
|
+
end
|
303
|
+
|
304
|
+
# is the thermostat AWL compliant?
|
305
|
+
def awl_thermostat?
|
306
|
+
thermostat? && thermostat_version >= 3.0
|
307
|
+
end
|
308
|
+
|
309
|
+
# is the IZ2 AWL compliant?
|
310
|
+
def awl_iz2?
|
311
|
+
iz2? && iz2_version >= 2.0
|
312
|
+
end
|
313
|
+
|
314
|
+
# is the AXB AWL compliant?
|
315
|
+
def awl_axb?
|
316
|
+
axb? && axb_version >= 2.0
|
317
|
+
end
|
318
|
+
|
290
319
|
def inspect
|
291
320
|
"#<Aurora::ABCClient #{(instance_variables - [:@modbus_slave]).map do |iv|
|
292
321
|
"#{iv}=#{instance_variable_get(iv).inspect}"
|
data/lib/aurora/humidistat.rb
CHANGED
@@ -29,6 +29,8 @@ module Aurora
|
|
29
29
|
alias_method :dehumidifier_running?, :dehumidifier_running
|
30
30
|
|
31
31
|
def registers_to_read
|
32
|
+
return [] unless @abc.awl_communicating?
|
33
|
+
|
32
34
|
result = [741]
|
33
35
|
if humidifier? || dehumidifier? || abc.compressor.is_a?(Compressor::VSDrive)
|
34
36
|
result.concat(abc.iz2? ? [21_114, 31_109..31_110] : [12_309..12_310])
|
data/lib/aurora/mock_abc.rb
CHANGED
@@ -20,9 +20,14 @@ module Aurora
|
|
20
20
|
if register.length == 1
|
21
21
|
case register.first
|
22
22
|
when Integer
|
23
|
+
missing_register(register.first) unless @registers.key?(register.first)
|
23
24
|
@registers[register.first]
|
24
25
|
when Range
|
25
|
-
|
26
|
+
registers = register.first.to_a
|
27
|
+
registers.each do |i|
|
28
|
+
missing_register(i) unless @registers.key?(i)
|
29
|
+
end
|
30
|
+
@registers.values_at(*registers)
|
26
31
|
else
|
27
32
|
raise ArgumentError, "Not implemented yet #{register.inspect}"
|
28
33
|
end
|
@@ -35,6 +40,11 @@ module Aurora
|
|
35
40
|
result = {}
|
36
41
|
queries.each do |query|
|
37
42
|
Array(query).each do |i|
|
43
|
+
unless @registers.key?(i)
|
44
|
+
missing_register(i)
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
38
48
|
result[i] = @registers[i]
|
39
49
|
end
|
40
50
|
end
|
@@ -45,5 +55,11 @@ module Aurora
|
|
45
55
|
@registers[addr] = value
|
46
56
|
end
|
47
57
|
alias_method :[]=, :write_holding_register
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def missing_register(idx)
|
62
|
+
logger.warn("missing register #{idx}")
|
63
|
+
end
|
48
64
|
end
|
49
65
|
end
|
data/lib/aurora/pump.rb
CHANGED
@@ -31,7 +31,7 @@ module Aurora
|
|
31
31
|
alias_method :manual_control?, :manual_control
|
32
32
|
|
33
33
|
def registers_to_read
|
34
|
-
super + [321..325]
|
34
|
+
super + (@abc.awl_axb? ? [321..325] : [321..324])
|
35
35
|
end
|
36
36
|
|
37
37
|
def refresh(registers)
|
@@ -39,7 +39,7 @@ module Aurora
|
|
39
39
|
@minimum_speed = registers[321]
|
40
40
|
@maximum_speed = registers[322]
|
41
41
|
@manual_control = registers[323] != :off
|
42
|
-
@speed = registers[325]
|
42
|
+
@speed = registers[325] if @abc.awl_axb?
|
43
43
|
end
|
44
44
|
|
45
45
|
def manual_control=(value)
|
data/lib/aurora/registers.rb
CHANGED
@@ -65,7 +65,7 @@ module Aurora
|
|
65
65
|
|
66
66
|
def to_string(registers, idx, length)
|
67
67
|
(idx...(idx + length)).map do |i|
|
68
|
-
|
68
|
+
next "\ufffd" unless registers[i] # missing data? add unicode invalid character
|
69
69
|
|
70
70
|
(registers[i] >> 8).chr + (registers[i] & 0xff).chr
|
71
71
|
end.join.sub(/[ \0]+$/, "")
|
@@ -112,7 +112,7 @@ module Aurora
|
|
112
112
|
53 => "Condensing Pressure Sensor", # Low condensing pressure (PD) or invalid (0 to 870 psi) Retry 10x.
|
113
113
|
54 => "Low Supply Voltage", # Supply Voltage is <180 V (190V to reset) or powered off/on too quickly (<30 sec.).
|
114
114
|
55 => "Out of Envelope", # Comp Operating out of envelope (P0) more than 90 sec. Retry 10x.
|
115
|
-
56 => "Drive Over
|
115
|
+
56 => "Drive Over Current", # Over current tripped by phase loss, earth fault, short circuit, low water flow, low air flow, or major drive fault. # rubocop:disable Layout/LineLength
|
116
116
|
57 => "Drive Over/Under Voltage", # DC Link Voltage to compressor is >450vdc or at minimum voltage (<185vdc).
|
117
117
|
58 => "High Drive Temp", # Drive Temp has reached critical High Temp >239 F
|
118
118
|
59 => "Internal Drive Error", # The MOC has encountered an internal fault or an internal error. Probably fatal.
|
data/lib/aurora/thermostat.rb
CHANGED
@@ -15,19 +15,23 @@ module Aurora
|
|
15
15
|
:fan_intermittent_off
|
16
16
|
|
17
17
|
def registers_to_read
|
18
|
+
return [31] unless @abc.awl_thermostat?
|
19
|
+
|
18
20
|
[31, 502, 745..746, 12_005..12_006]
|
19
21
|
end
|
20
22
|
|
21
23
|
def refresh(registers)
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
if @abc.awl_thermostat?
|
25
|
+
@ambient_temperature = registers[502]
|
26
|
+
@heating_target_temperature = registers[745]
|
27
|
+
@cooling_target_temperature = registers[746]
|
28
|
+
config1 = registers[12_005]
|
29
|
+
config2 = registers[12_006]
|
30
|
+
@target_fan_mode = config1[:fan]
|
31
|
+
@fan_intermittent_on = config1[:on_time]
|
32
|
+
@fan_intermittent_off = config1[:off_time]
|
33
|
+
@target_mode = config2[:mode]
|
34
|
+
end
|
31
35
|
|
32
36
|
inputs = registers[31]
|
33
37
|
@current_fan_mode = inputs.include?(:g)
|
data/lib/aurora/version.rb
CHANGED