waterfurnace_aurora 0.4.5 → 0.5.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: 792824de511d596a9c0cacc0ef0eae5385e0ec72e4c9da1765292d4825256769
4
- data.tar.gz: 9cbd94692b1074e7430e6089348d07d5a31506f6e679d82aaa8762316efbf634
3
+ metadata.gz: 16b9a4ef085dc672bf6b360947c70a959f03b3406f0c2dae4eac614a2f12c412
4
+ data.tar.gz: 5a7ef967170bd5440b94407e05cfe6e2f1bae40d838a23de26d442a1e4fa9a14
5
5
  SHA512:
6
- metadata.gz: cec2a4f8ef4353a3c824af4d701dc6fe8ccc904d2ead6176b3507828023430ff335a6d2f2a5132e764d21adf8242973677d0b857079c74f16e8b49ae14a45977
7
- data.tar.gz: c52dfdbc4e6e18c636c3e61226b11f7b4cc056fd76413794a41235936783f07ea09f46db77a901c02957a50ba82555cf35e84794c8903d73b00cf2fd830b480b
6
+ metadata.gz: d31c1d4a82dc9420adedd8b5043ebde59845eb5cc90c14109ad51d533687e0fa7010e91c04858773d9f40523f534118d72f891fb673344810244e2d121c0b764
7
+ data.tar.gz: b83b92e7b7ad9ecb2dda5eae57d2d460a82285420e169acc317c54390234cc123bead659fc56e2be53dbb602dd24e0b4cce66bd4223bd52badd7d543d641a4a7
@@ -76,8 +76,10 @@ class MQTTBridge
76
76
  @abc.refresh
77
77
 
78
78
  components = { @homie_abc => @abc,
79
+ @compressor => @abc.compressor,
79
80
  @blower => @abc.blower,
80
- @pump => @abc.pump }
81
+ @pump => @abc.pump,
82
+ @dhw => @abc.dhw }.compact
81
83
  @abc.zones.each_with_index do |z, idx|
82
84
  homie_zone = @homie["zone#{idx + 1}"]
83
85
  components[homie_zone] = z
@@ -89,12 +91,6 @@ class MQTTBridge
89
91
  end
90
92
  end
91
93
 
92
- if @abc.dhw?
93
- @dhw["enabled"].value = @abc.dhw_enabled
94
- @dhw["water-temperature"].value = @abc.dhw_water_temperature
95
- @dhw["set-point"].value = @abc.dhw_setpoint
96
- end
97
-
98
94
  @abc.faults.each_with_index do |fault_count, i|
99
95
  @faults["e#{i + 1}"].value = fault_count
100
96
  end
@@ -109,8 +105,6 @@ class MQTTBridge
109
105
 
110
106
  def publish_basic_attributes
111
107
  @homie_abc = @homie.node("abc", "Aurora Basic Control", "ABC") do |node|
112
- node.property("compressor-speed", "Compressor Speed", :integer, @abc.compressor_speed,
113
- format: @abc.vs_drive? ? 0..12 : 0..2)
114
108
  node.property("current-mode", "Current Heating/Cooling Mode", :enum, @abc.current_mode,
115
109
  format: %w[lockout standby blower heating cooling eh1 eh2 emergency waiting dehumidify])
116
110
  node.property("entering-air-temperature", "Entering Air Temperature", :float, @abc.entering_air_temperature,
@@ -128,13 +122,29 @@ class MQTTBridge
128
122
  format: 0..100)
129
123
  node.property("fp1", "FP1 Sensor", :float, @abc.fp1, unit: "ºF")
130
124
  node.property("fp2", "FP2 Sensor", :float, @abc.fp2, unit: "ºF")
131
- %i[compressor aux_heat total].each do |component|
125
+ %i[aux_heat total].each do |component|
132
126
  component = "#{component}_watts"
133
127
  node.property(component.tr("_", "-"), component.tr("_", " ").titleize, :integer,
134
128
  @abc.public_send(component), unit: "W")
135
129
  end
136
130
  end
137
131
 
