waterfurnace_aurora 0.8.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 288c8dbc14788d26473f14dcfaf388f75c8aee92c2f3b4d388bfa8326cfd2842
4
- data.tar.gz: c06f92936c81e402d08e01ae6b8c6c573acca46a85c9630914cb3c69f125a56a
3
+ metadata.gz: d9f0f7d0f0c846720df96f8889d1d5952ece7e0dbabea3431484f4efbff06f5a
4
+ data.tar.gz: e82bc4400c9543322debe51a21da1dea54d07a673f7302e5ec2a2910e8229714
5
5
  SHA512:
6
- metadata.gz: 5e64658afee912c8188af6d88bc98e208427b8dc4ef2ce1ea6ff1efcaca15ea2042ed4eef08ccfd764ec59ce0bb82013b0abd82173ec00f9ec61cbde07a66634
7
- data.tar.gz: 6deff29644f83c329f1727d0a568c87536618ae63c7a27e58e4054eff187496c6f04bf3b63e2c35e649b2a0eb5b6395d81450a68b0096d1cacee9137c2f53c31
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("Use `known` to fetch all identified registers. Use `valid` to fetch all registers that will respond.")
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") { debug_modbus = true }
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($stdout)
47
- modbus_slave.logger.level = debug_modbus ? :debug : :warn
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
 
@@ -90,29 +90,33 @@ class MQTTBridge
90
90
  loop do
91
91
  begin
92
92
  @mutex.synchronize do
93
- @abc.refresh
94
-
95
- components = { @homie_abc => @abc,
96
- @compressor => @abc.compressor,
97
- @blower => @abc.blower,
98
- @pump => @abc.pump,
99
- @dhw => @abc.dhw,
100
- @humidistat => @abc.humidistat }.compact
101
- @abc.zones.each_with_index do |z, idx|
102
- homie_zone = @homie["zone#{idx + 1}"]
103
- components[homie_zone] = z
104
- end
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
- components.each do |(node, object)|
107
- node.each do |property|
108
- property.value = object.public_send(property.id.tr("-", "_"))
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
- @abc.faults.each_with_index do |fault_count, i|
113
- next if fault_count == 0xffff
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
- @faults["e#{i + 1}"].value = fault_count
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 cooling eh1 eh2 emergency waiting]
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, property|
193
- @mutex.synchronize { property.value = @abc.line_voltage = value }
232
+ unit: "V") do |value|
233
+ @mutex.synchronize { @abc.line_voltage = value }
194
234
  end
