waterfurnace_aurora 0.3.12 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aurora/component"
4
+
5
+ module Aurora
6
+ module Blower
7
+ class GenericBlower < Component
8
+ attr_reader :type, :watts
9
+
10
+ def initialize(abc, type)
11
+ super(abc)
12
+ @type = type
13
+ end
14
+
15
+ def registers_to_read
16
+ if abc.energy_monitoring?
17
+ [1148..1149]
18
+ else
19
+ []
20
+ end
21
+ end
22
+
23
+ def refresh(registers)
24
+ @watts = registers[1148] if abc.energy_monitoring?
25
+ end
26
+ end
27
+
28
+ class PSC < GenericBlower
29
+ attr_reader :running
30
+ alias running? running
31
+
32
+ def refresh(registers)
33
+ @running = registers[30].include?(:g)
34
+ end
35
+ end
36
+
37
+ class FiveSpeed < GenericBlower
38
+ attr_reader :speed
39
+
40
+ def speed_range
41
+ 0..4
42
+ end
43
+
44
+ def refresh(registers)
45
+ outputs = registers[30]
46
+ @speed = if outputs.include?(:eh1)
47
+ 4
48
+ elsif outputs.include?(:cc2)
49
+ 3
50
+ elsif outputs.include?(:cc)
51
+ 2
52
+ elsif outputs.include?(:g)
53
+ 1
54
+ else
55
+ 0
56
+ end
57
+ end
58
+ end
59
+
60
+ class ECM < GenericBlower
61
+ attr_reader :speed, :blower_only_speed, :low_compressor_speed, :high_compressor_speed, :aux_heat_speed,
62
+ :iz2_desired_speed
63
+
64
+ def speed_range
65
+ 0..12
66
+ end
67
+
68
+ def registers_to_read
69
+ result = super + [340..342, 344, 347]
70
+ result << 565 if abc.iz2?
71
+ result
72
+ end
73
+
74
+ def refresh(registers)
75
+ super
76
+
77
+ @speed = registers[344]
78
+ @blower_only_speed = registers[340]
79
+ @low_compressor_speed = registers[341]
80
+ @high_compressor_speed = registers[342]
81
+ @aux_heat_speed = registers[347]
82
+ @iz2_desired_speed = registers[565] if abc.iz2?
83
+ end
84
+
85
+ { blower_only: 340,
86
+ low_compressor: 341,
87
+ high_compressor: 342,
88
+ aux_heat: 347 }.each do |(setting, register)|
89
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
90
+ def #{setting}_speed=(value)
91
+ raise ArgumentError unless (1..12).include?(value)
92
+
93
+ holding_registers[#{register}] = value
94
+ end
95
+ RUBY
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aurora
4
+ class Component
5
+ def initialize(abc)
6
+ @abc = abc
7
+ end
8
+
9
+ private
10
+
11
+ attr_reader :abc
12
+
13
+ def holding_registers
14
+ abc.modbus_slave.holding_registers
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aurora
4
+ class MockABC
5
+ attr_accessor :logger
6
+
7
+ def initialize(registers)
8
+ @registers = registers
9
+ end
10
+
11
+ def read_retry_timeout=(_); end
12
+
13
+ def read_retries=(_); end
14
+
15
+ def holding_registers
16
+ self
17
+ end
18
+
19
+ def [](*register)
20
+ if register.length == 1
21
+ case register.first
22
+ when Integer
23
+ @registers[register.first]
24
+ when Range
25
+ @registers.values_at(*register.first.to_a)
26
+ else
27
+ raise ArgumentError, "Not implemented yet #{register.inspect}"
28
+ end
29
+ else
30
+ read_multiple_holding_registers(*register)
31
+ end
32
+ end
33
+
34
+ def read_multiple_holding_registers(*queries)
35
+ result = {}
36
+ queries.each do |query|
37
+ Array(query).each do |i|
38
+ result[i] = @registers[i]
39
+ end
40
+ end
41
+ result
42
+ end
43
+
44
+ def write_holding_register(addr, value)
45
+ @registers[addr] = value
46
+ end
47
+ end
48
+ end
@@ -59,69 +59,145 @@ module Aurora
59
59
  result
60
60
  end
61
61
 
62
+ def to_int32(registers, idx)
63
+ (registers[idx] << 16) + registers[idx + 1]
64
+ end
65
+
62
66
  def to_string(registers, idx, length)
63
67
  (idx...(idx + length)).map do |i|
68
+ raise ArgumentError, "Missing register #{i} for string starting at #{idx}" unless registers[i]
69
+
64
70
  (registers[i] >> 8).chr + (registers[i] & 0xff).chr
65
71
  end.join.sub(/[ \0]+$/, "")
66
72
  end
67
73
 
68
74
  FAULTS = {
69
- 1 => "Input Flt Limit",
70
- 2 => "High Pressure",
71
- 3 => "Low Pressure",
72
- 4 => "FP2",
73
- 5 => "FP1",
74
- 7 => "Condensate Limit",
75
- 8 => "Over/Under Voltage",
75
+ # ABC/AXB Basic Faults
76
+ 1 => "Input Error", # Tstat input error. Autoreset upon condition removal.
77
+ 2 => "High Pressure", # HP switch has tripped (>600 psi)
78
+ 3 => "Low Pressure", # Low Pressure Switch has tripped (<40 psi for 30 continous sec.)
79
+ 4 => "Freeze Detect FP2", # Freeze protection sensor has tripped (<15 or 30 degF for 30 continuous sec.)
80
+ 5 => "Freeze Detect FP1", # Freeze protection sensor has tripped (<15 or 30 degF for 30 continuous sec.)
81
+ 7 => "Condensate Overflow", # Condensate switch has shown continuity for 30 continuous sec.
82
+ 8 => "Over/Under Voltage", # Instantaneous Voltage is out of range. **Controls shut down until resolved.
76
83
  9 => "AirF/RPM",
77
- 10 => "CompMon",
78
- 11 => "FP1/2 Snr Limit",
79
- 12 => "RefPerfrm Limit",
80
- 13 => "NCrtAxbSr Limit",
81
- 14 => "CrtAxbSnr Limit",
82
- 15 => "HW Limit",
83
- 16 => "VSPumpFlt Limit",
84
- 17 => "CommTStat Limit",
85
- 18 => "NCritComm Limit",
86
- 19 => "Crit Comm Limit",
87
- 21 => "Low Loop Pressure",
88
- 22 => "ComEcmErr Limit",
89
- 23 => "HAGenAlrm1 Limit",
90
- 24 => "HAGenAlrm2 Limit",
91
- 25 => "AxbEevErr Limit",
92
- 41 => "High Drive Temp Limit",
93
- 42 => "High Discharge Temp Limit",
94
- 43 => "Low Suction Pressure Limit",
95
- 44 => "Low Con Pressure Limit",
96
- 45 => "High Con Pressure Limit",
97
- 46 => "Out Power Limit",
98
- 47 => "EevIDComm Limit",
99
- 48 => "EevODComm Limit",
100
- 49 => "CabTmpSnr Limit",
101
- 51 => "Discharge Temp Sensor Limit",
102
- 52 => "Suction Presure Sensor Limit",
103
- 53 => "Con Pressure Sensor Limit",
104
- 54 => "Low Supply Voltage Limit",
105
- 55 => "OutEnvelp Limit",
106
- 56 => "Suction Pressure Sensor Limit",
107
- 57 => "Drive Over/Under Voltage Limit",
108
- 58 => "High Drive Temp Limit",
109
- 59 => "Internal Drive Error Limit",
110
- 61 => "MultSafm",
111
- 71 => "ChrgLoss",
112
- 72 => "Suction Temp Sensor Limit",
113
- 73 => "Leaving Air Temp Sensor Limit",
114
- 74 => "Maximum Operating Pressure Limit",
115
- 75 => "Charge Loss",
116
- 76 => "Suction Temperatur Sensor Limit",
117
- 77 => "Leaving Air Temperature Sensor Limit",
118
- 78 => "Maximum Operating Pressure Limit"
84
+ 10 => "Compressor Monitor", # Open Crkt, Run, Start or welded cont
85
+ 11 => "FP1/2 Sensor Error",
86
+ 12 => "RefPerfrm Error",
87
+ # Miscellaneous
88
+ 13 => "Non-Critical AXB Sensor Error", # Any Other Sensor Error
89
+ 14 => "Critical AXB Sensor Error", # Sensor Err for EEV or HW
90
+ 15 => "Hot Water Limit", # HW over limit or logic lockout. HW pump deactivated.
91
+ 16 => "VS Pump Error", # Alert is read from PWM feedback.
92
+ 17 => "Communicating Thermostat Error",
93
+ 18 => "Non-Critical Communications Error", # Any non-critical com error
94
+ 19 => "Critical Communications Error", # Any critical com error. Auto reset upon condition removal
95
+ 21 => "Low Loop Pressure", # Loop pressure is below 3 psi for more than 3 minutes
96
+ 22 => "Communicating ECM Error",
97
+ 23 => "HA Alarm 1", # Closed contact input is present on Dig 2 input - Text is configurable.
98
+ 24 => "HA Alarm 2", # Closed contact input is present on Dig 3 input - Text is configurable.
99
+ 25 => "AxbEev Error",
100
+ # VS Drive
101
+ 41 => "High Drive Temp", # Drive Temp has reached critical High Temp (>239 ̊F/115 ̊C)
102
+ 42 => "High Discharge Temp", # Discharge temperature has reached critical high temp (> 280 ̊F/138 ̊C)
103
+ 43 => "Low Suction Pressure", # Suction Pressure is critically low (< 28 psig)
104
+ 44 => "Low Condensing Pressure", # Condensing pressure is critically low (< 119 psig)
105
+ 45 => "High Condensing Pressure", # Condensing pressure is critically high (> 654 psig)
106
+ 46 => "Output Power Limit", # Supply Voltage is <208V or Max Pwr is reached due to high pressure
107
+ 47 => "EEV ID Comm Error", # Com with EEV is interupted EEV has gone independent mode
108
+ 48 => "EEV OD Comm Error", # Com with EEV is interupted EEV has gone independent mode
109
+ 49 => "Cabinet Temperature Sensor", # Ambient Temperature (Tamb) is <-76 or > 212 F and out of range or invalid
110
+ 51 => "Discharge Temp Sensor", # Discharge Sensor (Sd) is > 280 F or invalid (-76 to 392 F)
111
+ 52 => "Suction Presure Sensor", # Suction Pressure (P0) is invalid (0 to 232 psi)
112
+ 53 => "Condensing Pressure Sensor", # Low condensing pressure (PD) or invalid (0 to 870 psi) Retry 10x.
113
+ 54 => "Low Supply Voltage", # Supply Voltage is <180 V (190V to reset) or powered off/on too quickly (<30 sec.).
114
+ 55 => "Out of Envelope", # Comp Operating out of envelope (P0) more than 90 sec. Retry 10x.
115
+ 56 => "Drive Over Currnet", # 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
+ 57 => "Drive Over/Under Voltage", # DC Link Voltage to compressor is >450vdc or at minimum voltage (<185vdc).
117
+ 58 => "High Drive Temp", # Drive Temp has reached critical High Temp >239 F
118
+ 59 => "Internal Drive Error", # The MOC has encountered an internal fault or an internal error. Probably fatal.
119
+ 61 => "Multiple Safe Mode", # More than one SafeMode condition is present requiring lockout
120
+ # EEV2
121
+ 71 => "Loss of Charge", # High superheat and high EEV opening % for a long time will trigger a loss of charge fault
122
+ 72 => "Suction Temperature Sensor", # Suction Temperature Sensor is invalid (-76 to 392 F)
123
+ 73 => "Leaving Air Temperature Sensor", # Leaving Air Temperature Sensor is invalid (-76 to 392 F)
124
+ 74 => "Maximum Operating Pressure", # Suction pressure has exceeded that maximum operating level for 90 sec.
125
+ 99 => "System Reset"
126
+ }.freeze
127
+
128
+ SMARTGRID_ACTION = {
129
+ 0 => :none,
130
+ 1 => :unoccupied_set_points,
131
+ 2 => :load_shed,
132
+ 3 => :capacity_limiting,
133
+ 4 => :off_time
134
+ }.freeze
135
+
136
+ HA_ALARM = {
137
+ 0 => :none,
138
+ 1 => :general,
139
+ 2 => :security,
140
+ 3 => :sump,
141
+ 4 => :carbon_monoxide,
142
+ 5 => :dirty_filter
143
+ }.freeze
144
+
145
+ BRINE_TYPE = Hash.new("Water").merge!(
146
+ 485 => "Antifreeze"
147
+ ).freeze
148
+
149
+ FLOW_METER_TYPE = Hash.new("Other").merge!(
150
+ 0 => "None",
151
+ 1 => '3/4"',
152
+ 2 => '1"'
153
+ ).freeze
154
+
155
+ PUMP_TYPE = Hash.new("Other").merge!(
156
+ 0 => "Open Loop",
157
+ 1 => "FC1",
158
+ 2 => "FC2",
159
+ 3 => "VS Pump",
160
+ 4 => "VS Pump + 26-99",
161
+ 5 => "VS Pump + UPS26-99",
162
+ 6 => "FC1_GLNP",
163
+ 7 => "FC2_GLNP"
164
+ ).freeze
165
+
166
+ PHASE_TYPE = Hash.new("Other").merge!(
167
+ 0 => "Single",
168
+ 1 => "Three"
169
+ ).freeze
170
+
171
+ BLOWER_TYPE = Hash.new("Other").merge!(
172
+ 0 => "PSC",
173
+ 1 => "ECM 208/230",
174
+ 2 => "ECM 265/277",
175
+ 3 => "5 Speed ECM 460"
176
+ ).freeze
177
+
178
+ ENERGY_MONITOR_TYPE = Hash.new("Other").merge!(
179
+ 0 => "None",
180
+ 1 => "Compressor Monitor",
181
+ 2 => "Energy Monitor"
182
+ ).freeze
183
+
184
+ VS_FAULTS = {
185
+ "Under-Voltage Warning" => (71..77),
186
+ "RPM Sensor Signal Fault" => (78..82),
187
+ "Under-Voltage Stop" => (83..87),
188
+ "Rotor Locked" => (88..92),
189
+ "Standby" => (93..)
119
190
  }.freeze
120
191
 
192
+ def vs_fault(value)
193
+ name = VS_FAULTS.find { |(_, range)| range.include?(value) }&.first
194
+ name ? "#{value} #{name}" : value.to_s
195
+ end
196
+
121
197
  AR_SETTINGS = {
122
198
  0 => "Cycle with Compressor",
123
- 1 => "Cycle with Thermostat Humidification Call",
124
- 2 => "Slow Opening Water Valve",
199
+ 1 => "Slow Opening Water Valve",
200
+ 2 => "Cycle with Thermostat Humidification Call",
125
201
  3 => "Cycle with Blower"
126
202
  }.freeze
127
203
 
@@ -132,23 +208,18 @@ module Aurora
132
208
  fp1: value & 0x01 == 0x01 ? "30ºF" : "15ºF",
133
209
  fp2: value & 0x02 == 0x02 ? "30ºF" : "15ºF",
134
210
  rv: value & 0x04 == 0x04 ? "O" : "B",
135
- ar: AR_SETTINGS[(value >> 3) & 0x7],
211
+ ar: AR_SETTINGS[(value >> 3) & 0x3],
136
212
  cc: value & 0x20 == 0x20 ? "Single Stage" : "Dual Stage",
137
213
  lo: value & 0x40 == 0x40 ? "Continouous" : "Pulse",
138
- dh_rh: value & 0x80 == 0x80 ? "Dehumdifier On" : "Reheat On"
214
+ dh_rh: value & 0x80 == 0x80 ? "Dehumidifier On" : "Reheat On"
139
215
  }