132
+ @compressor = @homie.node("compressor", "Compressor", @abc.compressor.type) do |node|
133
+ node.property("speed", "Current compressor speed", :integer, @abc.compressor.speed,
134
+ format: @abc.compressor.speed_range)
135
+ node.property("watts", "Energy Usage", :integer, @abc.compressor.watts, unit: "W") if @abc.energy_monitoring?
136
+
137
+ next unless @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
138
+
139
+ node.property("ambient-temperature", "Compressor ambient temperature", :float,
140
+ @abc.compressor.ambient_temperature, unit: "ºF")
141
+
142
+ next unless @abc.iz2?
143
+
144
+ node.property("iz2-desired-speed", "IZ2 Desired Speed", :integer, @abc.compressor.iz2_desired_speed,
145
+ format: 0..12)
146
+ end
147
+
138
148
  @blower = @homie.node("blower", "Blower", @abc.blower.type) do |node|
139
149
  if @abc.blower.respond_to?(:running)
140
150
  node.property("running", "Blower is running", :boolean, @abc.blower.running?)
@@ -154,10 +164,11 @@ class MQTTBridge
154
164
  @mutex.synchronize { property.value = @abc.blower.public_send("#{field}=", value) }
155
165
  end
156
166
  end
157
- if @abc.iz2?
158
- node.property("iz2-desired-speed", "IZ2 Desired Speed", :integer, @abc.blower.iz2_desired_speed,
159
- format: 0..100, unit: "%")
160
- end
167
+
168
+ next unless @abc.iz2?
169
+
170
+ node.property("iz2-desired-speed", "IZ2 Desired Speed", :integer, @abc.blower.iz2_desired_speed,
171
+ format: 0..100, unit: "%")
161
172
  end
162
173
 
163
174
  @pump = @homie.node("pump", "Loop Pump", @abc.pump.type) do |node|
@@ -183,16 +194,16 @@ class MQTTBridge
183
194
  end
184
195
  end
185
196
 
186
- if @abc.dhw?
197
+ if @abc.dhw
187
198
  @dhw = @homie.node("dhw", "Domestic Hot Water Generator", "DHW") do |node|
188
- node.property("enabled", "Enabled", :boolean, @abc.dhw_enabled) do |value, property|
189
- @mutex.synchronize { property.value = @abc.dhw_enabled = value }
199
+ node.property("enabled", "Enabled", :boolean, @abc.dhw.enabled) do |value, property|
200
+ @mutex.synchronize { property.value = @abc.dhw.enabled = value }
190
201
  end
191
- node.property("water-temperature", "DHW Water Temperature", :float,
192
- @abc.dhw_water_temperature, unit: "ºF")
193
- node.property("set-point", "DHW Set Point", :float, @abc.dhw_setpoint, format: 100..140,
194
- unit: "ºF") do |value, property|
195
- @mutex.synchronize { property.value = @abc.dhw_setpoint = value }
202
+ node.property("water-temperature", "Water Temperature", :float,
203
+ @abc.dhw.water_temperature, unit: "ºF")
204
+ node.property("set-point", "Set Point", :float, @abc.dhw.set_point, format: 100..140,
205
+ unit: "ºF") do |value, property|
206
+ @mutex.synchronize { property.value = @abc.dhw.set_point = value }
196
207
  end
197
208
  end
198
209
  end
@@ -213,25 +224,21 @@ class MQTTBridge
213
224
  format: allowed_modes) do |value, property|
214
225
  @mutex.synchronize { property.value = zone.target_mode = value.to_sym }
215
226
  end
216
- if zone.respond_to?(:current_mode) # TODO: implement for non-IZ2
217
- node.property("current-mode", "Current Heating/Cooling Mode Requested", :enum, zone.current_mode,
218
- format: %w[standby h1 h2 h3 c1 c2])
219
- end
227
+ node.property("current-mode", "Current Heating/Cooling Mode Requested", :enum, zone.current_mode,
228
+ format: %w[standby h1 h2 h3 c1 c2])
220
229
  node.property("target-fan-mode", "Target Fan Mode", :enum, zone.target_fan_mode,
221
230
  format: %w[auto continuous intermittent]) do |value, property|