195
- node.property("fp1",
196
- "FP1 Sensor",
235
+ node.property("air-coil-temperature",
236
+ "Air Coil Temperature (FP2)",
197
237
  :float,
198
- @abc.fp1,
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
- node.property("fp2",
204
- "FP2 Sensor",
205
- :float,
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.public_send(component),
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, property|
298
- @mutex.synchronize { property.value = @abc.blower.public_send("#{field}=", value) }
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, property|
344
- @mutex.synchronize { property.value = @abc.pump.manual_control = value }
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, property|
353
- @mutex.synchronize { property.value = @abc.pump.minimum_speed = value }
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, property|
362
- @mutex.synchronize { property.value = @abc.pump.maximum_speed = value }
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, property|
373
- @mutex.synchronize { property.value = @abc.pump.speed = value }
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, property|
384
- @mutex.synchronize { property.value = @abc.dhw.enabled = value }
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, property|
405
- @mutex.synchronize { property.value = @abc.dhw.set_point = value }
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, property|
422
- @mutex.synchronize { property.value = @abc.humidistat.humidifier_mode = value.to_sym }
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, property|
430
- @mutex.synchronize { property.value = @abc.humidistat.humidification_target = value }
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, property|
454
- @mutex.synchronize { property.value = @abc.humidistat.dehumidifier_mode = value.to_sym }
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, property|
462
- @mutex.synchronize { property.value = @abc.humidistat.dehumidification_target = value }
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, property|
524
- @mutex.synchronize { property.value = zone.target_mode = value.to_sym }
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, property|
531
- @mutex.synchronize { property.value = zone.target_fan_mode = value.to_sym }
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, property|
540
- @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
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, property|
549
- @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
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, property|
591
- @mutex.synchronize { property.value = zone.heating_target_temperature = value }
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, property|
598
- @mutex.synchronize { property.value = zone.cooling_target_temperature = value }
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
 
@@ -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
- return Aurora::MockABC.new(YAML.load_file(uri.path)) if File.file?(uri.path)
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, ::ModBus::Errors::IllegalFunction
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
- :fp1,
106
- :fp2,
142
+ :air_coil_temperature,
107
143
  :line_voltage,
108
- :aux_heat_watts,
109
- :total_watts
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
- @registers_to_read = [6, 19..20, 25, 30, 112, 344, 567, 1104, 1110..1111, 1114, 1150..1153, 1165]
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[567]
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
- @fp1 = registers[19]
190
- @fp2 = registers[20]
191
- @locked_out = registers[25] & 0x8000
192
- @error = registers[25] & 0x7fff
193
- @derated = (41..46).cover?(@error)
194
- @safe_mode = [47, 48, 49, 72, 74].include?(@error)
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
- @aux_heat_watts = registers[1151]
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) ? :cooling : :heating
205
- elsif outputs.include?(:eh2)
206
- outputs.include?(:rv) ? :eh2 : :emergency
207
- elsif outputs.include?(:eh1)
208
- outputs.include?(:rv) ? :eh1 : :emergency
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
@@ -36,7 +36,7 @@ module Aurora
36
36
 
37
37
  def refresh(registers)
38
38
  outputs = registers[30]
39
- @speed = if outputs.include?(:eh1)
39
+ @speed = if outputs.include?(:eh1) || outputs.include?(:eh2)
40
40
  4
41
41
  elsif outputs.include?(:cc2)
42
42
  3
@@ -6,6 +6,10 @@ module Aurora
6
6
  @abc = abc
7
7
  end
8
8
 
9
+ def registers_to_read
10
+ []
11
+ end
12
+
9
13
  def inspect
10
14
  "#<Aurora::#{self.class.name} #{(instance_variables - [:@abc]).map do |iv|
11
15
  "#{iv}=#{instance_variable_get(iv).inspect}"
@@ -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
- if abc.energy_monitoring?
25
- [1146..1147]
26
- else
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 :ambient_temperature, :iz2_desired_speed
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, 3326]
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
@@ -27,7 +27,6 @@ module Aurora
27
27
 
28
28
  raw_value = (value * 10).to_i
29
29
  holding_registers[401] = raw_value
30
- @set_point = value
31
30
  end
32
31
  end
33
32
  end
@@ -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
@@ -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
@@ -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
@@ -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 has some complicated condition based on
707
- # current inputs and outputs on if it should have a value (310 - v) or (130 - v), or be 0
708
- 19 => "FP1 (Cooling Liquid Line) Temperature",
709
- 20 => "FP2",
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",
@@ -15,9 +15,9 @@ module Aurora
15
15
  :fan_intermittent_off
16
16
 
17
17
  def registers_to_read
18
- return [31] unless @abc.awl_thermostat?
18
+ return [] unless @abc.awl_thermostat?
19
19
 
20
- [31, 502, 745..746, 12_005..12_006]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aurora
4
- VERSION = "0.8.0"
4
+ VERSION = "1.2.0"
5
5
  end
data/lib/aurora.rb CHANGED
@@ -15,4 +15,7 @@ ModBus::Client::Slave.prepend(Aurora::ModBus::Slave)
15
15
  ModBus::RTUSlave.prepend(Aurora::ModBus::RTU)
16
16
 
17
17
  module Aurora
18
+ class << self
19
+ attr_accessor :logger
20
+ end
18
21
  end
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.8.0
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-27 00:00:00.000000000 Z
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