140
216
  end
141
217
 
142
218
  COMPONENT_STATUS = {
143
219
  1 => :active,
144
220
  2 => :added,
145
- 3 => :removed
146
- }.freeze
147
-
148
- VS_PUMP_CONTROL = {
149
- 0x7fff => :off,
150
- 40 => :min,
151
- 100 => :max
221
+ 3 => :removed,
222
+ 0xffff => :missing
152
223
  }.freeze
153
224
 
154
225
  SYSTEM_OUTPUTS = {
@@ -164,14 +235,14 @@ module Aurora
164
235
  }.freeze
165
236
 
166
237
  SYSTEM_INPUTS = {
167
- 0x01 => "Y1",
168
- 0x02 => "Y2",
169
- 0x04 => "W",
170
- 0x08 => "O",
171
- 0x10 => "G",
172
- 0x20 => "Dehumidifer",
173
- 0x40 => "Emergency Shutdown",
174
- 0x200 => "Load Shed"
238
+ 0x01 => :y1,
239
+ 0x02 => :y2,
240
+ 0x04 => :w,
241
+ 0x08 => :o,
242
+ 0x10 => :g,
243
+ 0x20 => :dh_rh,
244
+ 0x40 => :emergency_shutdown,
245
+ 0x200 => :load_shed
175
246
  }.freeze