222
231
  @mutex.synchronize { property.value = zone.target_fan_mode = value.to_sym }
223
232
  end
224
- if zone.respond_to?(:current_fan_mode) # TODO: implement for non-IZ2
225
- node.property("current-fan-mode", "Current Fan Status", :boolean, zone.current_fan_mode)
226
- node.property("fan-intermittent-on", "Fan Intermittent Mode On Duration", :enum, zone.fan_intermittent_on,
227
- unit: "M", format: %w[0 5 10 15 20]) do |value, property|
228
- @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
229
- end
230
- node.property("fan-intermittent-off", "Fan Intermittent Mode Off Duration", :enum, zone.fan_intermittent_on,
231
- unit: "M", format: %w[0 5 10 15 20 25 30 35 40]) do |value, property|
232
- @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
233
- end
233
+ node.property("fan-intermittent-on", "Fan Intermittent Mode On Duration", :enum, zone.fan_intermittent_on,
234
+ unit: "M", format: %w[0 5 10 15 20]) do |value, property|
235
+ @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
236
+ end
237
+ node.property("fan-intermittent-off", "Fan Intermittent Mode Off Duration", :enum, zone.fan_intermittent_on,
238
+ unit: "M", format: %w[0 5 10 15 20 25 30 35 40]) do |value, property|
239
+ @mutex.synchronize { property.value = zone.fan_intermittent_on = value.to_i }
234
240
  end
241
+ node.property("current-fan-mode", "Current Fan Status", :boolean, zone.current_fan_mode)
235
242
  if zone.is_a?(Aurora::IZ2Zone)
236
243
  node.property("priority", "Zone Priority", :enum, zone.priority, format: %w[economy comfort])
237
244
  node.property("size", "Size", :enum, zone.size, format: %w[0 25 45 70])
@@ -4,6 +4,8 @@ require "yaml"
4
4
  require "uri"
5
5
 
6
6
  require "aurora/blower"
7
+ require "aurora/compressor"
8
+ require "aurora/dhw"
7
9
  require "aurora/iz2_zone"
8
10
  require "aurora/pump"
9
11
  require "aurora/thermostat"
@@ -40,23 +42,20 @@ module Aurora
40
42
  attr_reader :modbus_slave,
41
43
  :serial_number,
42
44
  :zones,
45
+ :compressor,
43
46
  :blower,
44
47
  :pump,
48
+ :dhw,
45
49
  :faults,
46
50
  :current_mode,
47
- :dhw_enabled,
48
- :dhw_setpoint,
49
51
  :entering_air_temperature,
50
52
  :relative_humidity,
51
53
  :leaving_air_temperature,
52
54
  :leaving_water_temperature,
53
55
  :entering_water_temperature,
54
- :dhw_water_temperature,
55
- :compressor_speed,
56
56
  :outdoor_temperature,
57
57
  :fp1,
58
58
  :fp2,
59
- :compressor_watts,
60
59
  :aux_heat_watts,
61
60
  :total_watts
62
61
 
@@ -68,9 +67,16 @@ module Aurora
68
67
  registers = Aurora.transform_registers(raw_registers.dup)
69
68
  @program = registers[88]
70
69
  @serial_number = registers[105]
71
- @dhw_water_temperature = registers[1114]
72
70
  @energy_monitor = raw_registers[412]
73
71
 
72
+ @zones = if iz2?
73
+ iz2_zone_count = @modbus_slave.holding_registers[483]
74
+ (0...iz2_zone_count).map { |i| IZ2Zone.new(self, i + 1) }
75
+ else
76
+ [Thermostat.new(self)]
77
+ end
78
+
79
+ @compressor = @program == "ABCVSP" ? Compressor::VSDrive.new(self) : Compressor::GenericCompressor.new(self)
74
80
  @blower = case raw_registers[404]
75
81
  when 1, 2 then Blower::ECM.new(self, registers[404])
76
82
  when 3 then Blower::FiveSpeed.new(self, registers[404])
