waterfurnace_aurora 0.7.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,41 +69,71 @@ 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,
117
+ :abc_version,
89
118
  :model,
90
119
  :serial_number,
91
120
  :zones,
121
+ :aux_heat,
92
122
  :compressor,
93
123
  :blower,
94
124
  :pump,
95
125
  :dhw,
96
126
  :humidistat,
127
+ :current_fault,
97
128
  :faults,
129
+ :locked_out,
130
+ :derated,
131
+ :safe_mode,
98
132
  :current_mode,
133
+ :low_pressure_switch,
134
+ :high_pressure_switch,
135
+ :emergency_shutdown,
136
+ :load_shed,
99
137
  :entering_air_temperature,
100
138
  :leaving_air_temperature,
101
139
  :leaving_water_temperature,
@@ -104,21 +142,27 @@ module Aurora
104
142
  :fp1,
105
143
  :fp2,
106
144
  :line_voltage,
107
- :aux_heat_watts,
108
- :total_watts
145
+ :watts
146
+
147
+ alias_method :emergency_shutdown?, :emergency_shutdown
148
+ alias_method :load_shed?, :load_shed
149
+ alias_method :locked_out?, :locked_out
150
+ alias_method :derated?, :derated
151
+ alias_method :safe_mode?, :safe_mode
109
152
 
110
153
  def initialize(uri)
111
154
  @modbus_slave = self.class.open_modbus_slave(uri)
112
155
  @modbus_slave.read_retry_timeout = 15
113
156
  @modbus_slave.read_retries = 2
114
- raw_registers = @modbus_slave.holding_registers[33, 88...110, 404, 412..413, 1103, 1114]
157
+ raw_registers = @modbus_slave.holding_registers[2, 33, 88...110, 404, 412..413, 813, 1103, 1114]
115
158
  registers = Aurora.transform_registers(raw_registers.dup)
159
+ @abc_version = registers[2]
116
160
  @program = registers[88]
117
161
  @model = registers[92]
118
162
  @serial_number = registers[105]
119
163
  @energy_monitor = raw_registers[412]
120
164
 
121
- @zones = if iz2?
165
+ @zones = if iz2? && iz2_version >= 2.0
122
166
  iz2_zone_count = @modbus_slave.holding_registers[483]
123
167
  (0...iz2_zone_count).map { |i| IZ2Zone.new(self, i + 1) }
124
168
  else
@@ -127,6 +171,7 @@ module Aurora
127
171
 
128
172
  @abc_dipswitches = registers[33]
129
173
  @axb_dipswitches = registers[1103]
174
+ @aux_heat = AuxHeat.new(self)
130
175
  @compressor = if @program == "ABCVSP"
131
176
  Compressor::VSDrive.new(self)
132
177
  else
@@ -152,12 +197,15 @@ module Aurora
152
197
 
153
198
  @faults = []
154
199
 
155
- @registers_to_read = [6, 19..20, 25, 30, 112, 344, 740..741, 900, 1104, 1110..1111, 1114, 1150..1153, 1165,
156
- 31_003]
200
+ @entering_air_register = awl_axb? ? 740 : 567
201
+ @registers_to_read = [6, 19..20, 25, 30..31, 112, 344, @entering_air_register, 1104, 1110..1111, 1114, 1150..1153,
202
+ 1165]
203
+ @registers_to_read.concat([741, 31_003]) if awl_communicating?
204
+ @registers_to_read << 900 if awl_axb?
157
205
  zones.each do |z|
158
206
  @registers_to_read.concat(z.registers_to_read)
159
207
  end
160
- @components = [compressor, blower, pump, dhw, humidistat].compact
208
+ @components = [aux_heat, compressor, blower, pump, dhw, humidistat].compact
161
209
  @components.each do |component|
162
210
  @registers_to_read.concat(component.registers_to_read)
163
211
  end
@@ -178,34 +226,41 @@ module Aurora
178
226
 
179
227
  outputs = registers[30]
