waterfurnace_aurora 0.7.5 → 1.0.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_fetch +14 -4
- data/exe/aurora_mqtt_bridge +143 -78
- data/lib/aurora/abc_client.rb +88 -47
- data/lib/aurora/aux_heat.rb +21 -0
- data/lib/aurora/blower.rb +1 -1
- data/lib/aurora/component.rb +4 -0
- data/lib/aurora/compressor.rb +6 -2
- 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 +3 -3
- data/lib/aurora/thermostat.rb +13 -9
- data/lib/aurora/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a92e9aadd14ee0154443cea52907f793880242ce22a44f3df7912065074c3c8
|
4
|
+
data.tar.gz: 553a945493652a50f92f49e4e0620db8e03305c3ff0ab65823f20c15db2ac89d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fee6734f5e5752aec571c2c93a81e79be950af8c8f4a3ab3259f7d6b1d5e2540d4fd616be06d911a382c710b23ed43c1b1ecf23db23444022c24216faff52cb
|
7
|
+
data.tar.gz: c2e5a9f54f7bd0f6b869ffff94b4cd0a0bf9de65ea29d8342fe690f582893a9fe0a7b0f0ce94ba4c0ecf6595156d21a12e7e8203023aaadc923a56c0951f817f
|
data/exe/aurora_fetch
CHANGED
@@ -9,11 +9,19 @@ require "uri"
|
|
9
9
|
require "yaml"
|
10
10
|
|
11
11
|
debug_modbus = yaml = false
|
12
|
+
try_individual = nil
|
12
13
|
|
13
14
|
options = OptionParser.new do |opts|
|
14
15
|
opts.banner = "Usage: aurora_fetch /path/to/serial/port REGISTERS [options]"
|
15
16
|
|
17
|
+
opts.separator("")
|
18
|
+
opts.separator("Use `known` to fetch all identified registers. Use `valid` to fetch all registers that will respond.")
|
19
|
+
opts.separator("")
|
20
|
+
|
16
21
|
opts.on("--debug-modbus", "Print actual protocol bytes") { debug_modbus = true }
|
22
|
+
opts.on("--[no-]try-individual",
|
23
|
+
"Query registers one-by-one if a range has an illegal address. " \
|
24
|
+
"Defaults to true for `valid` and `known` special registers, false otherwise.") { |v| try_individual = v }
|
17
25
|
opts.on("-y", "--yaml", "Output raw values as YAML") { yaml = true }
|
18
26
|
opts.on("-v", "--version", "Print version") do
|
19
27
|
puts Aurora::VERSION
|
@@ -32,11 +40,13 @@ unless ARGV.length == 2
|
|
32
40
|
exit 1
|
33
41
|
end
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
modbus_slave = Aurora::ABCClient.open_modbus_slave(ARGV[0])
|
44
|
+
modbus_slave.read_retry_timeout = 15
|
45
|
+
modbus_slave.read_retries = 2
|
46
|
+
modbus_slave.logger = Logger.new($stdout)
|
47
|
+
modbus_slave.logger.level = debug_modbus ? :debug : :warn
|
38
48
|
|
39
|
-
registers =
|
49
|
+
registers = Aurora::ABCClient.query_registers(modbus_slave, ARGV[1], try_individual: try_individual)
|
40
50
|
|
41
51
|
if yaml
|
42
52
|
puts YAML.dump(registers)
|
data/exe/aurora_mqtt_bridge
CHANGED
@@ -93,6 +93,7 @@ class MQTTBridge
|
|
93
93
|
@abc.refresh
|
94
94
|
|
95
95
|
components = { @homie_abc => @abc,
|
96
|
+
@aux_heat => @abc.aux_heat,
|
96
97
|
@compressor => @abc.compressor,
|
97
98
|
@blower => @abc.blower,
|
98
99
|
@pump => @abc.pump,
|
@@ -131,7 +132,7 @@ class MQTTBridge
|
|
131
132
|
}
|
132
133
|
|
133
134
|
@homie_abc = @homie.node("abc", "Heat Pump", "ABC") do |node|
|
134
|
-
allowed_modes = %w[lockout standby blower heating cooling
|
135
|
+
allowed_modes = %w[lockout standby blower heating cooling waiting]
|
135
136
|
allowed_modes << "dehumidify" if @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
136
137
|
node.property("current-mode",
|
137
138
|
"Current Heating/Cooling Mode",
|
@@ -155,14 +156,16 @@ class MQTTBridge
|
|
155
156
|
hass: { sensor: { device_class: :temperature,
|
156
157
|
state_class: :measurement,
|
157
158
|
entity_category: :diagnostic } })
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
159
|
+
if @abc.awl_communicating?
|
160
|
+
node.property("leaving-air-temperature",
|
161
|
+
"Leaving Air Temperature",
|
162
|
+
:float,
|
163
|
+
@abc.leaving_air_temperature,
|
164
|
+
unit: "°F",
|
165
|
+
hass: { sensor: { device_class: :temperature,
|
166
|
+
state_class: :measurement,
|
167
|
+
entity_category: :diagnostic } })
|
168
|
+
end
|
166
169
|
node.property("leaving-water-temperature",
|
167
170
|
"Leaving Water Temperature",
|
168
171
|
:float,
|
@@ -171,7 +174,8 @@ class MQTTBridge
|
|
171
174
|
hass: { sensor: { device_class: :temperature,
|
172
175
|
state_class: :measurement,
|
173
176
|
entity_category: :diagnostic } })
|
174
|
-
|
177
|
+
# TODO: figure out the config if this actually exists
|
178
|
+
if @abc.awl_communicating? && !@abc.outdoor_temperature.zero?
|
175
179
|
node.property("outdoor-temperature",
|
176
180
|
"Outdoor Temperature",
|
177
181
|
:float,
|
@@ -181,6 +185,14 @@ class MQTTBridge
|
|
181
185
|
state_class: :measurement } })
|
182
186
|
end
|
183
187
|
|
188
|
+
node.property("line-voltage",
|
189
|
+
"Line Voltage Setting",
|
190
|
+
:integer,
|
191
|
+
@abc.line_voltage,
|
192
|
+
format: 90..635,
|
193
|
+
unit: "V") do |value, property|
|
194
|
+
@mutex.synchronize { property.value = @abc.line_voltage = value }
|
195
|
+
end
|
184
196
|
node.property("fp1",
|
185
197
|
"FP1 Sensor",
|
186
198
|
:float,
|
@@ -197,12 +209,11 @@ class MQTTBridge
|
|
197
209
|
hass: { sensor: { device_class: :temperature,
|
198
210
|
state_class: :measurement,
|
199
211
|
entity_category: :diagnostic } })
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
component.sub("_watts", " Power Usage").tr("_", " ").titleize,
|
212
|
+
if @abc.energy_monitoring?
|
213
|
+
node.property("watts",
|
214
|
+
"Total Power Usage",
|
204
215
|
:integer,
|
205
|
-
@abc.
|
216
|
+
@abc.watts,
|
206
217
|
unit: "W",
|
207
218
|
hass: { sensor: { device_class: :power,
|
208
219
|
state_class: :measurement } })
|
@@ -236,6 +247,30 @@ class MQTTBridge
|
|
236
247
|
hass: { sensor: { device_class: :temperature,
|
237
248
|
state_class: :measurement,
|
238
249
|
entity_category: :diagnostic } })
|
250
|
+
node.property("drive-temperature",
|
251
|
+
"Drive Temperature",
|
252
|
+
:float,
|
253
|
+
@abc.compressor.drive_temperature,
|
254
|
+
unit: "°F",
|
255
|
+
hass: { sensor: { device_class: :temperature,
|
256
|
+
state_class: :measurement,
|
257
|
+
entity_category: :diagnostic } })
|
258
|
+
node.property("inverter-temperature",
|
259
|
+
"Inverter Temperature",
|
260
|
+
:float,
|
261
|
+
@abc.compressor.inverter_temperature,
|
262
|
+
unit: "°F",
|
263
|
+
hass: { sensor: { device_class: :temperature,
|
264
|
+
state_class: :measurement,
|
265
|
+
entity_category: :diagnostic } })
|
266
|
+
node.property("fan-speed",
|
267
|
+
"Fan Speed",
|
268
|
+
:integer,
|
269
|
+
@abc.compressor.fan_speed,
|
270
|
+
unit: "%",
|
271
|
+
format: 0..100,
|
272
|
+
hass: { sensor: { state_class: :measurement,
|
273
|
+
entity_category: :diagnostic } })
|
239
274
|
|
240
275
|
next unless @abc.iz2?
|
241
276
|
|
@@ -248,6 +283,25 @@ class MQTTBridge
|
|
248
283
|
entity_category: :diagnostic } })
|
249
284
|
end
|
250
285
|
|
286
|
+
@aux_heat = @homie.node("aux-heat", "Aux Heater", "Aux Heater") do |node|
|
287
|
+
node.property("stage",
|
288
|
+
"Current Stage",
|
289
|
+
:integer,
|
290
|
+
@abc.aux_heat.stage,
|
291
|
+
format: 0..2,
|
292
|
+
hass: { sensor: { state_class: :measurement } })
|
293
|
+
|
294
|
+
if @abc.energy_monitoring?
|
295
|
+
node.property("watts",
|
296
|
+
"Power Usage",
|
297
|
+
:integer,
|
298
|
+
@abc.aux_heat.watts,
|
299
|
+
unit: "W",
|
300
|
+
hass: { sensor: { device_class: :power,
|
301
|
+
state_class: :measurement } })
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
251
305
|
@blower = @homie.node("blower", "Blower", @abc.blower.type) do |node|
|
252
306
|
node.property("running",
|
253
307
|
"Running",
|
@@ -325,15 +379,6 @@ class MQTTBridge
|
|
325
379
|
:boolean,
|
326
380
|
@abc.pump.running,
|
327
381
|
hass: { binary_sensor: { device_class: :running } })
|
328
|
-
node.property("speed",
|
329
|
-
"Speed",
|
330
|
-
:integer,
|
331
|
-
@abc.pump.speed,
|
332
|
-
format: 0..100,
|
333
|
-
unit: "%",
|
334
|
-
hass: { number: { entity_category: :diagnostic } }) do |value, property|
|
335
|
-
@mutex.synchronize { property.value = @abc.pump.speed = value }
|
336
|
-
end
|
337
382
|
node.property("manual-control",
|
338
383
|
"Manual Control",
|
339
384
|
:boolean,
|
@@ -359,6 +404,17 @@ class MQTTBridge
|
|
359
404
|
hass: { number: { entity_category: :config } }) do |value, property|
|
360
405
|
@mutex.synchronize { property.value = @abc.pump.maximum_speed = value }
|
361
406
|
end
|
407
|
+
next unless @abc.awl_axb?
|
408
|
+
|
409
|
+
node.property("speed",
|
410
|
+
"Speed",
|
411
|
+
:integer,
|
412
|
+
@abc.pump.speed,
|
413
|
+
format: 0..100,
|
414
|
+
unit: "%",
|
415
|
+
hass: { number: { entity_category: :diagnostic } }) do |value, property|
|
416
|
+
@mutex.synchronize { property.value = @abc.pump.speed = value }
|
417
|
+
end
|
362
418
|
end
|
363
419
|
|
364
420
|
if @abc.dhw
|
@@ -388,47 +444,41 @@ class MQTTBridge
|
|
388
444
|
@abc.dhw.set_point,
|
389
445
|
format: 100..140,
|
390
446
|
unit: "°F",
|
391
|
-
hass: :
|
447
|
+
hass: { number: { step: 5 } }) do |value, property|
|
392
448
|
@mutex.synchronize { property.value = @abc.dhw.set_point = value }
|
393
449
|
end
|
394
450
|
end
|
395
451
|
end
|
396
452
|
|
397
453
|
@humidistat = @homie.node("humidistat", "Humidistat", "Humidistat") do |node|
|
398
|
-
node.property("relative-humidity",
|
399
|
-
"Relative Humidity",
|
400
|
-
:integer,
|
401
|
-
@abc.humidistat.relative_humidity,
|
402
|
-
unit: "%",
|
403
|
-
format: 0..100,
|
404
|
-
hass: { sensor: { device_class: :humidity,
|
405
|
-
state_class: :measurement } })
|
406
454
|
if @abc.humidistat.humidifier?
|
407
455
|
node.property("humidifier-running",
|
408
456
|
"Humidifier Running",
|
409
457
|
:boolean,
|
410
458
|
@abc.humidistat.humidifier_running?)
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
459
|
+
if @abc.awl_communicating?
|
460
|
+
node.property("humidifier-mode",
|
461
|
+
"Humidifier Mode",
|
462
|
+
:enum,
|
463
|
+
@abc.humidistat.humidifier_mode,
|
464
|
+
format: %i[auto manual]) do |value, property|
|
465
|
+
@mutex.synchronize { property.value = @abc.humidistat.humidifier_mode = value.to_sym }
|
466
|
+
end
|
467
|
+
node.property("humidification-target",
|
468
|
+
"Humidification Target Relative Humidity",
|
469
|
+
:integer,
|
470
|
+
@abc.humidistat.humidification_target,
|
471
|
+
unit: "%",
|
472
|
+
format: 15..50) do |value, property|
|
473
|
+
@mutex.synchronize { property.value = @abc.humidistat.humidification_target = value }
|
474
|
+
end
|
475
|
+
node.hass_humidifier("humidifier-running",
|
476
|
+
target_property: "humidification-target",
|
477
|
+
mode_property: "humidifier-mode",
|
478
|
+
id: "humidifier",
|
479
|
+
name: "Humidifier",
|
480
|
+
device_class: :humidifier)
|
425
481
|
end
|
426
|
-
node.hass_humidifier("humidifier-running",
|
427
|
-
target_property: "humidification-target",
|
428
|
-
mode_property: "humidifier-mode",
|
429
|
-
id: "humidifier",
|
430
|
-
name: "Humidifier",
|
431
|
-
device_class: :humidifier)
|
432
482
|
end
|
433
483
|
|
434
484
|
# VSDrive can perform active dehumidification, even without a dedicated dehumidifier
|
@@ -438,28 +488,40 @@ class MQTTBridge
|
|
438
488
|
"Dehumidifier Running",
|
439
489
|
:boolean,
|
440
490
|
@abc.humidistat.dehumidifier_running?)
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
491
|
+
if @abc.awl_communicating?
|
492
|
+
node.property("dehumidifier-mode",
|
493
|
+
"Dehumidifier Mode",
|
494
|
+
:enum,
|
495
|
+
@abc.humidistat.dehumidifier_mode,
|
496
|
+
format: %i[auto manual]) do |value, property|
|
497
|
+
@mutex.synchronize { property.value = @abc.humidistat.dehumidifier_mode = value.to_sym }
|
498
|
+
end
|
499
|
+
node.property("dehumidification-target",
|
500
|
+
"Dehumidification Target Relative Humidity",
|
501
|
+
:integer,
|
502
|
+
@abc.humidistat.dehumidification_target,
|
503
|
+
unit: "%",
|
504
|
+
format: 35..65) do |value, property|
|
505
|
+
@mutex.synchronize { property.value = @abc.humidistat.dehumidification_target = value }
|
506
|
+
end
|
507
|
+
node.hass_humidifier("dehumidifier-running",
|
508
|
+
target_property: "dehumidification-target",
|
509
|
+
mode_property: "dehumidifier-mode",
|
510
|
+
id: "dehumidifier",
|
511
|
+
name: "Dehumidifier",
|
512
|
+
device_class: :dehumidifier)
|
455
513
|
end
|
456
|
-
node.hass_humidifier("dehumidifier-running",
|
457
|
-
target_property: "dehumidification-target",
|
458
|
-
mode_property: "dehumidifier-mode",
|
459
|
-
id: "dehumidifier",
|
460
|
-
name: "Dehumidifier",
|
461
|
-
device_class: :dehumidifier)
|
462
514
|
end
|
515
|
+
next unless @abc.awl_communicating?
|
516
|
+
|
517
|
+
node.property("relative-humidity",
|
518
|
+
"Relative Humidity",
|
519
|
+
:integer,
|
520
|
+
@abc.humidistat.relative_humidity,
|
521
|
+
unit: "%",
|
522
|
+
format: 0..100,
|
523
|
+
hass: { sensor: { device_class: :humidity,
|
524
|
+
state_class: :measurement } })
|
463
525
|
end
|
464
526
|
|
465
527
|
@faults = @homie.node("faults", "Fault History", "ABC") do |node|
|
@@ -487,6 +549,14 @@ class MQTTBridge
|
|
487
549
|
@abc.zones.each_with_index do |zone, i|
|
488
550
|
type = zone.is_a?(Aurora::IZ2Zone) ? "IntelliZone 2 Zone" : "Thermostat"
|
489
551
|
@homie.node("zone#{i + 1}", "Zone #{i + 1}", type) do |node|
|
552
|
+
node.property("current-mode",
|
553
|
+
"Current Heating/Cooling Mode Requested",
|
554
|
+
:enum,
|
555
|
+
zone.current_mode,
|
556
|
+
format: %w[standby h1 h2 h3 c1 c2])
|
557
|
+
|
558
|
+
next unless @abc.awl_communicating?
|
559
|
+
|
490
560
|
allowed_modes = %w[off auto cool heat]
|
491
561
|
allowed_modes << "eheat" if i.zero?
|
492
562
|
node.property("target-mode",
|
@@ -496,11 +566,6 @@ class MQTTBridge
|
|
496
566
|
format: allowed_modes) do |value, property|
|
497
567
|
@mutex.synchronize { property.value = zone.target_mode = value.to_sym }
|
498
568
|
end
|
499
|
-
node.property("current-mode",
|
500
|
-
"Current Heating/Cooling Mode Requested",
|
501
|
-
:enum,
|
502
|
-
zone.current_mode,
|
503
|
-
format: %w[standby h1 h2 h3 c1 c2])
|
504
569
|
node.property("target-fan-mode",
|
505
570
|
"Target Fan Mode",
|
506
571
|
:enum,
|
data/lib/aurora/abc_client.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "yaml"
|
4
4
|
require "uri"
|
5
5
|
|
6
|
+
require "aurora/aux_heat"
|
6
7
|
require "aurora/blower"
|
7
8
|
require "aurora/compressor"
|
8
9
|
require "aurora/dhw"
|
@@ -40,12 +41,57 @@ module Aurora
|
|
40
41
|
client = ::ModBus::RTUClient.new(io)
|
41
42
|
client.with_slave(1)
|
42
43
|
end
|
44
|
+
|
45
|
+
def query_registers(modbus_slave, query, try_individual: false)
|
46
|
+
implicit = try_individual
|
47
|
+
ranges = query.split(",").map do |addr|
|
48
|
+
case addr
|
49
|
+
when "known"
|
50
|
+
implicit = true
|
51
|
+
try_individual = true if try_individual.nil?
|
52
|
+
Aurora::REGISTER_NAMES.keys
|
53
|
+
when "valid"
|
54
|
+
implicit = true
|
55
|
+
try_individual = true if try_individual.nil?
|
56
|
+
break Aurora::REGISTER_RANGES
|
57
|
+
when /^(\d+)(?:\.\.|-)(\d+)$/
|
58
|
+
$1.to_i..$2.to_i
|
59
|
+
else
|
60
|
+
addr.to_i
|
61
|
+
end
|
62
|
+
end
|
63
|
+
queries = Aurora.normalize_ranges(ranges)
|
64
|
+
registers = {}
|
65
|
+
queries.each do |subquery|
|
66
|
+
registers.merge!(modbus_slave.read_multiple_holding_registers(*subquery))
|
67
|
+
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction
|
68
|
+
# maybe this unit doesn't respond to all the addresses we want?
|
69
|
+
raise unless implicit
|
70
|
+
|
71
|
+
# try each query individually
|
72
|
+
subquery.each do |subsubquery|
|
73
|
+
registers.merge!(modbus_slave.read_multiple_holding_registers(subsubquery))
|
74
|
+
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction
|
75
|
+
next unless try_individual
|
76
|
+
|
77
|
+
# seriously?? try each register individually
|
78
|
+
subsubquery.each do |i|
|
79
|
+
registers[i] = modbus_slave.holding_registers[i]
|
80
|
+
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction
|
81
|
+
next
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
registers
|
86
|
+
end
|
43
87
|
end
|
44
88
|
|
45
89
|
attr_reader :modbus_slave,
|
90
|
+
:abc_version,
|
46
91
|
:model,
|
47
92
|
:serial_number,
|
48
93
|
:zones,
|
94
|
+
:aux_heat,
|
49
95
|
:compressor,
|
50
96
|
:blower,
|
51
97
|
:pump,
|
@@ -60,21 +106,22 @@ module Aurora
|
|
60
106
|
:outdoor_temperature,
|
61
107
|
:fp1,
|
62
108
|
:fp2,
|
63
|
-
:
|
64
|
-
:
|
109
|
+
:line_voltage,
|
110
|
+
:watts
|
65
111
|
|
66
112
|
def initialize(uri)
|
67
113
|
@modbus_slave = self.class.open_modbus_slave(uri)
|
68
114
|
@modbus_slave.read_retry_timeout = 15
|
69
115
|
@modbus_slave.read_retries = 2
|
70
|
-
raw_registers = @modbus_slave.holding_registers[33, 88...110, 404, 412..413, 1103, 1114]
|
116
|
+
raw_registers = @modbus_slave.holding_registers[2, 33, 88...110, 404, 412..413, 813, 1103, 1114]
|
71
117
|
registers = Aurora.transform_registers(raw_registers.dup)
|
118
|
+
@abc_version = registers[2]
|
72
119
|
@program = registers[88]
|
73
120
|
@model = registers[92]
|
74
121
|
@serial_number = registers[105]
|
75
122
|
@energy_monitor = raw_registers[412]
|
76
123
|
|
77
|
-
@zones = if iz2?
|
124
|
+
@zones = if iz2? && iz2_version >= 2.0
|
78
125
|
iz2_zone_count = @modbus_slave.holding_registers[483]
|
79
126
|
(0...iz2_zone_count).map { |i| IZ2Zone.new(self, i + 1) }
|
80
127
|
else
|
@@ -83,6 +130,7 @@ module Aurora
|
|
83
130
|
|
84
131
|
@abc_dipswitches = registers[33]
|
85
132
|
@axb_dipswitches = registers[1103]
|
133
|
+
@aux_heat = AuxHeat.new(self)
|
86
134
|
@compressor = if @program == "ABCVSP"
|
87
135
|
Compressor::VSDrive.new(self)
|
88
136
|
else
|
@@ -108,12 +156,13 @@ module Aurora
|
|
108
156
|
|
109
157
|
@faults = []
|
110
158
|
|
111
|
-
@registers_to_read = [6, 19..20, 25, 30,
|
112
|
-
|
159
|
+
@registers_to_read = [6, 19..20, 25, 30, 112, 344, 567, 1104, 1110..1111, 1114, 1150..1153, 1165]
|
160
|
+
@registers_to_read.concat([741, 31_003]) if awl_communicating?
|
161
|
+
@registers_to_read << 900 if awl_axb?
|
113
162
|
zones.each do |z|
|
114
163
|
@registers_to_read.concat(z.registers_to_read)
|
115
164
|
end
|
116
|
-
@components = [compressor, blower, pump, dhw, humidistat].compact
|
165
|
+
@components = [aux_heat, compressor, blower, pump, dhw, humidistat].compact
|
117
166
|
@components.each do |component|
|
118
167
|
@registers_to_read.concat(component.registers_to_read)
|
119
168
|
end
|
@@ -122,37 +171,7 @@ module Aurora
|
|
122
171
|
end
|
123
172
|
|
124
173
|
def query_registers(query)
|
125
|
-
|
126
|
-
ranges = query.split(",").map do |addr|
|
127
|
-
case addr
|
128
|
-
when "known"
|
129
|
-
implicit = true
|
130
|
-
Aurora::REGISTER_NAMES.keys
|
131
|
-
when "valid"
|
132
|
-
implicit = true
|
133
|
-
break Aurora::REGISTER_RANGES
|
134
|
-
when /^(\d+)(?:\.\.|-)(\d+)$/
|
135
|
-
$1.to_i..$2.to_i
|
136
|
-
else
|
137
|
-
addr.to_i
|
138
|
-
end
|
139
|
-
end
|
140
|
-
queries = Aurora.normalize_ranges(ranges)
|
141
|
-
registers = {}
|
142
|
-
queries.each do |subquery|
|
143
|
-
registers.merge!(@modbus_slave.read_multiple_holding_registers(*subquery))
|
144
|
-
rescue ::ModBus::Errors::IllegalDataAddress
|
145
|
-
# maybe this unit doesn't respond to all the addresses we want?
|
146
|
-
raise unless implicit
|
147
|
-
|
148
|
-
# try each query individually
|
149
|
-
subquery.each do |subsubquery|
|
150
|
-
registers.merge!(@modbus_slave.read_multiple_holding_registers(subsubquery))
|
151
|
-
rescue ::ModBus::Errors::IllegalDataAddress
|
152
|
-
next
|
153
|
-
end
|
154
|
-
end
|
155
|
-
registers
|
174
|
+
self.class.query_registers(@modbus_slave, query)
|
156
175
|
end
|
157
176
|
|
158
177
|
def refresh
|
@@ -164,8 +183,8 @@ module Aurora
|
|
164
183
|
|
165
184
|
outputs = registers[30]
|
166
185
|
|
167
|
-
@entering_air_temperature = registers[
|
168
|
-
@leaving_air_temperature = registers[900]
|
186
|
+
@entering_air_temperature = registers[567]
|
187
|
+
@leaving_air_temperature = registers[900] if awl_axb?
|
169
188
|
@leaving_water_temperature = registers[1110]
|
170
189
|
@entering_water_temperature = registers[1111]
|
171
190
|
@outdoor_temperature = registers[31_003]
|
@@ -175,8 +194,8 @@ module Aurora
|
|
175
194
|
@error = registers[25] & 0x7fff
|
176
195
|
@derated = (41..46).cover?(@error)
|
177
196
|
@safe_mode = [47, 48, 49, 72, 74].include?(@error)
|
178
|
-
@
|
179
|
-
@
|
197
|
+
@line_voltage = registers[112]
|
198
|
+
@watts = registers[1153]
|
180
199
|
|
181
200
|
@current_mode = if outputs.include?(:lockout)
|
182
201
|
:lockout
|
@@ -184,10 +203,6 @@ module Aurora
|
|
184
203
|
:dehumidify
|
185
204
|
elsif outputs.include?(:cc2) || outputs.include?(:cc)
|
186
205
|
outputs.include?(:rv) ? :cooling : :heating
|
187
|
-
elsif outputs.include?(:eh2)
|
188
|
-
outputs.include?(:rv) ? :eh2 : :emergency
|
189
|
-
elsif outputs.include?(:eh1)
|
190
|
-
outputs.include?(:rv) ? :eh1 : :emergency
|
191
206
|
elsif outputs.include?(:blower)
|
192
207
|
:blower
|
193
208
|
elsif registers[6]
|
@@ -255,13 +270,18 @@ module Aurora
|
|
255
270
|
end
|
256
271
|
|
257
272
|
# config aurora system
|
258
|
-
{ thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824 }.each do |(component, register)|
|
273
|
+
{ thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824, awl: 827 }.each do |(component, register)|
|
259
274
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
260
275
|
def #{component}?
|
261
276
|
return @#{component} if instance_variable_defined?(:@#{component})
|
262
277
|
@#{component} = @modbus_slave.holding_registers[#{register}] != 3
|
263
278
|
end
|
264
279
|
|
280
|
+
def #{component}_version
|
281
|
+
return @#{component}_version if instance_variable_defined?(:@#{component}_version)
|
282
|
+
@#{component}_version = @modbus_slave.holding_registers[#{register + 1}].to_f / 100
|
283
|
+
end
|
284
|
+
|
265
285
|
def add_#{component}
|
266
286
|
@modbus_slave.holding_registers[#{register}] = 2
|
267
287
|
end
|
@@ -272,6 +292,27 @@ module Aurora
|
|
272
292
|
RUBY
|
273
293
|
end
|
274
294
|
|
295
|
+
# see https://www.waterfurnace.com/literature/symphony/ig2001ew.pdf
|
296
|
+
# is there a communicating system compliant with AWL?
|
297
|
+
def awl_communicating?
|
298
|
+
awl_thermostat? || awl_iz2?
|
299
|
+
end
|
300
|
+
|
301
|
+
# is the thermostat AWL compliant?
|
302
|
+
def awl_thermostat?
|
303
|
+
thermostat? && thermostat_version >= 3.0
|
304
|
+
end
|
305
|
+
|
306
|
+
# is the IZ2 AWL compliant?
|
307
|
+
def awl_iz2?
|
308
|
+
iz2? && iz2_version >= 2.0
|
309
|
+
end
|
310
|
+
|
311
|
+
# is the AXB AWL compliant?
|
312
|
+
def awl_axb?
|
313
|
+
axb? && axb_version >= 2.0
|
314
|
+
end
|
315
|
+
|
275
316
|
def inspect
|
276
317
|
"#<Aurora::ABCClient #{(instance_variables - [:@modbus_slave]).map do |iv|
|
277
318
|
"#{iv}=#{instance_variable_get(iv).inspect}"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aurora/component"
|
4
|
+
|
5
|
+
module Aurora
|
6
|
+
class AuxHeat < Component
|
7
|
+
attr_reader :stage, :watts
|
8
|
+
|
9
|
+
def refresh(registers)
|
10
|
+
outputs = registers[30]
|
11
|
+
@stage = if outputs.include?(:eh2)
|
12
|
+
2
|
13
|
+
elsif outputs.include?(:eh1)
|
14
|
+
1
|
15
|
+
else
|
16
|
+
0
|
17
|
+
end
|
18
|
+
@watts = registers[1151] if abc.energy_monitoring?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/aurora/blower.rb
CHANGED
data/lib/aurora/component.rb
CHANGED
data/lib/aurora/compressor.rb
CHANGED
@@ -42,7 +42,7 @@ module Aurora
|
|
42
42
|
end
|
43
43
|
|
44
44
|
class VSDrive < GenericCompressor
|
45
|
-
attr_reader :ambient_temperature, :iz2_desired_speed
|
45
|
+
attr_reader :drive_temperature, :inverter_temperature, :ambient_temperature, :iz2_desired_speed, :fan_speed
|
46
46
|
|
47
47
|
def initialize(abc)
|
48
48
|
super(abc, 12)
|
@@ -53,7 +53,7 @@ module Aurora
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def registers_to_read
|
56
|
-
result = super + [209, 3001, 3326]
|
56
|
+
result = super + [209, 3001, 3326..3327, 3522, 3524]
|
57
57
|
result << 564 if abc.iz2?
|
58
58
|
result
|
59
59
|
end
|
@@ -63,6 +63,10 @@ module Aurora
|
|
63
63
|
|
64
64
|
@speed = registers[3001]
|
65
65
|
@ambient_temperature = registers[3326]
|
66
|
+
@drive_temperature = registers[3327]
|
67
|
+
@inverter_temperature = registers[3522]
|
68
|
+
@fan_speed = registers[3524]
|
69
|
+
|
66
70
|
@iz2_desired_speed = registers[564] if abc.iz2?
|
67
71
|
end
|
68
72
|
end
|
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.
|
@@ -867,11 +867,11 @@ module Aurora
|
|
867
867
|
3225 => "VS Drive Details (Safemode 2)",
|
868
868
|
3226 => "VS Drive Details (Alarm 1)",
|
869
869
|
3227 => "VS Drive Details (Alarm 2)",
|
870
|
-
3327 => "VS Drive Temperature",
|
871
870
|
3322 => "VS Drive Discharge Pressure",
|
872
871
|
3323 => "VS Drive Suction Pressure",
|
873
872
|
3325 => "VS Drive Discharge Temperature",
|
874
873
|
3326 => "VS Drive Compressor Ambient Temperature",
|
874
|
+
3327 => "VS Drive Temperature",
|
875
875
|
3330 => "VS Drive Entering Water Temperature",
|
876
876
|
3331 => "VS Drive Line Voltage",
|
877
877
|
3332 => "VS Drive Thermo Power",
|
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
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waterfurnace_aurora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ccutrer-serialport
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- exe/web_aid_tool
|
167
167
|
- lib/aurora.rb
|
168
168
|
- lib/aurora/abc_client.rb
|
169
|
+
- lib/aurora/aux_heat.rb
|
169
170
|
- lib/aurora/blower.rb
|
170
171
|
- lib/aurora/component.rb
|
171
172
|
- lib/aurora/compressor.rb
|