176
247
 
177
248
  def status(value)
@@ -179,9 +250,10 @@ module Aurora
179
250
  lps: value & 0x80 == 0x80 ? :closed : :open,
180
251
  hps: value & 0x100 == 0x100 ? :closed : :open
181
252
  }
182
- result[:load_shed] = true if value & 0x0200 == 0x0200
183
- result[:emergency_shutdown] = true if value & 0x0040 == 0x0040
184
- leftover = value & ~0x03c0
253
+ SYSTEM_INPUTS.each do |(i, name)|
254
+ result[name] = true if value & i == i
255
+ end
256
+ leftover = value & ~0x03ff
185
257
  result[:unknown] = format("0x%04x", leftover) unless leftover.zero?
186
258
  result
187
259
  end
@@ -228,13 +300,36 @@ module Aurora
228
300
 
229
301
  }.freeze
230
302
 
231
- AXB_INPUTS = {
232
- }.freeze
303
+ def axb_inputs(value)
304
+ result = {}
305
+ result["Smart Grid"] = value & 0x001 == 0x001
306
+ result["Home Automation 1"] = value & 0x002 == 0x002
307
+ result["Home Automation 2"] = value & 0x004 == 0x004
308
+ result["Pump Slave"] = value & 0x008 == 0x008
309
+
310
+ result[:mb_address] = value & 0x010 == 0x010 ? 3 : 4
311
+ result[:sw1_2] = value & 0x020 == 0x020 # future use # rubocop:disable Naming/VariableNumber
312
+ result[:sw1_3] = value & 0x040 == 0x040 # future use # rubocop:disable Naming/VariableNumber
313
+ result[:cycle_with] = if value & 0x080 == 0x080 && value & 0x100 == 0x100
314
+ "Blower"
315
+ elsif value & 0x100 == 0x100
316
+ "Low Capacity Compressor"
317
+ elsif value & 0x080 == 0x080
318
+ "High Capacity Compressor"
319
+ else
320
+ "Thermostat Dehumidifier"
321
+ end
322
+ leftover = value & ~0x1ff
323
+ result[:unknown] = format("0x%04x", leftover) unless leftover.zero?
324
+ result
325
+ end
233
326
 