180
228
 
181
- @entering_air_temperature = registers[740]
182
- @leaving_air_temperature = registers[900]
229
+ @entering_air_temperature = registers[@entering_air_register]
230
+ @leaving_air_temperature = registers[900] if awl_axb?
183
231
  @leaving_water_temperature = registers[1110]
184
232
  @entering_water_temperature = registers[1111]
185
233
  @outdoor_temperature = registers[31_003]
186
234
  @fp1 = registers[19]
187
235
  @fp2 = registers[20]
188
- @locked_out = registers[25] & 0x8000
189
- @error = registers[25] & 0x7fff
190
- @derated = (41..46).cover?(@error)
191
- @safe_mode = [47, 48, 49, 72, 74].include?(@error)
236
+ @locked_out = !(registers[25] & 0x8000).zero?
237
+ @current_fault = registers[25] & 0x7fff
238
+ @derated = (41..46).cover?(@current_fault)
239
+ @safe_mode = [47, 48, 49, 72, 74].include?(@current_fault)
240
+ @low_pressure_switch = registers[31][:lps]
241
+ @high_pressure_switch = registers[31][:hps]
242
+ @emergency_shutdown = !!registers[31][:emergency_shutdown]
243
+ @load_shed = !!registers[31][:load_shed]
192
244
  @line_voltage = registers[112]
193
- @aux_heat_watts = registers[1151]
194
- @total_watts = registers[1153]
245
+ @watts = registers[1153]
195
246
 
196
247
  @current_mode = if outputs.include?(:lockout)
197
248
  :lockout
198
249
  elsif registers[362]
199
250
  :dehumidify
200
251
  elsif outputs.include?(:cc2) || outputs.include?(:cc)
201
- outputs.include?(:rv) ? :cooling : :heating
202
- elsif outputs.include?(:eh2)
203
- outputs.include?(:rv) ? :eh2 : :emergency
204
- elsif outputs.include?(:eh1)
205
- outputs.include?(:rv) ? :eh1 : :emergency
252
+ if outputs.include?(:rv)
253
+ :cooling
254
+ elsif outputs.include?(:eh2) || outputs.include?(:eh1)
255
+ :heating_with_aux
256
+ else
257
+ :heating
258
+ end
259
+ elsif outputs.include?(:eh2) || outputs.include?(:eh1)
260
+ :emergency_heat
206
261
  elsif outputs.include?(:blower)
207
262
  :blower
208
- elsif registers[6]
263
+ elsif !registers[6].zero?
209
264
  :waiting
210
265
  else
211
266
  :standby
@@ -270,13 +325,18 @@ module Aurora
270
325
  end
271
326
 
272
327
  # config aurora system
273
- { thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824 }.each do |(component, register)|
328
+ { thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824, awl: 827 }.each do |(component, register)|
274
329
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
275
330
  def #{component}?
276
331
  return @#{component} if instance_variable_defined?(:@#{component})
277
332
  @#{component} = @modbus_slave.holding_registers[#{register}] != 3
278
333
  end
279
334
 
335
+ def #{component}_version
336
+ return @#{component}_version if instance_variable_defined?(:@#{component}_version)
337
+ @#{component}_version = @modbus_slave.holding_registers[#{register + 1}].to_f / 100
338
+ end
339
+
280
340
  def add_#{component}