@@ -83,13 +89,8 @@ module Aurora
83
89
  Pump::GenericPump.new(self,
84
90
  registers[413])
85
91
  end
92
+ @dhw = DHW.new(self) if (-999..999).include?(registers[1114])
86
93
 
87
- @zones = if iz2?
88
- iz2_zone_count = @modbus_slave.holding_registers[483]
89
- (0...iz2_zone_count).map { |i| IZ2Zone.new(self, i + 1) }
90
- else
91
- [Thermostat.new(self)]
92
- end
93
94
  @faults = []
94
95
  end
95
96
 
@@ -128,26 +129,18 @@ module Aurora
128
129
  end
129
130
 
130
131
  def refresh
131
- registers_to_read = [6, 19..20, 25, 30, 344, 740..741, 900, 1110..1111, 1114, 1147..1153, 1165,
132
+ registers_to_read = [6, 19..20, 25, 30, 344, 740..741, 900, 1110..1111, 1114, 1150..1153, 1165,
132
133
  31_003]
133
- registers_to_read << (400..401) if dhw?
134
+ zones.each do |z|
135
+ registers_to_read.concat(z.registers_to_read)
136
+ end
137
+ registers_to_read.concat(compressor.registers_to_read)
134
138
  registers_to_read.concat(blower.registers_to_read)
135
139
  registers_to_read.concat(pump.registers_to_read)
136
- registers_to_read.concat([362, 3001]) if vs_drive?
137
-
138
- if zones.first.is_a?(IZ2Zone)
139
- zones.each_with_index do |_z, i|
140
- base1 = 21_203 + i * 9
141
- base2 = 31_007 + i * 3
142
- base3 = 31_200 + i * 3
143
- registers_to_read << (base1..(base1 + 1))
144
- registers_to_read << (base2..(base2 + 2))
145
- registers_to_read << base3
146
- end
147
- else
148
- registers_to_read << 502
149
- registers_to_read << (745..746)
150
- end
140
+ registers_to_read.concat(dhw.registers_to_read) if dhw
141
+ # need dehumidify mode to calculate final current mode;
142
+ # apparently non-VSD doesn't have this register at all?
143
+ registers_to_read.concat([362]) if compressor.is_a?(Compressor::VSDrive)
151
144
 
152
145
  @faults = @modbus_slave.holding_registers[601..699]
153
146
 
@@ -156,23 +149,11 @@ module Aurora
156
149
 
157
150
  outputs = registers[30]
158
151
 
159
- @dhw_enabled = registers[400]
160
- @dhw_setpoint = registers[401]
161
152
  @entering_air_temperature = registers[740]
162
153
  @relative_humidity = registers[741]
163
154
  @leaving_air_temperature = registers[900]
164
155
  @leaving_water_temperature = registers[1110]
165
156
  @entering_water_temperature = registers[1111]
166
- @dhw_water_temperature = registers[1114]
167
- @compressor_speed = if vs_drive?
168
- registers[3001]
169
- elsif outputs.include?(:cc2)
170
- 2
171
- elsif outputs.include?(:cc)
172
- 1
173
- else
174
- 0
175
- end
176
157
  @outdoor_temperature = registers[31_003]
177
158
  @fp1 = registers[19]
178
159
  @fp2 = registers[20]
@@ -180,7 +161,6 @@ module Aurora
180
161
  @error = registers[25] & 0x7fff
181
162
  @derated = (41..46).include?(@error)
182
163
  @safe_mode = [47, 48, 49, 72, 74].include?(@error)
183
- @compressor_watts = registers[1147]
184
164
  @aux_heat_watts = registers[1151]
185
165
  @total_watts = registers[1153]
186
166
 
@@ -202,12 +182,13 @@ module Aurora
202
182
  :standby
203
183
  end
204
184
 
205
- blower.refresh(registers)
206
- pump.refresh(registers)
207
-
208
185
  zones.each do |z|
209
186
  z.refresh(registers)
210
187
  end
188
+ compressor.refresh(registers)
189
+ blower.refresh(registers)
190
+ pump.refresh(registers)
191
+ dhw&.refresh(registers)
211
192
  end
212
193
 
213
194
  def cooling_airflow_adjustment=(value)
@@ -215,16 +196,6 @@ module Aurora
215
196
  @modbus_slave.holding_registers[346] = value
216
197
  end
217
198
 
218
- def dhw_enabled=(value)
219
- @modbus_slave.holding_registers[400] = value ? 1 : 0
220
- end
221
-
222
- def dhw_setpoint=(value)
223
- raise ArgumentError unless (100..140).include?(value)
224
-
225
- @modbus_slave.holding_registers[401] = (value * 10).to_i
226
- end
227
-
228
199
  def loop_pressure_trip=(value)
229
200
  @modbus_slave.holding_registers[419] = (value * 10).to_i
230
201
  end
@@ -270,14 +241,6 @@ module Aurora
270
241
  @energy_monitor == 2
271
242
  end
272
243
 
273
- def vs_drive?
274
- @program == "ABCVSP"
275
- end
276
-
277
- def dhw?
278
- (-999..999).include?(dhw_water_temperature)
279
- end
280
-
281
244
  # config aurora system
282
245
  { thermostat: 800, axb: 806, iz2: 812, aoc: 815, moc: 818, eev2: 824 }.each do |(component, register)|
283
246
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -6,6 +6,12 @@ module Aurora
6
6
  @abc = abc
7
7
  end
8
8
 
9
+ def inspect
10
+ "#<Aurora::#{self.class.name} #{(instance_variables - [:@abc]).map do |iv|
11
+ "#{iv}=#{instance_variable_get(iv).inspect}"
12
+ end.join(', ')}>"
13
+ end
14
+
9
15
  private