234
327
  AXB_OUTPUTS = {
235
- 0x10 => "Accessory 2",
236
- 0x02 => "Loop Pump",
237
- 0x01 => "DHW"
328
+ 0x01 => :dhw,
329
+ 0x02 => :loop_pump,
330
+ 0x04 => :diverting_valve,
331
+ 0x08 => :dehumidifer_reheat,
332
+ 0x10 => :accessory2
238
333
  }.freeze
239
334
 
240
335
  HEATING_MODE = {
@@ -279,6 +374,33 @@ module Aurora
279
374
  0x7 => :unknown7
280
375
  }.freeze
281
376
 
377
+ def manual_operation(value)
378
+ return :off if value == 0x7fff
379
+
380
+ result = {
381
+ mode: value & 0x100 == 0x100 ? :cooling : :heating
382
+ }
383
+ result[:aux_heat] = true if value & 0x200 == 0x200
384
+ result[:compressor_speed] = value & 0xf
385
+ result[:blower_speed] = value & 0xf0
386
+ result[:blower_speed] = :with_compressor if value & 0xf0 == 0xf0
387
+ leftover = value & ~0x03ff
388
+ result[:unknown] = format("0x%04x", leftover) unless leftover.zero?
389
+ result
390
+ end
391
+
392
+ def vs_manual_control(value)
393
+ return :off if value == 0x7fff
394
+
395
+ value
396
+ end
397
+
398
+ def thermostat_override(value)
399
+ return [:off] if value == 0x7fff
400
+
401
+ from_bitmask(value, SYSTEM_INPUTS)
402
+ end
403
+
282
404
  def iz2_demand(value)