281
341
  @modbus_slave.holding_registers[#{register}] = 2
282
342
  end
@@ -287,6 +347,27 @@ module Aurora
287
347
  RUBY
288
348
  end
289
349
 
350
+ # see https://www.waterfurnace.com/literature/symphony/ig2001ew.pdf
351
+ # is there a communicating system compliant with AWL?
352
+ def awl_communicating?
353
+ awl_thermostat? || awl_iz2?
354
+ end
355
+
356
+ # is the thermostat AWL compliant?
357
+ def awl_thermostat?
358
+ thermostat? && thermostat_version >= 3.0
359
+ end
360
+
361
+ # is the IZ2 AWL compliant?
362
+ def awl_iz2?
363
+ iz2? && iz2_version >= 2.0
364
+ end
365
+
366
+ # is the AXB AWL compliant?
367
+ def awl_axb?
368
+ axb? && axb_version >= 2.0
369
+ end
370
+
290
371
  def inspect
291
372
  "#<Aurora::ABCClient #{(instance_variables - [:@modbus_slave]).map do |iv|
292
373
  "#{iv}=#{instance_variable_get(iv).inspect}"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aurora/component"
4
+
5
+ module Aurora
6
+ class AuxHeat < Component
7
+ attr_reader :stage, :watts
8
+
9
+ def refresh(registers)
10
+ outputs = registers[30]
11
+ @stage = if outputs.include?(:eh2)
12
+ 2
13
+ elsif outputs.include?(:eh1)
14
+ 1
15
+ else
16
+ 0
17
+ end
18
+ @watts = registers[1151] if abc.energy_monitoring?
19
+ end
20
+ end
21
+ end
data/lib/aurora/blower.rb CHANGED
@@ -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, :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 = [1134]
25
+ result << (1146..1147) if abc.energy_monitoring?
26
+ result
29
27
  end
30
28
 
31
29
  def refresh(registers)
@@ -37,12 +35,24 @@ module Aurora
37
35
  else
38
36
  0
39
37
  end
38
+ @saturated_condensor_discharge_temperature = registers[1134]
40
39
  @watts = registers[1146] if abc.energy_monitoring?
41
40
  end
42
41
  end
43
42
 
44
43
  class VSDrive < GenericCompressor
45
- attr_reader :ambient_temperature, :iz2_desired_speed
44
+ attr_reader :drive_temperature,
45
+ :inverter_temperature,
46
+ :ambient_temperature,
47
+ :iz2_desired_speed,
48
+ :fan_speed,
49
+ :discharge_pressure,
50
+ :discharge_temperature,
51
+ :suction_pressure,
52
+ :suction_temperature,
53
+ :saturated_evaporator_discharge_temperature,
54
+ :superheat_temperature,
55
+ :superheat_percentage
46
56
 
47
57
  def initialize(abc)
48
58
  super(abc, 12)
@@ -53,7 +63,7 @@ module Aurora
53
63
  end
54
64
 
55
65
  def registers_to_read
56
- result = super + [209, 3001, 3326]
66
+ result = super + [209, 3001, 3322..3327, 3522, 3524, 3808, 3903..3906]
57
67
  result << 564 if abc.iz2?
58
68
  result
59
69
  end
@@ -62,7 +72,18 @@ module Aurora
62
72
  super
63
73
 
64
74
  @speed = registers[3001]
75
+ @discharge_pressure = registers[3322]
76
+ @suction_pressure = registers[3323]
77
+ @discharge_temperature = registers[3325]
65
78
  @ambient_temperature = registers[3326]
79
+ @drive_temperature = registers[3327]
80
+ @inverter_temperature = registers[3522]
81
+ @fan_speed = registers[3524]
82
+ @superheat_percentage = registers[3808]
83
+ @suction_temperature = registers[3903]
84
+ @saturated_evaporator_discharge_temperature = registers[3905]
85
+ @superheat_temperature = registers[3906]
86
+
66
87
  @iz2_desired_speed = registers[564] if abc.iz2?
67
88
  end
68
89
  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
@@ -29,6 +29,8 @@ module Aurora
29
29
  alias_method :dehumidifier_running?, :dehumidifier_running
30
30
 
31
31
  def registers_to_read
32
+ return [] unless @abc.awl_communicating?
33
+
32
34
  result = [741]
33
35
  if humidifier? || dehumidifier? || abc.compressor.is_a?(Compressor::VSDrive)
34
36
  result.concat(abc.iz2? ? [21_114, 31_109..31_110] : [12_309..12_310])
@@ -73,8 +75,6 @@ module Aurora
73
75
  raw_value |= 0x4000 if humidifier_mode == :auto
74
76
  raw_value |= 0x8000 if dehumidifier_mode == :auto
75
77
  holding_registers[abc.iz2? ? 21_114 : 12_309] = raw_value
76
- @humidifier_mode = humidifier_mode
77
- @dehumidifier_mode = dehumidifier_mode
78
78
  end
79
79
 
80
80
  def humidification_target=(value)
@@ -90,8 +90,6 @@ module Aurora
90
90
  raise ArgumentError unless (35..65).cover?(dehumidification_target)
91
91
 
92
92
  holding_registers[abc.iz2? ? 21_115 : 12_310] = (humidification_target << 8) + dehumidification_target
93
- @humidification_target = humidification_target
94
- @dehumidification_target = dehumidification_target
95
93
  end
96
94
  end
97
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
 
@@ -20,9 +21,14 @@ module Aurora
20
21
  if register.length == 1
21
22
  case register.first
22
23
  when Integer
24
+ missing_register(register.first) unless @registers.key?(register.first)
23
25
  @registers[register.first]
24
26
  when Range
25
- @registers.values_at(*register.first.to_a)
27
+ registers = register.first.to_a
28
+ registers.each do |i|
29
+ missing_register(i) unless @registers.key?(i)
30
+ end
31
+ @registers.values_at(*registers)
26
32
  else
27
33
  raise ArgumentError, "Not implemented yet #{register.inspect}"
28
34
  end
@@ -35,6 +41,11 @@ module Aurora
35
41
  result = {}
36
42
  queries.each do |query|
37
43
  Array(query).each do |i|
44
+ unless @registers.key?(i)
45
+ missing_register(i)
46
+ next
47
+ end
48
+
38
49
  result[i] = @registers[i]
39
50
  end
40
51
  end
@@ -45,5 +56,13 @@ module Aurora
45
56
  @registers[addr] = value
46
57
  end
47
58
  alias_method :[]=, :write_holding_register
59
+
60
+ private
61
+
62
+ def missing_register(idx)
63
+ raise ::ModBus::Errors::IllegalDataAddress unless @ignore_missing_registers
64
+
65
+ logger.warn("missing register #{idx}")
66
+ end
48
67
  end
49
68
  end
data/lib/aurora/pump.rb CHANGED
@@ -31,7 +31,7 @@ module Aurora
31
31
  alias_method :manual_control?, :manual_control
32
32
 
33
33
  def registers_to_read
34
- super + [321..325]
34
+ super + (@abc.awl_axb? ? [321..325] : [321..324])
35
35
  end
36
36
 
37
37
  def refresh(registers)
@@ -39,7 +39,7 @@ module Aurora
39
39
  @minimum_speed = registers[321]
40
40
  @maximum_speed = registers[322]
41
41
  @manual_control = registers[323] != :off
42
- @speed = registers[325]
42
+ @speed = registers[325] if @abc.awl_axb?
43
43
  end
44
44
 
45
45
  def manual_control=(value)
@@ -60,12 +60,13 @@ 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
 
66
67
  def to_string(registers, idx, length)
67
68
  (idx...(idx + length)).map do |i|
68
- raise ArgumentError, "Missing register #{i} for string starting at #{idx}" unless registers[i]
69
+ next "\ufffd" unless registers[i] # missing data? add unicode invalid character
69
70
 
70
71
  (registers[i] >> 8).chr + (registers[i] & 0xff).chr
71
72
  end.join.sub(/[ \0]+$/, "")
@@ -112,7 +113,7 @@ module Aurora
112
113
  53 => "Condensing Pressure Sensor", # Low condensing pressure (PD) or invalid (0 to 870 psi) Retry 10x.
113
114
  54 => "Low Supply Voltage", # Supply Voltage is <180 V (190V to reset) or powered off/on too quickly (<30 sec.).
114
115
  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
+ 56 => "Drive Over Current", # Over current tripped by phase loss, earth fault, short circuit, low water flow, low air flow, or major drive fault. # rubocop:disable Layout/LineLength
116
117
  57 => "Drive Over/Under Voltage", # DC Link Voltage to compressor is >450vdc or at minimum voltage (<185vdc).
117
118
  58 => "High Drive Temp", # Drive Temp has reached critical High Temp >239 F
118
119
  59 => "Internal Drive Error", # The MOC has encountered an internal fault or an internal error. Probably fatal.
@@ -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,8 +706,9 @@ 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
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
708
712
  19 => "FP1 (Cooling Liquid Line) Temperature",
709
713
  20 => "FP2",
710
714
  21 => "Condensate", # >= 270 normal, otherwise fault
@@ -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,19 +15,23 @@ module Aurora
15
15
  :fan_intermittent_off
16
16
 
17
17
  def registers_to_read
18
- [31, 502, 745..746, 12_005..12_006]
18
+ return [] unless @abc.awl_thermostat?
19
+
20
+ [502, 745..746, 12_005..12_006]
19
21
  end
20
22
 
21
23
  def refresh(registers)
22
- @ambient_temperature = registers[502]
23
- @heating_target_temperature = registers[745]
24
- @cooling_target_temperature = registers[746]
25
- config1 = registers[12_005]
26
- config2 = registers[12_006]
27
- @target_fan_mode = config1[:fan]
28
- @fan_intermittent_on = config1[:on_time]
29
- @fan_intermittent_off = config1[:off_time]
30
- @target_mode = config2[:mode]
24
+ if @abc.awl_thermostat?
25
+ @ambient_temperature = registers[502]
26
+ @heating_target_temperature = registers[745]
27
+ @cooling_target_temperature = registers[746]
28
+ config1 = registers[12_005]
29
+ config2 = registers[12_006]
30
+ @target_fan_mode = config1[:fan]
31
+ @fan_intermittent_on = config1[:on_time]
32
+ @fan_intermittent_off = config1[:off_time]
33
+ @target_mode = config2[:mode]
34
+ end
31
35
 
32
36
  inputs = registers[31]
33
37
  @current_fan_mode = inputs.include?(:g)
@@ -44,14 +48,12 @@ module Aurora
44
48
  return unless (raw_value = HEATING_MODE.invert[value])
45
49
 
46
50
  @abc.modbus_slave.holding_registers[12_606] = raw_value
47
- @target_mode = value
48
51
  end
49
52
 
50
53
  def target_fan_mode=(value)
51
54
  return unless (raw_value = FAN_MODE.invert[value])
52
55
 
53
56
  @abc.modbus_slave.holding_registers[12_621] = raw_value
54
- @target_fan_mode = value
55
57
  end
56
58
 
57
59
  def heating_target_temperature=(value)
@@ -59,7 +61,6 @@ module Aurora
59
61
 
60
62
  raw_value = (value * 10).to_i
61
63
  @abc.modbus_slave.holding_registers[12_619] = raw_value
62
- @heating_target_temperature = value
63
64
  end
64
65
 
65
66
  def cooling_target_temperature=(value)
@@ -67,21 +68,18 @@ module Aurora
67
68
 
68
69
  raw_value = (value * 10).to_i
69
70
  @abc.modbus_slave.holding_registers[12_620] = raw_value
70
- @cooling_target_temperature = value
71
71
  end
72
72
 
73
73
  def fan_intermittent_on=(value)
74
74
  return unless value >= 0 && value <= 25 && (value % 5).zero?
75
75
 
76
76
  holding_registers[12_622] = value
77
- @fan_intermittent_on = value
78
77
  end
79
78
 
80
79
  def fan_intermittent_off=(value)
81
80
  return unless value >= 0 && value <= 40 && (value % 5).zero?
82
81
 
83
82
  holding_registers[12_623] = value
84
- @fan_intermittent_off = value
85
83
  end
86
84
  end
87
85
  end