10
16
 
11
17
  attr_reader :abc
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aurora/component"
4
+
5
+ module Aurora
6
+ module Compressor
7
+ class GenericCompressor < Component
8
+ attr_reader :speed, :watts
9
+
10
+ def type
11
+ "Compressor"
12
+ end
13
+
14
+ def speed_range
15
+ 0..2
16
+ end
17
+
18
+ def registers_to_read
19
+ if abc.energy_monitoring?
20
+ [1146..1147]
21
+ else
22
+ []
23
+ end
24
+ end
25
+
26
+ def refresh(registers)
27
+ outputs = registers[30]
28
+ @speed = if outputs.include?(:cc2)
29
+ 2
30
+ elsif outputs.include?(:cc)
31
+ 1
32
+ else
33
+ 0
34
+ end
35
+ @watts = registers[1146] if abc.energy_monitoring?
36
+ end
37
+ end
38
+
39
+ class VSDrive < GenericCompressor
40
+ attr_reader :ambient_temperature, :iz2_desired_speed
41
+
42
+ def type
43
+ "Variable Speed Drive"
44
+ end
45
+
46
+ def speed_range
47
+ 0..12
48
+ end
49
+
50
+ def registers_to_read
51
+ result = super + [209, 3001, 3326]
52
+ result << 564 if abc.iz2?
53
+ result
54
+ end
55
+
56
+ def refresh(registers)
57
+ super
58
+
59
+ @speed = registers[3001]
60
+ @ambient_temperature = registers[3326]
61
+ @iz2_desired_speed = registers[564] if abc.iz2?
62
+ end
63
+ end
64
+ end
65
+ end
data/lib/aurora/dhw.rb ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aurora/component"
4
+
5
+ module Aurora
6
+ class DHW < Component
7
+ attr_reader :enabled, :set_point, :water_temperature
8
+
9
+ def registers_to_read
10
+ [400..401, 1114]
11
+ end
12
+
13
+ def refresh(registers)
14
+ @enabled = registers[400]
15
+ @set_point = registers[401]
16
+ @water_temperature = registers[1114]
17
+ end
18
+
19
+ def enabled=(value)
20
+ holding_registers[400] = value ? 1 : 0
21
+ end
22
+
23
+ def set_point=(value) # rubocop:disable Naming/AccessorMethodName
24
+ raise ArgumentError unless (100..140).include?(value)
25
+
26
+ raw_value = (value * 10).to_i
27
+ holding_registers[401] = raw_value
28
+ @set_point = value
29
+ end
30
+ end
31
+ end
@@ -5,18 +5,22 @@ require "aurora/thermostat"
5
5
  module Aurora
