waterfurnace_aurora 0.8.0 → 1.2.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 +17 -6
- data/exe/aurora_mqtt_bridge +228 -76
- data/exe/web_aid_tool +6 -2
- data/lib/aurora/abc_client.rb +76 -26
- 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 +30 -8
- data/lib/aurora/dhw.rb +0 -1
- data/lib/aurora/humidistat.rb +0 -4
- data/lib/aurora/iz2_zone.rb +0 -6
- data/lib/aurora/mock_abc.rb +4 -1
- data/lib/aurora/registers.rb +9 -5
- data/lib/aurora/thermostat.rb +2 -8
- data/lib/aurora/version.rb +1 -1
- data/lib/aurora.rb +3 -0
- 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: d9f0f7d0f0c846720df96f8889d1d5952ece7e0dbabea3431484f4efbff06f5a
|
4
|
+
data.tar.gz: e82bc4400c9543322debe51a21da1dea54d07a673f7302e5ec2a2910e8229714
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eddd8d24b22c6a1c1c64c8fdd29f79c00c76145252b5ddbcd08cf2c7edd0f03182439cb9cf511041bc1a789823b421eefcb3ac90d3f5c72e6fcb54fdf88dc60d
|
7
|
+
data.tar.gz: 76b06de5f2ff979a0c4eaaf05998d4856aa01f491f80fc224870920319d9abda0c89c800a221d532f3c2ccb850c01217570d3f72b447af221186da18ed81fa84
|
data/exe/aurora_fetch
CHANGED
@@ -8,20 +8,31 @@ require "optparse"
|
|
8
8
|
require "uri"
|
9
9
|
require "yaml"
|
10
10
|
|
11
|
-
debug_modbus = yaml = false
|
11
|
+
debug_modbus = yaml = ignore_missing_registers = false
|
12
12
|
try_individual = nil
|
13
13
|
|
14
14
|
options = OptionParser.new do |opts|
|
15
15
|
opts.banner = "Usage: aurora_fetch /path/to/serial/port REGISTERS [options]"
|
16
16
|
|
17
17
|
opts.separator("")
|
18
|
-
opts.separator(
|
18
|
+
opts.separator(<<~TEXT)
|
19
|
+
Use `known` to fetch all identified registers. Use `valid` to fetch all registers
|
20
|
+
that should respond. Use `all` to search the entire ModBus address space. Note that
|
21
|
+
logging of current progress is only periodic, and does not log every register it's
|
22
|
+
trying to fetch.
|
23
|
+
TEXT
|
19
24
|
opts.separator("")
|
20
25
|
|
21
|
-
opts.on("--debug-modbus", "Print actual protocol bytes")
|
26
|
+
opts.on("--debug-modbus", "Print actual protocol bytes") do
|
27
|
+
debug_modbus = true
|
28
|
+
end
|
22
29
|
opts.on("--[no-]try-individual",
|
23
30
|
"Query registers one-by-one if a range has an illegal address. " \
|
24
31
|
"Defaults to true for `valid` and `known` special registers, false otherwise.") { |v| try_individual = v }
|
32
|
+
opts.on("--ignore-missing-registers",
|
33
|
+
"For YAML input only, just log a warning when a register doesn't exist, instead of failing") do
|
34
|
+
ignore_missing_registers = true
|
35
|
+
end
|
25
36
|
opts.on("-y", "--yaml", "Output raw values as YAML") { yaml = true }
|
26
37
|
opts.on("-v", "--version", "Print version") do
|
27
38
|
puts Aurora::VERSION
|
@@ -40,11 +51,11 @@ unless ARGV.length == 2
|
|
40
51
|
exit 1
|
41
52
|
end
|
42
53
|
|
43
|
-
modbus_slave = Aurora::ABCClient.open_modbus_slave(ARGV[0])
|
54
|
+
modbus_slave = Aurora::ABCClient.open_modbus_slave(ARGV[0], ignore_missing_registers: ignore_missing_registers)
|
44
55
|
modbus_slave.read_retry_timeout = 15
|
45
56
|
modbus_slave.read_retries = 2
|
46
|
-
modbus_slave.logger = Logger.new($
|
47
|
-
modbus_slave.logger.level = debug_modbus ? :debug : :
|
57
|
+
Aurora.logger = modbus_slave.logger = Logger.new($stderr)
|
58
|
+
modbus_slave.logger.level = debug_modbus ? :debug : :info
|
48
59
|
|
49
60
|
registers = Aurora::ABCClient.query_registers(modbus_slave, ARGV[1], try_individual: try_individual)
|
50
61
|
|
data/exe/aurora_mqtt_bridge
CHANGED
@@ -90,29 +90,33 @@ class MQTTBridge
|
|
90
90
|
loop do
|
91
91
|
begin
|
92
92
|
@mutex.synchronize do
|
93
|
-
@
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
93
|
+
@homie.mqtt.batch_publish do
|
94
|
+
@abc.refresh
|
95
|
+
|
96
|
+
components = { @homie_abc => @abc,
|
97
|
+
@aux_heat => @abc.aux_heat,
|
98
|
+
@compressor => @abc.compressor,
|
99
|
+
@blower => @abc.blower,
|
100
|
+
@pump => @abc.pump,
|
101
|
+
@dhw => @abc.dhw,
|
102
|
+
@humidistat => @abc.humidistat }.compact
|
103
|
+
@abc.zones.each_with_index do |z, idx|
|
104
|
+
homie_zone = @homie["zone#{idx + 1}"]
|
105
|
+
components[homie_zone] = z
|
106
|
+
end
|
105
107
|
|
106
|
-
|
107
|
-
|
108
|
-
|
108
|
+
components.each do |(node, object)|
|
109
|
+
node.each do |property|
|
110
|
+
property.value = object.public_send(property.id.tr("-", "_"))
|
111
|
+
end
|
109
112
|
end
|
110
|
-
end
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
+
@faults["current"].value = @abc.current_fault
|
115
|
+
@abc.faults.each_with_index do |fault_count, i|
|
116
|
+
next if fault_count == 0xffff
|
114
117
|
|
115
|
-
|
118
|
+
@faults["e#{i + 1}"].value = fault_count
|
119
|
+
end
|
116
120
|
end
|
117
121
|
end
|
118
122
|
rescue => e
|
@@ -131,7 +135,7 @@ class MQTTBridge
|
|
131
135
|
}
|
132
136
|
|
133
137
|
@homie_abc = @homie.node("abc", "Heat Pump", "ABC") do |node|
|
134
|
-
allowed_modes = %w[lockout standby blower heating
|
138
|
+
allowed_modes = %w[lockout standby blower heating heating_with_aux emergency_heat cooling waiting]
|
135
139
|
allowed_modes << "dehumidify" if @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
136
140
|
node.property("current-mode",
|
137
141
|
"Current Heating/Cooling Mode",
|
@@ -139,6 +143,31 @@ class MQTTBridge
|
|
139
143
|
@abc.current_mode,
|
140
144
|
format: allowed_modes,
|
141
145
|
hass: { sensor: { state_class: :measurement } })
|
146
|
+
node.property("emergency-shutdown",
|
147
|
+
"Emergency Shutdown Requested",
|
148
|
+
:boolean,
|
149
|
+
@abc.emergency_shutdown?,
|
150
|
+
hass: :binary_sensor)
|
151
|
+
node.property("load-shed",
|
152
|
+
"Load Shed Requested",
|
153
|
+
:boolean,
|
154
|
+
@abc.load_shed?,
|
155
|
+
hass: :binary_sensor)
|
156
|
+
node.property("locked-out",
|
157
|
+
"Is the heat pump currently locked out?",
|
158
|
+
:boolean,
|
159
|
+
@abc.locked_out?,
|
160
|
+
hass: :binary_sensor)
|
161
|
+
node.property("derated",
|
162
|
+
"Is the compressor currently running at a derated level?",
|
163
|
+
:boolean,
|
164
|
+
@abc.derated?,
|
165
|
+
hass: :binary_sensor)
|
166
|
+
node.property("safe-mode",
|
167
|
+
"Is the heat pump currently in safe mode?",
|
168
|
+
:boolean,
|
169
|
+
@abc.safe_mode?,
|
170
|
+
hass: :binary_sensor)
|
142
171
|
node.property("entering-air-temperature",
|
143
172
|
"Entering Air Temperature",
|
144
173
|
:float,
|
@@ -155,6 +184,17 @@ class MQTTBridge
|
|
155
184
|
hass: { sensor: { device_class: :temperature,
|
156
185
|
state_class: :measurement,
|
157
186
|
entity_category: :diagnostic } })
|
187
|
+
node.property("low-pressure-switch",
|
188
|
+
"Low Pressure Switch Status",
|
189
|
+
:enum,
|
190
|
+
@abc.low_pressure_switch,
|
191
|
+
format: %w[open closed])
|
192
|
+
node.property("high-pressure-switch",
|
193
|
+
"High Pressure Switch Status",
|
194
|
+
:enum,
|
195
|
+
@abc.high_pressure_switch,
|
196
|
+
format: %w[open closed])
|
197
|
+
|
158
198
|
if @abc.awl_communicating?
|
159
199
|
node.property("leaving-air-temperature",
|
160
200
|
"Leaving Air Temperature",
|
@@ -189,31 +229,22 @@ class MQTTBridge
|
|
189
229
|
:integer,
|
190
230
|
@abc.line_voltage,
|
191
231
|
format: 90..635,
|
192
|
-
unit: "V") do |value
|
193
|
-
@mutex.synchronize {
|
232
|
+
unit: "V") do |value|
|
233
|
+
@mutex.synchronize { @abc.line_voltage = value }
|
194
234
|
end
|
195
|
-
node.property("
|
196
|
-
"
|
235
|
+
node.property("air-coil-temperature",
|
236
|
+
"Air Coil Temperature (FP2)",
|
197
237
|
:float,
|
198
|
-
@abc.
|
238
|
+
@abc.air_coil_temperature,
|
199
239
|
unit: "°F",
|
200
240
|
hass: { sensor: { device_class: :temperature,
|
201
241
|
state_class: :measurement,
|
202
242
|
entity_category: :diagnostic } })
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
@abc.fp2,
|
207
|
-
unit: "°F",
|
208
|
-
hass: { sensor: { device_class: :temperature,
|
209
|
-
state_class: :measurement,
|
210
|
-
entity_category: :diagnostic } })
|
211
|
-
%i[aux_heat total].each do |component|
|
212
|
-
component = "#{component}_watts"
|
213
|
-
node.property(component.tr("_", "-"),
|
214
|
-
component.sub("_watts", " Power Usage").tr("_", " ").titleize,
|
243
|
+
if @abc.energy_monitoring?
|
244
|
+
node.property("watts",
|
245
|
+
"Total Power Usage",
|
215
246
|
:integer,
|
216
|
-
@abc.
|
247
|
+
@abc.watts,
|
217
248
|
unit: "W",
|
218
249
|
hass: { sensor: { device_class: :power,
|
219
250
|
state_class: :measurement } })
|
@@ -227,6 +258,22 @@ class MQTTBridge
|
|
227
258
|
@abc.compressor.speed,
|
228
259
|
format: @abc.compressor.speed_range,
|
229
260
|
hass: { sensor: { state_class: :measurement } })
|
261
|
+
node.property("cooling-liquid-line-temperature",
|
262
|
+
"Cooling Liquid Line Temperature (FP1)",
|
263
|
+
:float,
|
264
|
+
@abc.compressor.cooling_liquid_line_temperature,
|
265
|
+
unit: "°F",
|
266
|
+
hass: { sensor: { device_class: :temperature,
|
267
|
+
state_class: :measurement,
|
268
|
+
entity_category: :diagnostic } })
|
269
|
+
node.property("saturated-condensor-discharge-temperature",
|
270
|
+
"Saturated Condensor Discharge Temperature",
|
271
|
+
:float,
|
272
|
+
@abc.compressor.saturated_condensor_discharge_temperature,
|
273
|
+
unit: "°F",
|
274
|
+
hass: { sensor: { device_class: :temperature,
|
275
|
+
state_class: :measurement,
|
276
|
+
entity_category: :diagnostic } })
|
230
277
|
if @abc.energy_monitoring?
|
231
278
|
node.property("watts",
|
232
279
|
"Power Usage",
|
@@ -247,6 +294,86 @@ class MQTTBridge
|
|
247
294
|
hass: { sensor: { device_class: :temperature,
|
248
295
|
state_class: :measurement,
|
249
296
|
entity_category: :diagnostic } })
|
297
|
+
node.property("drive-temperature",
|
298
|
+
"Drive Temperature",
|
299
|
+
:float,
|
300
|
+
@abc.compressor.drive_temperature,
|
301
|
+
unit: "°F",
|
302
|
+
hass: { sensor: { device_class: :temperature,
|
303
|
+
state_class: :measurement,
|
304
|
+
entity_category: :diagnostic } })
|
305
|
+
node.property("inverter-temperature",
|
306
|
+
"Inverter Temperature",
|
307
|
+
:float,
|
308
|
+
@abc.compressor.inverter_temperature,
|
309
|
+
unit: "°F",
|
310
|
+
hass: { sensor: { device_class: :temperature,
|
311
|
+
state_class: :measurement,
|
312
|
+
entity_category: :diagnostic } })
|
313
|
+
node.property("fan-speed",
|
314
|
+
"Fan Speed",
|
315
|
+
:integer,
|
316
|
+
@abc.compressor.fan_speed,
|
317
|
+
unit: "%",
|
318
|
+
format: 0..100,
|
319
|
+
hass: { sensor: { state_class: :measurement,
|
320
|
+
entity_category: :diagnostic } })
|
321
|
+
node.property("discharge-temperature",
|
322
|
+
"Discharge Temperature",
|
323
|
+
:float,
|
324
|
+
@abc.compressor.discharge_temperature,
|
325
|
+
unit: "°F",
|
326
|
+
hass: { sensor: { device_class: :temperature,
|
327
|
+
state_class: :measurement,
|
328
|
+
entity_category: :diagnostic } })
|
329
|
+
node.property("discharge-pressure",
|
330
|
+
"Discharge Pressure",
|
331
|
+
:float,
|
332
|
+
@abc.compressor.discharge_pressure,
|
333
|
+
unit: "psi",
|
334
|
+
hass: { sensor: { device_class: :pressure,
|
335
|
+
state_class: :measurement,
|
336
|
+
entity_category: :diagnostic } })
|
337
|
+
node.property("suction-temperature",
|
338
|
+
"Suction Temperature",
|
339
|
+
:float,
|
340
|
+
@abc.compressor.suction_temperature,
|
341
|
+
unit: "°F",
|
342
|
+
hass: { sensor: { device_class: :temperature,
|
343
|
+
state_class: :measurement,
|
344
|
+
entity_category: :diagnostic } })
|
345
|
+
node.property("suction-pressure",
|
346
|
+
"Suction Pressure",
|
347
|
+
:float,
|
348
|
+
@abc.compressor.suction_pressure,
|
349
|
+
unit: "psi",
|
350
|
+
hass: { sensor: { device_class: :pressure,
|
351
|
+
state_class: :measurement,
|
352
|
+
entity_category: :diagnostic } })
|
353
|
+
node.property("saturated-evaporator-discharge-temperature",
|
354
|
+
"Saturated Evaporator Discharge Temperature",
|
355
|
+
:float,
|
356
|
+
@abc.compressor.saturated_evaporator_discharge_temperature,
|
357
|
+
unit: "°F",
|
358
|
+
hass: { sensor: { device_class: :temperature,
|
359
|
+
state_class: :measurement,
|
360
|
+
entity_category: :diagnostic } })
|
361
|
+
node.property("superheat-temperature",
|
362
|
+
"SuperHeat Temperature",
|
363
|
+
:float,
|
364
|
+
@abc.compressor.superheat_temperature,
|
365
|
+
unit: "°F",
|
366
|
+
hass: { sensor: { device_class: :temperature,
|
367
|
+
state_class: :measurement,
|
368
|
+
entity_category: :diagnostic } })
|
369
|
+
node.property("superheat-percentage",
|
370
|
+
"SuperHeat Percentage",
|
371
|
+
:integer,
|
372
|
+
@abc.compressor.superheat_percentage,
|
373
|
+
unit: "%",
|
374
|
+
format: 0..100,
|
375
|
+
hass: { sensor: { state_class: :measurement,
|
376
|
+
entity_category: :diagnostic } })
|
250
377
|
|
251
378
|
next unless @abc.iz2?
|
252
379
|
|
@@ -259,6 +386,25 @@ class MQTTBridge
|
|
259
386
|
entity_category: :diagnostic } })
|
260
387
|
end
|
261
388
|
|
389
|
+
@aux_heat = @homie.node("aux-heat", "Aux Heater", "Aux Heater") do |node|
|
390
|
+
node.property("stage",
|
391
|
+
"Current Stage",
|
392
|
+
:integer,
|
393
|
+
@abc.aux_heat.stage,
|
394
|
+
format: 0..2,
|
395
|
+
hass: { sensor: { state_class: :measurement } })
|
396
|
+
|
397
|
+
if @abc.energy_monitoring?
|
398
|
+
node.property("watts",
|
399
|
+
"Power Usage",
|
400
|
+
:integer,
|
401
|
+
@abc.aux_heat.watts,
|
402
|
+
unit: "W",
|
403
|
+
hass: { sensor: { device_class: :power,
|
404
|
+
state_class: :measurement } })
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
262
408
|
@blower = @homie.node("blower", "Blower", @abc.blower.type) do |node|
|
263
409
|
node.property("running",
|
264
410
|
"Running",
|
@@ -294,8 +440,8 @@ class MQTTBridge
|
|
294
440
|
:integer,
|
295
441
|
@abc.blower.public_send(field),
|
296
442
|
format: 1..12,
|
297
|
-
hass: { number: { entity_category: :config } }) do |value
|
298
|
-
@mutex.synchronize {
|
443
|
+
hass: { number: { entity_category: :config } }) do |value|
|
444
|
+
@mutex.synchronize { @abc.blower.public_send("#{field}=", value) }
|
299
445
|
end
|
300
446
|
end
|
301
447
|
|
@@ -340,8 +486,8 @@ class MQTTBridge
|
|
340
486
|
"Manual Control",
|
341
487
|
:boolean,
|
342
488
|
@abc.pump.manual_control?,
|
343
|
-
hass: { switch: { entity_category: :diagnostic } }) do |value
|
344
|
-
@mutex.synchronize {
|
489
|
+
hass: { switch: { entity_category: :diagnostic } }) do |value|
|
490
|
+
@mutex.synchronize { @abc.pump.manual_control = value }
|
345
491
|
end
|
346
492
|
node.property("minimum-speed",
|
347
493
|
"Actual Minimum Speed",
|
@@ -349,8 +495,8 @@ class MQTTBridge
|
|
349
495
|
@abc.pump.minimum_speed,
|
350
496
|
format: 0..100,
|
351
497
|
unit: "%",
|
352
|
-
hass: { number: { entity_category: :config } }) do |value
|
353
|
-
@mutex.synchronize {
|
498
|
+
hass: { number: { entity_category: :config } }) do |value|
|
499
|
+
@mutex.synchronize { @abc.pump.minimum_speed = value }
|
354
500
|
end
|
355
501
|
node.property("maximum-speed",
|
356
502
|
"Actual Maximum Speed",
|
@@ -358,8 +504,8 @@ class MQTTBridge
|
|
358
504
|
@abc.pump.minimum_speed,
|
359
505
|
format: 0..100,
|
360
506
|
unit: "%",
|
361
|
-
hass: { number: { entity_category: :config } }) do |value
|
362
|
-
@mutex.synchronize {
|
507
|
+
hass: { number: { entity_category: :config } }) do |value|
|
508
|
+
@mutex.synchronize { @abc.pump.maximum_speed = value }
|
363
509
|
end
|
364
510
|
next unless @abc.awl_axb?
|
365
511
|
|
@@ -369,8 +515,8 @@ class MQTTBridge
|
|
369
515
|
@abc.pump.speed,
|
370
516
|
format: 0..100,
|
371
517
|
unit: "%",
|
372
|
-
hass: { number: { entity_category: :diagnostic } }) do |value
|
373
|
-
@mutex.synchronize {
|
518
|
+
hass: { number: { entity_category: :diagnostic } }) do |value|
|
519
|
+
@mutex.synchronize { @abc.pump.speed = value }
|
374
520
|
end
|
375
521
|
end
|
376
522
|
|
@@ -380,8 +526,8 @@ class MQTTBridge
|
|
380
526
|
"Enabled",
|
381
527
|
:boolean,
|
382
528
|
@abc.dhw.enabled,
|
383
|
-
hass: { switch: { icon: "mdi:water-boiler" } }) do |value
|
384
|
-
@mutex.synchronize {
|
529
|
+
hass: { switch: { icon: "mdi:water-boiler" } }) do |value|
|
530
|
+
@mutex.synchronize { @abc.dhw.enabled = value }
|
385
531
|
end
|
386
532
|
node.property("running",
|
387
533
|
"Pump Running",
|
@@ -401,8 +547,8 @@ class MQTTBridge
|
|
401
547
|
@abc.dhw.set_point,
|
402
548
|
format: 100..140,
|
403
549
|
unit: "°F",
|
404
|
-
hass: { number: { step: 5 } }) do |value
|
405
|
-
@mutex.synchronize {
|
550
|
+
hass: { number: { step: 5 } }) do |value|
|
551
|
+
@mutex.synchronize { @abc.dhw.set_point = value }
|
406
552
|
end
|
407
553
|
end
|
408
554
|
end
|
@@ -418,16 +564,16 @@ class MQTTBridge
|
|
418
564
|
"Humidifier Mode",
|
419
565
|
:enum,
|
420
566
|
@abc.humidistat.humidifier_mode,
|
421
|
-
format: %i[auto manual]) do |value
|
422
|
-
@mutex.synchronize {
|
567
|
+
format: %i[auto manual]) do |value|
|
568
|
+
@mutex.synchronize { @abc.humidistat.humidifier_mode = value.to_sym }
|
423
569
|
end
|
424
570
|
node.property("humidification-target",
|
425
571
|
"Humidification Target Relative Humidity",
|
426
572
|
:integer,
|
427
573
|
@abc.humidistat.humidification_target,
|
428
574
|
unit: "%",
|
429
|
-
format: 15..50) do |value
|
430
|
-
@mutex.synchronize {
|
575
|
+
format: 15..50) do |value|
|
576
|
+
@mutex.synchronize { @abc.humidistat.humidification_target = value }
|
431
577
|
end
|
432
578
|
node.hass_humidifier("humidifier-running",
|
433
579
|
target_property: "humidification-target",
|
@@ -450,16 +596,16 @@ class MQTTBridge
|
|
450
596
|
"Dehumidifier Mode",
|
451
597
|
:enum,
|
452
598
|
@abc.humidistat.dehumidifier_mode,
|
453
|
-
format: %i[auto manual]) do |value
|
454
|
-
@mutex.synchronize {
|
599
|
+
format: %i[auto manual]) do |value|
|
600
|
+
@mutex.synchronize { @abc.humidistat.dehumidifier_mode = value.to_sym }
|
455
601
|
end
|
456
602
|
node.property("dehumidification-target",
|
457
603
|
"Dehumidification Target Relative Humidity",
|
458
604
|
:integer,
|
459
605
|
@abc.humidistat.dehumidification_target,
|
460
606
|
unit: "%",
|
461
|
-
format: 35..65) do |value
|
462
|
-
@mutex.synchronize {
|
607
|
+
format: 35..65) do |value|
|
608
|
+
@mutex.synchronize { @abc.humidistat.dehumidification_target = value }
|
463
609
|
end
|
464
610
|
node.hass_humidifier("dehumidifier-running",
|
465
611
|
target_property: "dehumidification-target",
|
@@ -482,6 +628,12 @@ class MQTTBridge
|
|
482
628
|
end
|
483
629
|
|
484
630
|
@faults = @homie.node("faults", "Fault History", "ABC") do |node|
|
631
|
+
node.property("current",
|
632
|
+
"Current fault",
|
633
|
+
:integer,
|
634
|
+
@abc.current_fault,
|
635
|
+
format: 0..99,
|
636
|
+
hass: :sensor)
|
485
637
|
node.property("clear-history",
|
486
638
|
"Reset Fault Counts",
|
487
639
|
:enum,
|
@@ -520,15 +672,15 @@ class MQTTBridge
|
|
520
672
|
"Target Heating/Cooling Mode",
|
521
673
|
:enum,
|
522
674
|
zone.target_mode,
|
523
|
-
format: allowed_modes) do |value
|
524
|
-
@mutex.synchronize {
|
675
|
+
format: allowed_modes) do |value|
|
676
|
+
@mutex.synchronize { zone.target_mode = value.to_sym }
|
525
677
|
end
|
526
678
|
node.property("target-fan-mode",
|
527
679
|
"Target Fan Mode",
|
528
680
|
:enum,
|
529
681
|
zone.target_fan_mode,
|
530
|
-
format: %w[auto continuous intermittent]) do |value
|
531
|
-
@mutex.synchronize {
|
682
|
+
format: %w[auto continuous intermittent]) do |value|
|
683
|
+
@mutex.synchronize { zone.target_fan_mode = value.to_sym }
|
532
684
|
end
|
533
685
|
node.property("fan-intermittent-on",
|
534
686
|
"Fan Intermittent Mode On Duration",
|
@@ -536,8 +688,8 @@ class MQTTBridge
|
|
536
688
|
zone.fan_intermittent_on,
|
537
689
|
unit: "M",
|
538
690
|
format: %w[0 5 10 15 20],
|
539
|
-
hass: { select: { entity_category: :config } }) do |value
|
540
|
-
@mutex.synchronize {
|
691
|
+
hass: { select: { entity_category: :config } }) do |value|
|
692
|
+
@mutex.synchronize { zone.fan_intermittent_on = value.to_i }
|
541
693
|
end
|
542
694
|
node.property("fan-intermittent-off",
|
543
695
|
"Fan Intermittent Mode Off Duration",
|
@@ -545,8 +697,8 @@ class MQTTBridge
|
|
545
697
|
zone.fan_intermittent_on,
|
546
698
|
unit: "M",
|
547
699
|
format: %w[0 5 10 15 20 25 30 35 40],
|
548
|
-
hass: { select: { entity_category: :config } }) do |value
|
549
|
-
@mutex.synchronize {
|
700
|
+
hass: { select: { entity_category: :config } }) do |value|
|
701
|
+
@mutex.synchronize { zone.fan_intermittent_on = value.to_i }
|
550
702
|
end
|
551
703
|
node.property("current-fan-mode",
|
552
704
|
"Current Fan Status",
|
@@ -587,15 +739,15 @@ class MQTTBridge
|
|
587
739
|
:integer,
|
588
740
|
zone.heating_target_temperature,
|
589
741
|
unit: "°F",
|
590
|
-
format: 40..90) do |value
|
591
|
-
@mutex.synchronize {
|
742
|
+
format: 40..90) do |value|
|
743
|
+
@mutex.synchronize { zone.heating_target_temperature = value }
|
592
744
|
end
|
593
745
|
node.property("cooling-target-temperature",
|
594
746
|
"Cooling Target Temperature", :integer,
|
595
747
|
zone.cooling_target_temperature,
|
596
748
|
unit: "°F",
|
597
|
-
format: 54..99) do |value
|
598
|
-
@mutex.synchronize {
|
749
|
+
format: 54..99) do |value|
|
750
|
+
@mutex.synchronize { zone.cooling_target_temperature = value }
|
599
751
|
end
|
600
752
|
node.hass_climate(action_property: "current-mode",
|
601
753
|
current_temperature_property: "ambient-temperature",
|
@@ -626,12 +778,12 @@ class MQTTBridge
|
|
626
778
|
end
|
627
779
|
|
628
780
|
log_level = ARGV.include?("--debug") ? :debug : :warn
|
629
|
-
logger = Logger.new($stdout)
|
630
|
-
logger.level = log_level
|
631
|
-
abc.modbus_slave.logger = logger
|
781
|
+
Aurora.logger = Logger.new($stdout)
|
782
|
+
Aurora.logger.level = log_level
|
783
|
+
abc.modbus_slave.logger = Aurora.logger
|
632
784
|
|
633
785
|
device = "aurora-#{abc.serial_number}"
|
634
786
|
homie = MQTT::Homie::Device.new(device, "WaterFurnace", mqtt: mqtt_uri)
|
635
|
-
homie.logger = logger
|
787
|
+
homie.logger = Aurora.logger
|
636
788
|
|
637
789
|
MQTTBridge.new(abc, homie)
|
data/exe/web_aid_tool
CHANGED
@@ -7,13 +7,17 @@ require "logger"
|
|
7
7
|
require "optparse"
|
8
8
|
require "yaml"
|
9
9
|
|
10
|
-
debug_modbus = monitor = false
|
10
|
+
debug_modbus = monitor = ignore_missing_registers = false
|
11
11
|
|
12
12
|
options = OptionParser.new do |opts|
|
13
13
|
opts.banner = "Usage: web_aid_tool /path/to/serial/port [options]"
|
14
14
|
|
15
15
|
opts.on("--debug-modbus", "Print actual protocol bytes") { debug_modbus = true }
|
16
16
|
opts.on("--monitor", "Print interpreted registers as they are requested, like aurora_monitor") { monitor = true }
|
17
|
+
opts.on("--ignore-missing-registers",
|
18
|
+
"For YAML input only, just log a warning when a register doesn't exist, instead of failing") do
|
19
|
+
ignore_missing_registers = true
|
20
|
+
end
|
17
21
|
opts.on("-v", "--version", "Print version") do
|
18
22
|
puts Aurora::VERSION
|
19
23
|
exit
|
@@ -31,7 +35,7 @@ unless ARGV.length == 1
|
|
31
35
|
exit 1
|
32
36
|
end
|
33
37
|
|
34
|
-
slave = Aurora::ABCClient.open_modbus_slave(ARGV[0])
|
38
|
+
slave = Aurora::ABCClient.open_modbus_slave(ARGV[0], ignore_missing_registers: ignore_missing_registers)
|
35
39
|
slave.logger = Logger.new($stdout)
|
36
40
|
slave.logger.level = debug_modbus ? :debug : :warn
|
37
41
|
|
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"
|
@@ -14,7 +15,7 @@ require "aurora/thermostat"
|
|
14
15
|
module Aurora
|
15
16
|
class ABCClient
|
16
17
|
class << self
|
17
|
-
def open_modbus_slave(uri)
|
18
|
+
def open_modbus_slave(uri, ignore_missing_registers: false)
|
18
19
|
uri = URI.parse(uri)
|
19
20
|
|
20
21
|
io = case uri.scheme
|
@@ -31,7 +32,10 @@ module Aurora
|
|
31
32
|
require "aurora/mqtt_modbus"
|
32
33
|
return Aurora::MQTTModBus.new(uri)
|
33
34
|
else
|
34
|
-
|
35
|
+
if File.file?(uri.path)
|
36
|
+
return Aurora::MockABC.new(YAML.load_file(uri.path),
|
37
|
+
ignore_missing_registers: ignore_missing_registers)
|
38
|
+
end
|
35
39
|
|
36
40
|
require "ccutrer-serialport"
|
37
41
|
CCutrer::SerialPort.new(uri.path, baud: 19_200, parity: :even)
|
@@ -53,6 +57,10 @@ module Aurora
|
|
53
57
|
implicit = true
|
54
58
|
try_individual = true if try_individual.nil?
|
55
59
|
break Aurora::REGISTER_RANGES
|
60
|
+
when "all"
|
61
|
+
implicit = true
|
62
|
+
try_individual = true if try_individual.nil?
|
63
|
+
break 0..65_535
|
56
64
|
when /^(\d+)(?:\.\.|-)(\d+)$/
|
57
65
|
$1.to_i..$2.to_i
|
58
66
|
else
|
@@ -61,28 +69,48 @@ module Aurora
|
|
61
69
|
end
|
62
70
|
queries = Aurora.normalize_ranges(ranges)
|
63
71
|
registers = {}
|
72
|
+
last_log_time = nil
|
64
73
|
queries.each do |subquery|
|
74
|
+
last_log_time = log_query(last_log_time, subquery.inspect)
|
65
75
|
registers.merge!(modbus_slave.read_multiple_holding_registers(*subquery))
|
66
|
-
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction
|
76
|
+
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction, ::ModBus::Errors::ModBusTimeout
|
67
77
|
# maybe this unit doesn't respond to all the addresses we want?
|
68
78
|
raise unless implicit
|
69
79
|
|
70
80
|
# try each query individually
|
71
81
|
subquery.each do |subsubquery|
|
82
|
+
last_log_time = log_query(last_log_time, subsubquery.inspect)
|
72
83
|
registers.merge!(modbus_slave.read_multiple_holding_registers(subsubquery))
|
73
|
-
rescue ::ModBus::Errors::IllegalDataAddress,
|
84
|
+
rescue ::ModBus::Errors::IllegalDataAddress,
|
85
|
+
::ModBus::Errors::IllegalFunction,
|
86
|
+
::ModBus::Errors::ModBusTimeout => e
|
87
|
+
raise if e.is_a?(::ModBus::Errors::ModBusTimeout) && !try_individual
|
74
88
|
next unless try_individual
|
75
89
|
|
76
90
|
# seriously?? try each register individually
|
77
|
-
subsubquery.each do |i|
|
91
|
+
Array(subsubquery).each do |i|
|
92
|
+
last_log_time = log_query(last_log_time, i.to_s)
|
78
93
|
registers[i] = modbus_slave.holding_registers[i]
|
79
94
|
rescue ::ModBus::Errors::IllegalDataAddress, ::ModBus::Errors::IllegalFunction
|
95
|
+
# don't catch ModBusTimeout here... it should have no problem responding to a single register request
|
80
96
|
next
|
81
97
|
end
|
82
98
|
end
|
83
99
|
end
|
84
100
|
registers
|
85
101
|
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def log_query(last_log_time, query)
|
106
|
+
last_log_time ||= Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
107
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
108
|
+
if now - last_log_time > 5
|
109
|
+
Aurora&.logger&.info("Fetching register(s) #{query}...")
|
110
|
+
last_log_time = now
|
111
|
+
end
|
112
|
+
last_log_time
|
113
|
+
end
|
86
114
|
end
|
87
115
|
|
88
116
|
attr_reader :modbus_slave,
|
@@ -90,23 +118,36 @@ module Aurora
|
|
90
118
|
:model,
|
91
119
|
:serial_number,
|
92
120
|
:zones,
|
121
|
+
:aux_heat,
|
93
122
|
:compressor,
|
94
123
|
:blower,
|
95
124
|
:pump,
|
96
125
|
:dhw,
|
97
126
|
:humidistat,
|
127
|
+
:current_fault,
|
98
128
|
:faults,
|
129
|
+
:locked_out,
|
130
|
+
:derated,
|
131
|
+
:safe_mode,
|
99
132
|
:current_mode,
|
133
|
+
:low_pressure_switch,
|
134
|
+
:high_pressure_switch,
|
135
|
+
:emergency_shutdown,
|
136
|
+
:load_shed,
|
100
137
|
:entering_air_temperature,
|
101
138
|
:leaving_air_temperature,
|
102
139
|
:leaving_water_temperature,
|
103
140
|
:entering_water_temperature,
|
104
141
|
:outdoor_temperature,
|
105
|
-
:
|
106
|
-
:fp2,
|
142
|
+
:air_coil_temperature,
|
107
143
|
:line_voltage,
|
108
|
-
:
|
109
|
-
|
144
|
+
:watts
|
145
|
+
|
146
|
+
alias_method :emergency_shutdown?, :emergency_shutdown
|
147
|
+
alias_method :load_shed?, :load_shed
|
148
|
+
alias_method :locked_out?, :locked_out
|
149
|
+
alias_method :derated?, :derated
|
150
|
+
alias_method :safe_mode?, :safe_mode
|
110
151
|
|
111
152
|
def initialize(uri)
|
112
153
|
@modbus_slave = self.class.open_modbus_slave(uri)
|
@@ -129,6 +170,7 @@ module Aurora
|
|
129
170
|
|
130
171
|
@abc_dipswitches = registers[33]
|
131
172
|
@axb_dipswitches = registers[1103]
|
173
|
+
@aux_heat = AuxHeat.new(self)
|
132
174
|
@compressor = if @program == "ABCVSP"
|
133
175
|
Compressor::VSDrive.new(self)
|
134
176
|
else
|
@@ -154,13 +196,15 @@ module Aurora
|
|
154
196
|
|
155
197
|
@faults = []
|
156
198
|
|
157
|
-
@
|
199
|
+
@entering_air_register = awl_axb? ? 740 : 567
|
200
|
+
@registers_to_read = [6, 19..20, 25, 30..31, 112, 344, @entering_air_register, 1104, 1110..1111, 1114, 1150..1153,
|
201
|
+
1165]
|
158
202
|
@registers_to_read.concat([741, 31_003]) if awl_communicating?
|
159
203
|
@registers_to_read << 900 if awl_axb?
|
160
204
|
zones.each do |z|
|
161
205
|
@registers_to_read.concat(z.registers_to_read)
|
162
206
|
end
|
163
|
-
@components = [compressor, blower, pump, dhw, humidistat].compact
|
207
|
+
@components = [aux_heat, compressor, blower, pump, dhw, humidistat].compact
|
164
208
|
@components.each do |component|
|
165
209
|
@registers_to_read.concat(component.registers_to_read)
|
166
210
|
end
|
@@ -181,34 +225,40 @@ module Aurora
|
|
181
225
|
|
182
226
|
outputs = registers[30]
|
183
227
|
|
184
|
-
@entering_air_temperature = registers[
|
228
|
+
@entering_air_temperature = registers[@entering_air_register]
|
185
229
|
@leaving_air_temperature = registers[900] if awl_axb?
|
186
230
|
@leaving_water_temperature = registers[1110]
|
187
231
|
@entering_water_temperature = registers[1111]
|
188
232
|
@outdoor_temperature = registers[31_003]
|
189
|
-
@
|
190
|
-
@
|
191
|
-
@
|
192
|
-
@
|
193
|
-
@
|
194
|
-
@
|
233
|
+
@air_coil_temperature = registers[20]
|
234
|
+
@locked_out = !(registers[25] & 0x8000).zero?
|
235
|
+
@current_fault = registers[25] & 0x7fff
|
236
|
+
@derated = (41..46).cover?(@current_fault)
|
237
|
+
@safe_mode = [47, 48, 49, 72, 74].include?(@current_fault)
|
238
|
+
@low_pressure_switch = registers[31][:lps]
|
239
|
+
@high_pressure_switch = registers[31][:hps]
|
240
|
+
@emergency_shutdown = !!registers[31][:emergency_shutdown]
|
241
|
+
@load_shed = !!registers[31][:load_shed]
|
195
242
|
@line_voltage = registers[112]
|
196
|
-
@
|
197
|
-
@total_watts = registers[1153]
|
243
|
+
@watts = registers[1153]
|
198
244
|
|
199
245
|
@current_mode = if outputs.include?(:lockout)
|
200
246
|
:lockout
|
201
247
|
elsif registers[362]
|
202
248
|
:dehumidify
|
203
249
|
elsif outputs.include?(:cc2) || outputs.include?(:cc)
|
204
|
-
outputs.include?(:rv)
|
205
|
-
|
206
|
-
outputs.include?(:
|
207
|
-
|
208
|
-
|
250
|
+
if outputs.include?(:rv)
|
251
|
+
:cooling
|
252
|
+
elsif outputs.include?(:eh2) || outputs.include?(:eh1)
|
253
|
+
:heating_with_aux
|
254
|
+
else
|
255
|
+
:heating
|
256
|
+
end
|
257
|
+
elsif outputs.include?(:eh2) || outputs.include?(:eh1)
|
258
|
+
:emergency_heat
|
209
259
|
elsif outputs.include?(:blower)
|
210
260
|
:blower
|
211
|
-
elsif registers[6]
|
261
|
+
elsif !registers[6].zero?
|
212
262
|
:waiting
|
213
263
|
else
|
214
264
|
:standby
|
@@ -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
@@ -5,7 +5,7 @@ require "aurora/component"
|
|
5
5
|
module Aurora
|
6
6
|
module Compressor
|
7
7
|
class GenericCompressor < Component
|
8
|
-
attr_reader :speed, :watts
|
8
|
+
attr_reader :speed, :watts, :cooling_liquid_line_temperature, :saturated_condensor_discharge_temperature
|
9
9
|
|
10
10
|
def initialize(abc, stages)
|
11
11
|
super(abc)
|
@@ -21,11 +21,9 @@ module Aurora
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def registers_to_read
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
[]
|
28
|
-
end
|
24
|
+
result = [19, 1134]
|
25
|
+
result << (1146..1147) if abc.energy_monitoring?
|
26
|
+
result
|
29
27
|
end
|
30
28
|
|
31
29
|
def refresh(registers)
|
@@ -37,12 +35,25 @@ module Aurora
|
|
37
35
|
else
|
38
36
|
0
|
39
37
|
end
|
38
|
+
@cooling_liquid_line_temperature = registers[19]
|
39
|
+
@saturated_condensor_discharge_temperature = registers[1134]
|
40
40
|
@watts = registers[1146] if abc.energy_monitoring?
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
class VSDrive < GenericCompressor
|
45
|
-
attr_reader :
|
45
|
+
attr_reader :drive_temperature,
|
46
|
+
:inverter_temperature,
|
47
|
+
:ambient_temperature,
|
48
|
+
:iz2_desired_speed,
|
49
|
+
:fan_speed,
|
50
|
+
:discharge_pressure,
|
51
|
+
:discharge_temperature,
|
52
|
+
:suction_pressure,
|
53
|
+
:suction_temperature,
|
54
|
+
:saturated_evaporator_discharge_temperature,
|
55
|
+
:superheat_temperature,
|
56
|
+
:superheat_percentage
|
46
57
|
|
47
58
|
def initialize(abc)
|
48
59
|
super(abc, 12)
|
@@ -53,7 +64,7 @@ module Aurora
|
|
53
64
|
end
|
54
65
|
|
55
66
|
def registers_to_read
|
56
|
-
result = super + [209, 3001,
|
67
|
+
result = super + [209, 3001, 3322..3327, 3522, 3524, 3808, 3903..3906]
|
57
68
|
result << 564 if abc.iz2?
|
58
69
|
result
|
59
70
|
end
|
@@ -62,7 +73,18 @@ module Aurora
|
|
62
73
|
super
|
63
74
|
|
64
75
|
@speed = registers[3001]
|
76
|
+
@discharge_pressure = registers[3322]
|
77
|
+
@suction_pressure = registers[3323]
|
78
|
+
@discharge_temperature = registers[3325]
|
65
79
|
@ambient_temperature = registers[3326]
|
80
|
+
@drive_temperature = registers[3327]
|
81
|
+
@inverter_temperature = registers[3522]
|
82
|
+
@fan_speed = registers[3524]
|
83
|
+
@superheat_percentage = registers[3808]
|
84
|
+
@suction_temperature = registers[3903]
|
85
|
+
@saturated_evaporator_discharge_temperature = registers[3905]
|
86
|
+
@superheat_temperature = registers[3906]
|
87
|
+
|
66
88
|
@iz2_desired_speed = registers[564] if abc.iz2?
|
67
89
|
end
|
68
90
|
end
|
data/lib/aurora/dhw.rb
CHANGED
data/lib/aurora/humidistat.rb
CHANGED
@@ -75,8 +75,6 @@ module Aurora
|
|
75
75
|
raw_value |= 0x4000 if humidifier_mode == :auto
|
76
76
|
raw_value |= 0x8000 if dehumidifier_mode == :auto
|
77
77
|
holding_registers[abc.iz2? ? 21_114 : 12_309] = raw_value
|
78
|
-
@humidifier_mode = humidifier_mode
|
79
|
-
@dehumidifier_mode = dehumidifier_mode
|
80
78
|
end
|
81
79
|
|
82
80
|
def humidification_target=(value)
|
@@ -92,8 +90,6 @@ module Aurora
|
|
92
90
|
raise ArgumentError unless (35..65).cover?(dehumidification_target)
|
93
91
|
|
94
92
|
holding_registers[abc.iz2? ? 21_115 : 12_310] = (humidification_target << 8) + dehumidification_target
|
95
|
-
@humidification_target = humidification_target
|
96
|
-
@dehumidification_target = dehumidification_target
|
97
93
|
end
|
98
94
|
end
|
99
95
|
end
|
data/lib/aurora/iz2_zone.rb
CHANGED
@@ -46,28 +46,24 @@ module Aurora
|
|
46
46
|
return unless (raw_value = Aurora::HEATING_MODE.invert[value])
|
47
47
|
|
48
48
|
holding_registers[21_202 + ((zone_number - 1) * 9)] = raw_value
|
49
|
-
@target_mode = value
|
50
49
|
end
|
51
50
|
|
52
51
|
def target_fan_mode=(value)
|
53
52
|
return unless (raw_value = Aurora::FAN_MODE.invert[value])
|
54
53
|
|
55
54
|
holding_registers[21_205 + ((zone_number - 1) * 9)] = raw_value
|
56
|
-
@target_fan_mode = value
|
57
55
|
end
|
58
56
|
|
59
57
|
def fan_intermittent_on=(value)
|
60
58
|
return unless value >= 0 && value <= 25 && (value % 5).zero?
|
61
59
|
|
62
60
|
holding_registers[21_206 + ((zone_number - 1) * 9)] = value
|
63
|
-
@fan_intermittent_on = value
|
64
61
|
end
|
65
62
|
|
66
63
|
def fan_intermittent_off=(value)
|
67
64
|
return unless value >= 0 && value <= 40 && (value % 5).zero?
|
68
65
|
|
69
66
|
holding_registers[21_207 + ((zone_number - 1) * 9)] = value
|
70
|
-
@fan_intermittent_off = value
|
71
67
|
end
|
72
68
|
|
73
69
|
def heating_target_temperature=(value)
|
@@ -75,7 +71,6 @@ module Aurora
|
|
75
71
|
|
76
72
|
raw_value = (value * 10).to_i
|
77
73
|
holding_registers[21_203 + ((zone_number - 1) * 9)] = raw_value
|
78
|
-
@heating_target_temperature = value
|
79
74
|
end
|
80
75
|
|
81
76
|
def cooling_target_temperature=(value)
|
@@ -83,7 +78,6 @@ module Aurora
|
|
83
78
|
|
84
79
|
raw_value = (value * 10).to_i
|
85
80
|
holding_registers[21_204 + ((zone_number - 1) * 9)] = raw_value
|
86
|
-
@cooling_target_temperature = value
|
87
81
|
end
|
88
82
|
end
|
89
83
|
end
|
data/lib/aurora/mock_abc.rb
CHANGED
@@ -4,7 +4,8 @@ module Aurora
|
|
4
4
|
class MockABC
|
5
5
|
attr_accessor :logger
|
6
6
|
|
7
|
-
def initialize(registers)
|
7
|
+
def initialize(registers, ignore_missing_registers: false)
|
8
|
+
@ignore_missing_registers = ignore_missing_registers
|
8
9
|
@registers = registers
|
9
10
|
end
|
10
11
|
|
@@ -59,6 +60,8 @@ module Aurora
|
|
59
60
|
private
|
60
61
|
|
61
62
|
def missing_register(idx)
|
63
|
+
raise ::ModBus::Errors::IllegalDataAddress unless @ignore_missing_registers
|
64
|
+
|
62
65
|
logger.warn("missing register #{idx}")
|
63
66
|
end
|
64
67
|
end
|
data/lib/aurora/registers.rb
CHANGED
@@ -60,6 +60,7 @@ module Aurora
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def to_int32(registers, idx)
|
63
|
+
Aurora&.logger&.warn("Missing register #{idx + 1}") unless registers[idx + 1]
|
63
64
|
(registers[idx] << 16) + registers[idx + 1]
|
64
65
|
end
|
65
66
|
|
@@ -229,6 +230,8 @@ module Aurora
|
|
229
230
|
0x08 => :blower,
|
230
231
|
0x10 => :eh1,
|
231
232
|
0x20 => :eh2,
|
233
|
+
# 0x40 => ??, # this turns on and off quite a bit during normal operation
|
234
|
+
# 0x80 => ??, # this turns on occasionally during normal operation; I've only seen it when aux heat is on
|
232
235
|
0x200 => :accessory,
|
233
236
|
0x400 => :lockout,
|
234
237
|
0x800 => :alarm
|
@@ -703,10 +706,11 @@ module Aurora
|
|
703
706
|
9 => "Compressor Minimum Run Time",
|
704
707
|
15 => "Blower Off Delay",
|
705
708
|
16 => "Line Voltage",
|
706
|
-
17 => "Aux/E Heat Stage", # this
|
707
|
-
#
|
708
|
-
|
709
|
-
|
709
|
+
17 => "Aux/E Heat Stage", # this is how long aux/eheat have been requested in seconds
|
710
|
+
# when in eheat mode (explicit on the thermostat), it will stage up to eh2 after 130s
|
711
|
+
# when in aux mode (thermostat set to heat; compressor at full capacity), it will stage up to eh2 after 310s
|
712
|
+
19 => "Cooling Liquid Line Temperature (FP1)",
|
713
|
+
20 => "Air Coil Temperature (FP2)",
|
710
714
|
21 => "Condensate", # >= 270 normal, otherwise fault
|
711
715
|
25 => "Last Fault Number", # high bit set if locked out
|
712
716
|
26 => "Last Lockout",
|
@@ -867,11 +871,11 @@ module Aurora
|
|
867
871
|
3225 => "VS Drive Details (Safemode 2)",
|
868
872
|
3226 => "VS Drive Details (Alarm 1)",
|
869
873
|
3227 => "VS Drive Details (Alarm 2)",
|
870
|
-
3327 => "VS Drive Temperature",
|
871
874
|
3322 => "VS Drive Discharge Pressure",
|
872
875
|
3323 => "VS Drive Suction Pressure",
|
873
876
|
3325 => "VS Drive Discharge Temperature",
|
874
877
|
3326 => "VS Drive Compressor Ambient Temperature",
|
878
|
+
3327 => "VS Drive Temperature",
|
875
879
|
3330 => "VS Drive Entering Water Temperature",
|
876
880
|
3331 => "VS Drive Line Voltage",
|
877
881
|
3332 => "VS Drive Thermo Power",
|
data/lib/aurora/thermostat.rb
CHANGED
@@ -15,9 +15,9 @@ module Aurora
|
|
15
15
|
:fan_intermittent_off
|
16
16
|
|
17
17
|
def registers_to_read
|
18
|
-
return [
|
18
|
+
return [] unless @abc.awl_thermostat?
|
19
19
|
|
20
|
-
[
|
20
|
+
[502, 745..746, 12_005..12_006]
|
21
21
|
end
|
22
22
|
|
23
23
|
def refresh(registers)
|
@@ -48,14 +48,12 @@ module Aurora
|
|
48
48
|
return unless (raw_value = HEATING_MODE.invert[value])
|
49
49
|
|
50
50
|
@abc.modbus_slave.holding_registers[12_606] = raw_value
|
51
|
-
@target_mode = value
|
52
51
|
end
|
53
52
|
|
54
53
|
def target_fan_mode=(value)
|
55
54
|
return unless (raw_value = FAN_MODE.invert[value])
|
56
55
|
|
57
56
|
@abc.modbus_slave.holding_registers[12_621] = raw_value
|
58
|
-
@target_fan_mode = value
|
59
57
|
end
|
60
58
|
|
61
59
|
def heating_target_temperature=(value)
|
@@ -63,7 +61,6 @@ module Aurora
|
|
63
61
|
|
64
62
|
raw_value = (value * 10).to_i
|
65
63
|
@abc.modbus_slave.holding_registers[12_619] = raw_value
|
66
|
-
@heating_target_temperature = value
|
67
64
|
end
|
68
65
|
|
69
66
|
def cooling_target_temperature=(value)
|
@@ -71,21 +68,18 @@ module Aurora
|
|
71
68
|
|
72
69
|
raw_value = (value * 10).to_i
|
73
70
|
@abc.modbus_slave.holding_registers[12_620] = raw_value
|
74
|
-
@cooling_target_temperature = value
|
75
71
|
end
|
76
72
|
|
77
73
|
def fan_intermittent_on=(value)
|
78
74
|
return unless value >= 0 && value <= 25 && (value % 5).zero?
|
79
75
|
|
80
76
|
holding_registers[12_622] = value
|
81
|
-
@fan_intermittent_on = value
|
82
77
|
end
|
83
78
|
|
84
79
|
def fan_intermittent_off=(value)
|
85
80
|
return unless value >= 0 && value <= 40 && (value % 5).zero?
|
86
81
|
|
87
82
|
holding_registers[12_623] = value
|
88
|
-
@fan_intermittent_off = value
|
89
83
|
end
|
90
84
|
end
|
91
85
|
end
|
data/lib/aurora/version.rb
CHANGED
data/lib/aurora.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:
|
4
|
+
version: 1.2.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: 2022-01
|
11
|
+
date: 2022-02-01 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
|