283
405
  {
284
406
  fan_demand: value >> 8,
@@ -286,6 +408,18 @@ module Aurora
286
408
  }
287
409
  end
288
410
 
411
+ def iz2_fan_desired(value)
412
+ case value
413
+ when 1 then 25
414
+ when 2 then 40
415
+ when 3 then 55
416
+ when 4 then 70
417
+ when 5 then 85
418
+ when 6 then 100
419
+ else value
420
+ end
421
+ end
422
+
289
423
  def zone_configuration1(value)
290
424
  fan = if value & 0x80 == 0x80
291
425
  :continuous
@@ -340,10 +474,11 @@ module Aurora
340
474
  # intermittent off time allowed: 5, 10, 15, 20, 25, 30, 35, 40
341
475
 
342
476
  REGISTER_CONVERTERS = {
343
- TO_HUNDREDTHS => [2, 3, 801, 807, 813, 816, 817, 819, 820, 825, 828],
477
+ TO_HUNDREDTHS => [2, 3, 417, 418, 801, 804, 807, 813, 816, 817, 819, 820, 825, 828],
344
478
  method(:dipswitch_settings) => [4, 33],
345
479
  TO_TENTHS => [19, 20, 401, 419, 501, 502, 567, 740, 745, 746, 747, 900,
346
- 1105, 1106, 1107, 1108, 1110, 1111, 1114, 1117, 1134, 1136,
480
+ 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1119, 1124, 1125, 1134,
481
+ 3322, 3323, 3325, 3326, 3327, 3330, 3522, 3903, 3905, 3906,
347
482
  12_619, 12_620,
348
483
  21_203, 21_204,
349
484
  21_212, 21_213,
@@ -357,21 +492,35 @@ module Aurora
357
492
  ->(v) { from_bitmask(v, SYSTEM_OUTPUTS) } => [27, 30],
358
493
  ->(v) { from_bitmask(v, SYSTEM_INPUTS) } => [28],
359
494
  method(:status) => [31],
495
+ method(:thermostat_override) => [32],
496
+ ->(v) { !v.zero? } => [45, 362, 400],
360
497
  ->(registers, idx) { to_string(registers, idx, 4) } => [88],
361
498
  ->(registers, idx) { to_string(registers, idx, 12) } => [92],
362
499
  ->(registers, idx) { to_string(registers, idx, 5) } => [105],
363
- ->(v) { from_bitmask(v, VS_DRIVE_DERATE) } => [214],
364
- ->(v) { from_bitmask(v, VS_SAFE_MODE) } => [216],
365
- ->(v) { from_bitmask(v, VS_ALARM1) } => [217],
366
- ->(v) { from_bitmask(v, VS_ALARM2) } => [218],
367
- ->(v) { from_bitmask(v, VS_EEV2) } => [280],
368
- ->(v) { VS_PUMP_CONTROL[v] } => [323],
500
+ ->(v) { from_bitmask(v, VS_DRIVE_DERATE) } => [214, 3223],
501
+ ->(v) { from_bitmask(v, VS_SAFE_MODE) } => [216, 3225],
502
+ ->(v) { from_bitmask(v, VS_ALARM1) } => [217, 3226],
503
+ ->(v) { from_bitmask(v, VS_ALARM2) } => [218, 3227],
504
+ ->(v) { from_bitmask(v, VS_EEV2) } => [280, 3804],
505
+ method(:vs_manual_control) => [323],
369
506
  NEGATABLE => [346, 1146],
370
- ->(v) { !v.zero? } => [400],
371
- ->(v) { COMPONENT_STATUS[v] } => [800, 806, 812, 815, 818, 824, 827],
372
- ->(v) { from_bitmask(v, AXB_INPUTS) } => [1103],
507
+ ->(v) { BRINE_TYPE[v] } => [402],
508
+ ->(v) { FLOW_METER_TYPE[v] } => [403],
509
+ ->(v) { BLOWER_TYPE[v] } => [404],
510
+ ->(v) { v.zero? ? :closed : :open } => [405, 408, 410],
511
+ ->(v) { SMARTGRID_ACTION[v] } => [406],
512
+ ->(v) { HA_ALARM[v] } => [409, 411],
513
+ ->(v) { ENERGY_MONITOR_TYPE[v] } => [412],
514
+ ->(v) { PUMP_TYPE[v] } => [413],
515
+ ->(v) { PHASE_TYPE[v] } => [416],
516
+ method(:iz2_fan_desired) => [565],
517
+ ->(registers, idx) { to_string(registers, idx, 8) } => [710],
518
+ ->(v) { COMPONENT_STATUS[v] } => [800, 803, 806, 812, 815, 818, 824, 827],
519
+ method(:axb_inputs) => [1103],
373
520
  ->(v) { from_bitmask(v, AXB_OUTPUTS) } => [1104],
374
- ->(v) { TO_TENTHS.call(NEGATABLE.call(v)) } => [1136],
521
+ ->(v) { TO_TENTHS.call(NEGATABLE.call(v)) } => [1135, 1136],
522
+ method(:to_int32) => [1146, 1148, 1150, 1152, 1154, 1156, 1164, 3422, 3424],
523
+ method(:manual_operation) => [3002],
375
524
  ->(v) { HEATING_MODE[v] } => [12_606, 21_202, 21_211, 21_220, 21_229, 21_238, 21_247],
376
525
  ->(v) { FAN_MODE[v] } => [12_621, 21_205, 21_214, 21_223, 21_232, 21_241, 21_250],
377
526
  ->(v) { from_bitmask(v, HUMIDIFIER_SETTINGS) } => [31_109],
@@ -389,9 +538,11 @@ module Aurora
389
538
  }.freeze
390
539
 
391
540
  REGISTER_FORMATS = {
392
- "%ds" => [1, 6, 9, 15, 84, 85],
393
- "%dV" => [16, 112],
394
- "%0.1fºF" => [19, 20, 401, 501, 502, 567, 740, 745, 746, 747, 900, 1110, 1111, 1114, 1134, 1136,
541
+ "%ds" => [1, 6, 9, 15, 84, 85, 110],
542
+ "%dV" => [16, 112, 3331, 3424, 3523],
543
+ "%0.1fºF" => [19, 20, 401, 501, 502, 567, 740, 745, 746, 747, 900,
544
+ 1109, 1110, 1111, 1112, 1113, 1114, 1124, 1125, 1134, 1135, 1136,
545
+ 3325, 3326, 3327, 3330, 3522, 3903, 3905, 3906,
395
546
  12_619, 12_620,
396
547
  21_203, 21_204,
397
548
  21_212, 21_213,
@@ -402,15 +553,17 @@ module Aurora
402
553
  31_003,
403
554
  31_007, 31_010, 31_013, 31_016, 31_019, 31_022],
404
555
  "E%d" => [25, 26],
405
- "%d%%" => [282, 321, 322, 346, 565, 741],
406
- "%0.1f psi" => [419],
556
+ "%d%%" => [282, 321, 322, 325, 346, 565, 741, 1126, 3332, 3524, 3808],
557
+ "%0.1f psi" => [419, 1115, 1116, 1119, 3322, 3323],
407
558
  "%0.1fA" => [1105, 1106, 1107, 1108],
408
559
  "%0.1fgpm" => [1117],
409
- "%dW" => [1147, 1149, 1151, 1153, 1165],
410
- "%dBtuh" => [1157]
560
+ "%dW" => [1146, 1148, 1150, 1152, 1164, 3422],
561
+ "%dBtuh" => [1154, 1156]
411
562
  }.freeze
412
563
 
413
- def ignore(range)
564
+ def ignore(*range)
565
+ range = range.first if range.length == 1
566
+ range = [range] if range.is_a?(Integer)
414
567
  range.zip(Array.new(range.count)).to_h
415
568
  end
416
569
 
@@ -530,26 +683,32 @@ module Aurora
530
683
  ].freeze
531
684
 
532
685
  REGISTER_NAMES = {
686
+ 0 => "Test Mode Flag", # 0x100 for enabled; this might have other flags
533
687
  1 => "Random Start Delay",
534
688
  2 => "ABC Program Version",
535
689
  3 => "??? Version?",
536
690
  4 => "DIP Switch Override",
537
691
  6 => "Compressor Anti-Short Cycle Delay",
538
- 8 => "Unit Type?",
692
+ 8 => "ABC Program Revision",
539
693
  9 => "Compressor Minimum Run Time",
540
694
  15 => "Blower Off Delay",
541
695
  16 => "Line Voltage",
542
- 19 => "FP1",
696
+ 17 => "Aux/E Heat Stage", # this has some complicated condition based on
697
+ # current inputs and outputs on if it should have a value (310 - v) or (130 - v), or be 0
698
+ 19 => "FP1 (Cooling Liquid Line) Temperature",
543
699
  20 => "FP2",
544
700
  21 => "Condensate", # >= 270 normal, otherwise fault
545
- 25 => "Last Fault Number",
701
+ 25 => "Last Fault Number", # high bit set if locked out
546
702
  26 => "Last Lockout",
547
703
  27 => "System Outputs (At Last Lockout)",
548
704
  28 => "System Inputs (At Last Lockout)",
549
705
  30 => "System Outputs",
550
706
  31 => "Status",
707
+ 32 => "Thermostat Input Override",
551
708
  33 => "DIP Switch Status",
552
709
  36 => "ABC Board Rev",
710
+ 45 => "Test Mode (write)", # 1 to enable
711
+ 47 => "Clear Fault History", # 0x5555 to clear
553
712
  50 => "ECM Speed Low (== 5)",
554
713
  51 => "ECM Speed Med (== 5)",
555
714
  52 => "ECM Speed High (== 5)",
@@ -559,7 +718,8 @@ module Aurora
559
718
  88 => "ABC Program",
560
719
  92 => "Model Number",
561
720
  105 => "Serial Number",
562
- 112 => "Setup Line Voltage",
721
+ 110 => "Reheat Delay",
722
+ 112 => "Line Voltage Setting",
563
723
  201 => "Discharge Pressure", # I can't figure out how this number is represented;
564
724
  203 => "Suction Pressure",
565
725
  205 => "Discharge Temperature",
@@ -580,7 +740,9 @@ module Aurora
580
740
  284 => "Saturated Suction Temperature", ## ?? data format
581
741
  321 => "VS Pump Min",
582
742
  322 => "VS Pump Max",
583
- 323 => "VS Pump Control",
743
+ 323 => "VS Pump Speed Manual Control",
744
+ 325 => "VS Pump Output",
745
+ 326 => "VS Pump Fault",
584
746
  340 => "Blower Only Speed",
585
747
  341 => "Lo Compressor ECM Speed",
586
748
  342 => "Hi Compressor ECM Speed",
@@ -588,20 +750,35 @@ module Aurora
588
750
  346 => "Cooling Airflow Adjustment",
589
751
  347 => "Aux Heat ECM Speed",
590
752
  362 => "Active Dehumidify", # any value is true
591
- 460 => "IZ2??",
592
- 461 => "IZ2??",
593
- 462 => "IZ2 Status", # 5 when online; 1 when in setup mode
594
753
  400 => "DHW Enabled",
595
754
  401 => "DHW Setpoint",
596
- # 403 => "DHW Status", just a guess, based on AID Tool querying this register while showing DHW settings
597
- 414 => "On Peak/SmartGrid 2", # 0x0001 only
755
+ 402 => "Brine Type",
756
+ 403 => "Flow Meter Type",
757
+ 404 => "Blower Type",
758
+ 405 => "SmartGrid Trigger",
759
+ 406 => "SmartGrid Action", # 0/1 for 1/2; see 414
760
+ 407 => "Off Time Length",
761
+ 408 => "HA Alarm 1 Trigger",
762
+ 409 => "HA Alarm 1 Action",
763
+ 410 => "HA Alarm 2 Trigger",
764
+ 411 => "HA Alarm 2 Action",
765
+ 412 => "Energy Monitor", # 0 none, 1 compressor monitor, 2 energy monitor
766
+ 413 => "Pump Type",
767
+ 414 => "On Peak/SmartGrid", # 0x0001 only
768
+ 416 => "Energy Phase Type",
769
+ 417 => "Power Adjustment Factor L",
770
+ 418 => "Power Adjustment Factor H",
598
771
  419 => "Loop Pressure Trip",
772
+ 460 => "IZ2 Heartbeat?",
773
+ 461 => "IZ2 Heartbeat?",
774
+ 462 => "IZ2 Status", # 5 when online; 1 when in setup mode
599
775
  483 => "Number of IZ2 Zones",
600
776
  501 => "Set Point", # only read by AID tool? this is _not_ heating/cooling set point
601
777
  502 => "Ambient Temperature",
602
778
  564 => "IZ2 Compressor Speed Desired",
603
779
  565 => "IZ2 Blower % Desired",
604
780
  567 => "Entering Air",
781
+ 710 => "Fault Description",
605
782
  740 => "Entering Air",
606
783
  741 => "Relative Humidity",
607
784
  745 => "Heating Set Point",
@@ -610,9 +787,15 @@ module Aurora
610
787
  800 => "Thermostat Installed",
611
788
  801 => "Thermostat Version",
612
789
  802 => "Thermostat Revision",
790
+ 803 => "??? Installed",
791
+ 804 => "??? Version",
792
+ 805 => "??? Revision",
613
793
  806 => "AXB Installed",
614
794
  807 => "AXB Version",
615
795
  808 => "AXB Revision",
796
+ 809 => "AHB Installed",
797
+ 810 => "AHB Version",
798
+ 811 => "AHB Revision",
616
799
  812 => "IZ2 Installed",
617
800
  813 => "IZ2 Version",
618
801
  814 => "IZ2 Revision",
@@ -635,27 +818,64 @@ module Aurora
635
818
  1106 => "Aux Amps",
636
819
  1107 => "Compressor 1 Amps",
637
820
  1108 => "Compressor 2 Amps",
638
- 1109 => "Heating Liquid Line",
821
+ 1109 => "Heating Liquid Line Temperature",
639
822
  1110 => "Leaving Water",
640
823
  1111 => "Entering Water",
641
- 1114 => "DHW Temp",
824
+ 1112 => "Leaving Air Temperature",
825
+ 1113 => "Suction Temperature",
826
+ 1114 => "DHW Temperature",
827
+ 1115 => "Discharge Pressure",
828
+ 1116 => "Suction Pressure",
642
829
  1117 => "Waterflow",
643
- 1134 => "Saturated Discharge Temperature",
644
- 1135 => "SubCooling",
645
- 1147 => "Compressor Watts",
646
- 1149 => "Blower Watts",
647
- 1151 => "Aux Watts",
648
- 1153 => "Total Watts",
649
- 1157 => "Ht of Rej",
650
- 1165 => "VS Pump Watts",
830
+ 1119 => "Loop Pressure", # only valid < 1000psi
831
+ 1124 => "Saturated Evaporator Temperature",
832
+ 1125 => "SuperHeat",
833
+ 1126 => "Vaport Injector Open %",
834
+ 1134 => "Saturated Condensor Discharge Temperature",
835
+ 1135 => "SubCooling (Heating)",
836
+ 1136 => "SubCooling (Cooling)",
837
+ 1146 => "Compressor Watts",
838
+ 1148 => "Blower Watts",
839
+ 1150 => "Aux Watts",
840
+ 1152 => "Total Watts",
841
+ 1154 => "Heat of Extraction",
842
+ 1156 => "Heat of Rejection",
843
+ 1164 => "Pump Watts",
651
844
  12_606 => "Heating Mode (write)",
652
845
  12_619 => "Heating Setpoint (write)",
653
846
  12_620 => "Cooling Setpoint (write)",
654
847
  12_621 => "Fan Mode (write)",
655
- 3000 => "Compressor Speed?",
656
- 3001 => "Compressor Speed?",
848
+ 3000 => "Compressor Speed Desired",
849
+ 3001 => "Compressor Speed Actual",
850
+ 3002 => "Manual Operation",
657
851
  3027 => "Compressor Speed",
658
- 3904 => "Leaving Air Temperature?",
852
+ 3220 => "VS Drive Details (General 1)",
853
+ 3221 => "VS Drive Details (General 2)",
854
+ 3222 => "VS Drive Details (Derate 1)",
855
+ 3223 => "VS Drive Details (Derate 2)",
856
+ 3224 => "VS Drive Details (Safemode 1)",
857
+ 3225 => "VS Drive Details (Safemode 2)",
858
+ 3226 => "VS Drive Details (Alarm 1)",
859
+ 3227 => "VS Drive Details (Alarm 2)",
860
+ 3327 => "VS Drive Temperature",
861
+ 3322 => "VS Drive Discharge Pressure",
862
+ 3323 => "VS Drive Suction Pressure",
863
+ 3325 => "VS Drive Discharge Temperature",
864
+ 3326 => "VS Drive Compressor Ambient Temperature",
865
+ 3330 => "VS Drive Entering Water Temperature",
866
+ 3331 => "VS Drive Line Voltage",
867
+ 3332 => "VS Drive Thermo Power",
868
+ 3422 => "VS Drive Compressor Power",
869
+ 3424 => "VS Drive Supply Voltage",
870
+ 3522 => "VS Drive Inverter Temperature",
871
+ 3523 => "VS Drive UDC Voltage",
872
+ 3524 => "VS Drive Fan Speed",
873
+ 3804 => "VS Drive Details (EEV2 Ctl)",
874
+ 3808 => "VS Drive SuperHeat Percent",
875
+ 3903 => "VS Drive Suction Temperature",
876
+ 3904 => "VS Drive Leaving Air Temperature?",
877
+ 3905 => "VS Drive Saturated Evaporator Discharge Temperature",
878
+ 3906 => "VS Drive SuperHeat Temperature",
659
879
  31_003 => "Outdoor Temp",
660
880
  31_005 => "IZ2 Demand",
661
881
  31_109 => "Humidifier Mode", # write to 21114
@@ -670,7 +890,10 @@ module Aurora
670
890
  .merge(ignore(93..104))
671
891
  .merge(ignore(106..109))
672
892
  .merge(faults(601..699))
893
+ .merge(ignore(711..717))
673
894
  .merge(zone_registers)
895
+ .merge(ignore(1147, 1149, 1151, 1153, 1155, 1157, 1165))
896
+ .merge(ignore(3423, 3425))
674
897
  .merge(ignore(31_401..31_412))
675
898
  .merge(ignore(31_414..31_420))
676
899
  .merge(ignore(31_422..31_433))