6
6
  class IZ2Zone < Thermostat
7
7
  attr_reader :zone_number,
8
- :current_mode,
9
- :current_fan_mode,
10
- :fan_intermittent_on,
11
- :fan_intermittent_off,
12
8
  :priority,
13
- :size, :normalized_size
9
+ :size,
10
+ :normalized_size
14
11
 
15
12
  def initialize(abc, zone_number)
16
13
  super(abc)
17
14
  @zone_number = zone_number
18
15
  end
19
16
 
17
+ def registers_to_read
18
+ base1 = 21_203 + (zone_number - 1) * 9
19
+ base2 = 31_007 + (zone_number - 1) * 3
20
+ base3 = 31_200 + (zone_number - 1) * 3
21
+ [base1..(base1 + 1), base2..(base2 + 2), base3]
22
+ end
23
+
20
24
  def refresh(registers)
21
25
  @ambient_temperature = registers[31_007 + (zone_number - 1) * 3]
22
26
 
@@ -420,6 +420,15 @@ module Aurora
420
420
  end
421
421
  end
422
422
 
423
+ def thermostat_configuration2(value)
424
+ result = {
425
+ mode: HEATING_MODE[(value >> 8) & 0x07]
426
+ }
427
+ leftover = value & ~0x0700
428
+ result[:unknown] = format("0x%04x", leftover) unless leftover.zero?
429
+ result
430
+ end
431
+
423
432
  def zone_configuration1(value)
424
433
  fan = if value & 0x80 == 0x80
425
434
  :continuous
@@ -433,7 +442,7 @@ module Aurora
433
442
  on_time: ((value >> 9) & 0x7) * 5,
434
443
  off_time: (((value >> 12) & 0x7) + 1) * 5,
435
444
  cooling_target_temperature: ((value & 0x7e) >> 1) + 36,
436
- heating_target_temperature_carry: value & 0o1
445
+ heating_target_temperature_carry: value & 0x01
437
446
  }
438
447
  leftover = value & ~0x7fff
439
448
  result[:unknown] = format("0x%04x", leftover) unless leftover.zero?
@@ -503,7 +512,7 @@ module Aurora
503
512
  ->(v) { from_bitmask(v, VS_ALARM2) } => [218, 3227],
504
513
  ->(v) { from_bitmask(v, VS_EEV2) } => [280, 3804],
505
514
  method(:vs_manual_control) => [323],
506
- NEGATABLE => [346, 1146],
515
+ NEGATABLE => [346],
507
516
  ->(v) { BRINE_TYPE[v] } => [402],
508
517
  ->(v) { FLOW_METER_TYPE[v] } => [403],
509
518
  ->(v) { BLOWER_TYPE[v] } => [404],
@@ -521,12 +530,13 @@ module Aurora
521
530
  ->(v) { TO_TENTHS.call(NEGATABLE.call(v)) } => [1135, 1136],
522
531
  method(:to_int32) => [1146, 1148, 1150, 1152, 1154, 1156, 1164, 3422, 3424],
523
532
  method(:manual_operation) => [3002],
533
+ method(:thermostat_configuration2) => [12_006],
524
534
  ->(v) { HEATING_MODE[v] } => [12_606, 21_202, 21_211, 21_220, 21_229, 21_238, 21_247],
525
535
  ->(v) { FAN_MODE[v] } => [12_621, 21_205, 21_214, 21_223, 21_232, 21_241, 21_250],
526
536
  ->(v) { from_bitmask(v, HUMIDIFIER_SETTINGS) } => [31_109],
527
537
  ->(v) { { humidification_target: v >> 8, dehumidification_target: v & 0xff } } => [31_110],
528
538
  method(:iz2_demand) => [31_005],
529
- method(:zone_configuration1) => [31_008, 31_011, 31_014, 31_017, 31_020, 31_023],
539
+ method(:zone_configuration1) => [12_005, 31_008, 31_011, 31_014, 31_017, 31_020, 31_023],
530
540
  method(:zone_configuration2) => [31_009, 31_012, 31_015, 31_018, 31_021, 31_024],
531
541
  method(:zone_configuration3) => [31_200, 31_203, 31_206, 31_209, 31_212, 31_215],
532
542
  ->(registers, idx) { to_string(registers, idx, 13) } => [31_400],
@@ -876,10 +886,14 @@ module Aurora
876
886
  3904 => "VS Drive Leaving Air Temperature?",
877
887
  3905 => "VS Drive Saturated Evaporator Discharge Temperature",
878
888
  3906 => "VS Drive SuperHeat Temperature",
889
+ 12_005 => "Fan Configuration",
890
+ 12_006 => "Heating Mode",
879
891
  12_606 => "Heating Mode (write)",
880
892
  12_619 => "Heating Setpoint (write)",
881
893
  12_620 => "Cooling Setpoint (write)",
882
894
  12_621 => "Fan Mode (write)",
895
+ 12_622 => "Intermittent Fan On Time (write)",
896
+ 12_623 => "Intermittent Fan Off Time (write)",
883
897
  31_003 => "Outdoor Temp",
884
898
  31_005 => "IZ2 Demand",
885
899
  31_109 => "Humidifier Mode", # write to 21114
@@ -5,15 +5,39 @@ require "aurora/component"
5
5
  module Aurora
6
6
  class Thermostat < Component
7
7
  attr_reader :target_mode,
8
+ :current_mode,
8
9
  :target_fan_mode,
10
+ :current_fan_mode,
9
11
  :ambient_temperature,
10
12
  :cooling_target_temperature,
11
- :heating_target_temperature
13
+ :heating_target_temperature,
14
+ :fan_intermittent_on,
15
+ :fan_intermittent_off
16
+
17
+ def registers_to_read
18
+ [31, 502, 745..746, 12_005..12_006]
19
+ end
12
20
 
13
21
  def refresh(registers)
14
22
  @ambient_temperature = registers[502]
15
23
  @heating_target_temperature = registers[745]
16
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]
31
+
32
+ inputs = registers[31]
33
+ @current_fan_mode = inputs.include?(:g)
34
+ @current_mode = if inputs[:y2]
35
+ inputs[:o] ? :c2 : :h2
36
+ elsif inputs[:y1]
37
+ inputs[:o] ? :c1 : :h1
38
+ else
39
+ :standby
40
+ end
17
41
  end
18
42
 
19
43
  def target_mode=(value)
@@ -46,10 +70,18 @@ module Aurora
46
70
  @cooling_target_temperature = value
47
71
  end
48
72
 
49
- def inspect
50
- "#<Aurora::#{self.class.name} #{(instance_variables - [:@abc]).map do |iv|
51
- "#{iv}=#{instance_variable_get(iv).inspect}"
52
- end.join(', ')}>"
73
+ def fan_intermittent_on=(value)
74
+ return unless value >= 0 && value <= 25 && (value % 5).zero?
75
+
76
+ holding_registers[12_622] = value
77
+ @fan_intermittent_on = value
78
+ end
79
+
80
+ def fan_intermittent_off=(value)
81
+ return unless value >= 0 && value <= 40 && (value % 5).zero?
82
+
83
+ holding_registers[12_623] = value
84
+ @fan_intermittent_off = value
53
85
  end
54
86
  end
55
87
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aurora
4
- VERSION = "0.4.5"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waterfurnace_aurora
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -136,7 +136,9 @@ files:
136
136
  - lib/aurora/abc_client.rb
137
137
  - lib/aurora/blower.rb
138
138
  - lib/aurora/component.rb
139
+ - lib/aurora/compressor.rb
139
140
  - lib/aurora/core_ext/string.rb
141
+ - lib/aurora/dhw.rb
140
142
  - lib/aurora/iz2_zone.rb
141
143
  - lib/aurora/mock_abc.rb
142
144
  - lib/aurora/modbus/server.rb