waterfurnace_aurora 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/aurora_mock +4 -4
- data/exe/aurora_monitor +4 -4
- data/exe/aurora_mqtt_bridge +210 -38
- data/lib/aurora/abc_client.rb +8 -8
- data/lib/aurora/blower.rb +1 -1
- data/lib/aurora/component.rb +1 -1
- data/lib/aurora/compressor.rb +1 -1
- data/lib/aurora/dhw.rb +2 -2
- data/lib/aurora/humidistat.rb +4 -4
- data/lib/aurora/iz2_zone.rb +13 -13
- data/lib/aurora/mock_abc.rb +1 -1
- data/lib/aurora/modbus/slave.rb +3 -3
- data/lib/aurora/pump.rb +2 -2
- data/lib/aurora/registers.rb +5 -5
- data/lib/aurora/version.rb +1 -1
- metadata +41 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 874cdb2301677f41dcae609df8e59651bb875a2f537bb6afa6f66cd2a3a38f1f
|
4
|
+
data.tar.gz: 1bda4a259f0989eb7bdff05feac18a9f75a1679edffe1ffe220e5ca3f0bbad32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7bb6b496cf370651f22292b225a72113ad390ebbfcfada985d6d7b3bd5d50b84f9d61b89053e2cd80159abd083adfbc14a90dcb183326048f002b941763e348
|
7
|
+
data.tar.gz: 31d6afb25c7df8ccef66da014605bc8a04618cd5b99377ce54462814000b134eb4486554d94bd9b25ef098e3dad07f38617533d0cdcfb4ad0b015070f7667b02
|
data/exe/aurora_mock
CHANGED
@@ -38,7 +38,7 @@ r = slave1.holding_registers = slave2.holding_registers = slave255.holding_regis
|
|
38
38
|
registers = YAML.safe_load(File.read(ARGV[2]))
|
39
39
|
registers.each { |(k, v)| r[k] = v }
|
40
40
|
|
41
|
-
server1.request_callback = lambda
|
41
|
+
server1.request_callback = lambda do |uid, func, req|
|
42
42
|
if func == 68
|
43
43
|
puts "===== no idea to #{uid}: #{req.inspect}"
|
44
44
|
elsif func == 67
|
@@ -54,9 +54,9 @@ server1.request_callback = lambda { |uid, func, req|
|
|
54
54
|
else
|
55
55
|
puts "**** new func #{func}"
|
56
56
|
end
|
57
|
-
|
57
|
+
end
|
58
58
|
|
59
|
-
server1.response_callback = lambda
|
59
|
+
server1.response_callback = lambda do |uid, func, res, req|
|
60
60
|
if func == 3 && res.is_a?(Array) && req
|
61
61
|
unless req[:quant] == res.length
|
62
62
|
puts "wrong number of results"
|
@@ -88,7 +88,7 @@ server1.response_callback = lambda { |uid, func, res, req|
|
|
88
88
|
else
|
89
89
|
puts "**** new func #{func}"
|
90
90
|
end
|
91
|
-
|
91
|
+
end
|
92
92
|
|
93
93
|
server2.start
|
94
94
|
server1.send(:serve, server1.instance_variable_get(:@sp))
|
data/exe/aurora_monitor
CHANGED
@@ -79,7 +79,7 @@ diff_and_print = lambda do |registers|
|
|
79
79
|
last_registers = new_registers
|
80
80
|
end
|
81
81
|
|
82
|
-
server.request_callback = lambda
|
82
|
+
server.request_callback = lambda do |uid, func, req|
|
83
83
|
if func == 6
|
84
84
|
puts "#{Time.now} ===== write register to #{uid}:"
|
85
85
|
registers = { req[:addr] => req[:val] }
|
@@ -104,9 +104,9 @@ server.request_callback = lambda { |uid, func, req|
|
|
104
104
|
else
|
105
105
|
puts "#{Time.now} **** new func #{func}"
|
106
106
|
end
|
107
|
-
|
107
|
+
end
|
108
108
|
|
109
|
-
server.response_callback = lambda
|
109
|
+
server.response_callback = lambda do |uid, func, res, req|
|
110
110
|
if func == 3 && res.is_a?(Array) && req
|
111
111
|
unless req[:quant] == res.length
|
112
112
|
puts "wrong number of results"
|
@@ -138,7 +138,7 @@ server.response_callback = lambda { |uid, func, res, req|
|
|
138
138
|
else
|
139
139
|
puts "#{Time.now} **** new func #{func}"
|
140
140
|
end
|
141
|
-
|
141
|
+
end
|
142
142
|
|
143
143
|
server.send(:serve, server.instance_variable_get(:@sp))
|
144
144
|
loop { nil }
|
data/exe/aurora_mqtt_bridge
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require "aurora"
|
5
5
|
require "homie-mqtt"
|
6
|
+
require "mqtt/home_assistant"
|
6
7
|
require "ccutrer-serialport"
|
7
8
|
require "uri"
|
8
9
|
require "optparse"
|
@@ -79,7 +80,7 @@ class MQTTBridge
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
82
|
-
rescue
|
83
|
+
rescue => e
|
83
84
|
warn "failed processing message: #{e}\n#{e.backtrace}"
|
84
85
|
end
|
85
86
|
|
@@ -123,41 +124,44 @@ class MQTTBridge
|
|
123
124
|
end
|
124
125
|
|
125
126
|
def publish_basic_attributes
|
126
|
-
@homie_abc = @homie.node("abc", "
|
127
|
+
@homie_abc = @homie.node("abc", "Heat Pump", "ABC") do |node|
|
127
128
|
allowed_modes = %w[lockout standby blower heating cooling eh1 eh2 emergency waiting]
|
128
129
|
allowed_modes << "dehumidify" if @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
129
130
|
node.property("current-mode", "Current Heating/Cooling Mode", :enum, @abc.current_mode,
|
130
131
|
format: allowed_modes)
|
131
132
|
node.property("entering-air-temperature", "Entering Air Temperature", :float, @abc.entering_air_temperature,
|
132
|
-
unit: "
|
133
|
+
unit: "°F")
|
133
134
|
node.property("entering-water-temperature", "Entering Water Temperature", :float,
|
134
|
-
@abc.entering_water_temperature, unit: "
|
135
|
+
@abc.entering_water_temperature, unit: "°F")
|
135
136
|
node.property("leaving-air-temperature", "Leaving Air Temperature", :float, @abc.leaving_air_temperature,
|
136
|
-
unit: "
|
137
|
+
unit: "°F")
|
137
138
|
node.property("leaving-water-temperature", "Leaving Water Temperature", :float, @abc.leaving_water_temperature,
|
138
|
-
unit: "
|
139
|
+
unit: "°F")
|
139
140
|
unless @abc.outdoor_temperature.zero? # TODO: figure out the config if this actually exists
|
140
|
-
node.property("outdoor-temperature", "Outdoor Temperature", :float, @abc.outdoor_temperature, unit: "
|
141
|
+
node.property("outdoor-temperature", "Outdoor Temperature", :float, @abc.outdoor_temperature, unit: "°F")
|
141
142
|
end
|
142
143
|
|
143
|
-
node.property("fp1", "FP1 Sensor", :float, @abc.fp1, unit: "
|
144
|
-
node.property("fp2", "FP2 Sensor", :float, @abc.fp2, unit: "
|
144
|
+
node.property("fp1", "FP1 Sensor", :float, @abc.fp1, unit: "°F")
|
145
|
+
node.property("fp2", "FP2 Sensor", :float, @abc.fp2, unit: "°F")
|
145
146
|
%i[aux_heat total].each do |component|
|
146
147
|
component = "#{component}_watts"
|
147
|
-
node.property(component.tr("_", "-"),
|
148
|
-
|
148
|
+
node.property(component.tr("_", "-"),
|
149
|
+
component.sub("_watts", " Power Usage").tr("_", " ").titleize,
|
150
|
+
:integer,
|
151
|
+
@abc.public_send(component),
|
152
|
+
unit: "W")
|
149
153
|
end
|
150
154
|
end
|
151
155
|
|
152
156
|
@compressor = @homie.node("compressor", "Compressor", @abc.compressor.type) do |node|
|
153
|
-
node.property("speed", "Current
|
157
|
+
node.property("speed", "Current Speed", :integer, @abc.compressor.speed,
|
154
158
|
format: @abc.compressor.speed_range)
|
155
|
-
node.property("watts", "
|
159
|
+
node.property("watts", "Power Usage", :integer, @abc.compressor.watts, unit: "W") if @abc.energy_monitoring?
|
156
160
|
|
157
161
|
next unless @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
158
162
|
|
159
|
-
node.property("ambient-temperature", "
|
160
|
-
@abc.compressor.ambient_temperature, unit: "
|
163
|
+
node.property("ambient-temperature", "Ambient Temperature", :float,
|
164
|
+
@abc.compressor.ambient_temperature, unit: "°F")
|
161
165
|
|
162
166
|
next unless @abc.iz2?
|
163
167
|
|
@@ -166,19 +170,19 @@ class MQTTBridge
|
|
166
170
|
end
|
167
171
|
|
168
172
|
@blower = @homie.node("blower", "Blower", @abc.blower.type) do |node|
|
169
|
-
node.property("running", "
|
173
|
+
node.property("running", "Running", :boolean, @abc.blower.running?)
|
170
174
|
if @abc.blower.respond_to?(:speed)
|
171
|
-
node.property("speed", "Current
|
175
|
+
node.property("speed", "Current Speed", :integer, @abc.blower.speed, format: @abc.blower.speed_range)
|
172
176
|
end
|
173
|
-
node.property("watts", "
|
177
|
+
node.property("watts", "Power Usage", :integer, @abc.blower.watts, unit: "W") if @abc.energy_monitoring?
|
174
178
|
|
175
179
|
next unless @abc.blower.is_a?(Aurora::Blower::ECM)
|
176
180
|
|
177
181
|
presets = %w[blower-only aux-heat]
|
178
182
|
presets.concat %w[low-compressor high-compressor] unless @abc.iz2?
|
179
183
|
presets.each do |setting|
|
180
|
-
field = "#{setting.tr(
|
181
|
-
node.property("#{setting}-speed", "#{setting.tr(
|
184
|
+
field = "#{setting.tr("-", "_")}_speed"
|
185
|
+
node.property("#{setting}-speed", "#{setting.tr("-", " ").titleize} Preset Speed", :integer,
|
182
186
|
@abc.blower.public_send(field), format: 1..12) do |value, property|
|
183
187
|
@mutex.synchronize { property.value = @abc.blower.public_send("#{field}=", value) }
|
184
188
|
end
|
@@ -192,23 +196,23 @@ class MQTTBridge
|
|
192
196
|
|
193
197
|
@pump = @homie.node("pump", "Loop Pump", @abc.pump.type) do |node|
|
194
198
|
node.property("waterflow", "Waterflow", :float, @abc.pump.waterflow, unit: "gpm")
|
195
|
-
node.property("watts", "
|
199
|
+
node.property("watts", "Power Usage", :integer, @abc.pump.watts, unit: "W") if @abc.energy_monitoring?
|
196
200
|
|
197
201
|
next unless @abc.pump.is_a?(Aurora::Pump::VSPump)
|
198
202
|
|
199
|
-
node.property("running", "
|
203
|
+
node.property("running", "Running", :boolean, @abc.pump.running)
|
200
204
|
node.property("speed", "Speed", :integer, @abc.pump.speed, format: 0..100, unit: "%") do |value, property|
|
201
205
|
@mutex.synchronize { property.value = @abc.pump.speed = value }
|
202
206
|
end
|
203
|
-
node.property("manual-control", "
|
207
|
+
node.property("manual-control", "Manual Control", :boolean,
|
204
208
|
@abc.pump.manual_control?) do |value, property|
|
205
209
|
@mutex.synchronize { property.value = @abc.pump.manual_control = value }
|
206
210
|
end
|
207
|
-
node.property("minimum-speed", "
|
211
|
+
node.property("minimum-speed", "Actual Minimum Speed", :integer, @abc.pump.minimum_speed,
|
208
212
|
format: 0..100, unit: "%") do |value, property|
|
209
213
|
@mutex.synchronize { property.value = @abc.pump.minimum_speed = value }
|
210
214
|
end
|
211
|
-
node.property("maximum-speed", "
|
215
|
+
node.property("maximum-speed", "Actual Maximum Speed", :integer, @abc.pump.minimum_speed,
|
212
216
|
format: 0..100, unit: "%") do |value, property|
|
213
217
|
@mutex.synchronize { property.value = @abc.pump.maximum_speed = value }
|
214
218
|
end
|
@@ -219,11 +223,11 @@ class MQTTBridge
|
|
219
223
|
node.property("enabled", "Enabled", :boolean, @abc.dhw.enabled) do |value, property|
|
220
224
|
@mutex.synchronize { property.value = @abc.dhw.enabled = value }
|
221
225
|
end
|
222
|
-
node.property("running", "
|
226
|
+
node.property("running", "Pump Running", :boolean, @abc.dhw.running?)
|
223
227
|
node.property("water-temperature", "Water Temperature", :float,
|
224
|
-
@abc.dhw.water_temperature, unit: "
|
228
|
+
@abc.dhw.water_temperature, unit: "°F")
|
225
229
|
node.property("set-point", "Set Point", :float, @abc.dhw.set_point, format: 100..140,
|
226
|
-
unit: "
|
230
|
+
unit: "°F") do |value, property|
|
227
231
|
@mutex.synchronize { property.value = @abc.dhw.set_point = value }
|
228
232
|
end
|
229
233
|
end
|
@@ -233,12 +237,12 @@ class MQTTBridge
|
|
233
237
|
node.property("relative-humidity", "Relative Humidity", :integer, @abc.humidistat.relative_humidity,
|
234
238
|
unit: "%", format: 0..100)
|
235
239
|
if @abc.humidistat.humidifier?
|
236
|
-
node.property("humidifier-running", "Humidifier
|
240
|
+
node.property("humidifier-running", "Humidifier Running", :boolean, @abc.humidistat.humidifier_running?)
|
237
241
|
node.property("humidifier-mode", "Humidifier Mode", :enum, @abc.humidistat.humidifier_mode,
|
238
242
|
format: %i[auto manual]) do |value, property|
|
239
243
|
@mutex.synchronize { property.value = @abc.humidistat.humidifier_mode = value.to_sym }
|
240
244
|
end
|
241
|
-
node.property("humidification-target", "Humidification
|
245
|
+
node.property("humidification-target", "Humidification Target Relative Humidity", :integer,
|
242
246
|
@abc.humidistat.humidification_target, unit: "%", format: 15..50) do |value, property|
|
243
247
|
@mutex.synchronize { property.value = @abc.humidistat.humidification_target = value }
|
244
248
|
end
|
@@ -250,7 +254,7 @@ class MQTTBridge
|
|
250
254
|
format: %i[auto manual]) do |value, property|
|
251
255
|
@mutex.synchronize { property.value = @abc.humidistat.dehumidifier_mode = value.to_sym }
|
252
256
|
end
|
253
|
-
node.property("dehumidification-target", "Dehumidification
|
257
|
+
node.property("dehumidification-target", "Dehumidification Target Relative Humidity", :integer,
|
254
258
|
@abc.humidistat.dehumidification_target, unit: "%", format: 35..65) do |value, property|
|
255
259
|
@mutex.synchronize { property.value = @abc.humidistat.dehumidification_target = value }
|
256
260
|
end
|
@@ -258,11 +262,11 @@ class MQTTBridge
|
|
258
262
|
|
259
263
|
next unless @abc.humidistat.dehumidifier?
|
260
264
|
|
261
|
-
node.property("dehumidifier-running", "Dehumidifier
|
265
|
+
node.property("dehumidifier-running", "Dehumidifier Running", :boolean, @abc.humidistat.dehumidifier_running?)
|
262
266
|
end
|
263
267
|
|
264
268
|
@faults = @homie.node("faults", "Fault History", "ABC") do |node|
|
265
|
-
node.property("clear-history", "Reset
|
269
|
+
node.property("clear-history", "Reset Fault Counts", :enum, retained: false, format: "clear") do |_|
|
266
270
|
@mutex.synchronize { @abc.clear_fault_history }
|
267
271
|
end
|
268
272
|
@abc.faults.each_with_index do |count, i|
|
@@ -302,13 +306,13 @@ class MQTTBridge
|
|
302
306
|
node.property("size", "Size", :enum, zone.size, format: %w[0 25 45 70])
|
303
307
|
node.property("normalized-size", "Normalized Size", :integer, zone.normalized_size, unit: "%", format: 0..100)
|
304
308
|
end
|
305
|
-
node.property("ambient-temperature", "Ambient Temperature", :float, zone.ambient_temperature, unit: "
|
309
|
+
node.property("ambient-temperature", "Ambient Temperature", :float, zone.ambient_temperature, unit: "°F")
|
306
310
|
node.property("heating-target-temperature", "Heating Target Temperature", :integer,
|
307
|
-
zone.heating_target_temperature, unit: "
|
311
|
+
zone.heating_target_temperature, unit: "°F", format: 40..90) do |value, property|
|
308
312
|
@mutex.synchronize { property.value = zone.heating_target_temperature = value }
|
309
313
|
end
|
310
314
|
node.property("cooling-target-temperature", "Cooling Target Temperature", :integer,
|
311
|
-
zone.cooling_target_temperature, unit: "
|
315
|
+
zone.cooling_target_temperature, unit: "°F", format: 54..99) do |value, property|
|
312
316
|
@mutex.synchronize { property.value = zone.cooling_target_temperature = value }
|
313
317
|
end
|
314
318
|
end
|
@@ -318,7 +322,175 @@ class MQTTBridge
|
|
318
322
|
@homie.mqtt.subscribe("#{@homie.topic}/$modbus")
|
319
323
|
@homie.mqtt.subscribe("#{@homie.topic}/$modbus/getregs")
|
320
324
|
@homie.mqtt.subscribe("#{@homie.topic}/$modbus/+/set")
|
321
|
-
@homie.publish
|
325
|
+
@homie.publish do
|
326
|
+
# do HASS publishes in this block so they're done in bulk
|
327
|
+
|
328
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["current-mode"],
|
329
|
+
device_class: :power)
|
330
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["entering-air-temperature"],
|
331
|
+
device_class: :temperature,
|
332
|
+
entity_category: :diagnostic)
|
333
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["entering-water-temperature"],
|
334
|
+
device_class: :temperature,
|
335
|
+
entity_category: :diagnostic)
|
336
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["leaving-air-temperature"],
|
337
|
+
device_class: :temperature,
|
338
|
+
entity_category: :diagnostic)
|
339
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["leaving-water-temperature"],
|
340
|
+
device_class: :temperature,
|
341
|
+
entity_category: :diagnostic)
|
342
|
+
unless @abc.outdoor_temperature.zero?
|
343
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["outdoor-temperature"],
|
344
|
+
device_class: :temperature)
|
345
|
+
end
|
346
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["fp1"],
|
347
|
+
device_class: :temperature,
|
348
|
+
entity_category: :diagnostic)
|
349
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["fp2"],
|
350
|
+
device_class: :temperature,
|
351
|
+
entity_category: :diagnostic)
|
352
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["aux-heat-watts"],
|
353
|
+
device_class: :power)
|
354
|
+
MQTT::HomeAssistant.publish_sensor(@homie["abc"]["total-watts"],
|
355
|
+
device_class: :power)
|
356
|
+
|
357
|
+
MQTT::HomeAssistant.publish_sensor(@homie["compressor"]["speed"])
|
358
|
+
MQTT::HomeAssistant.publish_sensor(@homie["compressor"]["watts"],
|
359
|
+
device_class: :power)
|
360
|
+
|
361
|
+
if @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
362
|
+
MQTT::HomeAssistant.publish_sensor(@homie["compressor"]["ambient-temperature"],
|
363
|
+
device_class: :temperature,
|
364
|
+
entity_category: :diagnostic)
|
365
|
+
|
366
|
+
if @abc.iz2?
|
367
|
+
MQTT::HomeAssistant.publish_sensor(@homie["compressor"]["iz2-desired-speed"],
|
368
|
+
entity_category: :diagnostic)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
MQTT::HomeAssistant.publish_binary_sensor(@homie["blower"]["running"],
|
373
|
+
device_class: :running)
|
374
|
+
MQTT::HomeAssistant.publish_sensor(@homie["blower"]["speed"]) if @abc.blower.respond_to?(:speed)
|
375
|
+
MQTT::HomeAssistant.publish_sensor(@homie["blower"]["watts"],
|
376
|
+
device_class: :power)
|
377
|
+
MQTT::HomeAssistant.publish_number(@homie["blower"]["blower-only-speed"],
|
378
|
+
entity_category: :config)
|
379
|
+
MQTT::HomeAssistant.publish_number(@homie["blower"]["aux-heat-speed"],
|
380
|
+
entity_category: :config)
|
381
|
+
if @abc.iz2?
|
382
|
+
MQTT::HomeAssistant.publish_sensor(@homie["blower"]["iz2-desired-speed"])
|
383
|
+
else
|
384
|
+
MQTT::HomeAssistant.publish_number(@homie["blower"]["low-compressor-speed"],
|
385
|
+
entity_category: :config)
|
386
|
+
MQTT::HomeAssistant.publish_number(@homie["blower"]["high-compressor-speed"],
|
387
|
+
entity_category: :config)
|
388
|
+
end
|
389
|
+
|
390
|
+
MQTT::HomeAssistant.publish_sensor(@homie["pump"]["waterflow"],
|
391
|
+
entity_category: :diagnostic)
|
392
|
+
MQTT::HomeAssistant.publish_sensor(@homie["pump"]["watts"],
|
393
|
+
device_class: :power)
|
394
|
+
|
395
|
+
if @abc.pump.is_a?(Aurora::Pump::VSPump)
|
396
|
+
MQTT::HomeAssistant.publish_binary_sensor(@homie["pump"]["running"],
|
397
|
+
device_class: :running)
|
398
|
+
MQTT::HomeAssistant.publish_number(@homie["pump"]["speed"],
|
399
|
+
entity_category: :diagnostic)
|
400
|
+
|
401
|
+
MQTT::HomeAssistant.publish_switch(@homie["pump"]["manual-control"],
|
402
|
+
entity_category: :diagnostic)
|
403
|
+
MQTT::HomeAssistant.publish_number(@homie["pump"]["minimum-speed"],
|
404
|
+
entity_category: :config)
|
405
|
+
MQTT::HomeAssistant.publish_number(@homie["pump"]["maximum-speed"],
|
406
|
+
entity_category: :config)
|
407
|
+
end
|
408
|
+
|
409
|
+
MQTT::HomeAssistant.publish_scene(@homie["faults"]["clear-history"])
|
410
|
+
@homie["faults"].each do |property|
|
411
|
+
next if property.id == "clear-history"
|
412
|
+
|
413
|
+
MQTT::HomeAssistant.publish_sensor(property,
|
414
|
+
entity_category: :diagnostic)
|
415
|
+
end
|
416
|
+
|
417
|
+
if @abc.dhw
|
418
|
+
MQTT::HomeAssistant.publish_switch(@homie["dhw"]["enabled"],
|
419
|
+
icon: "mdi:water-boiler")
|
420
|
+
MQTT::HomeAssistant.publish_binary_sensor(@homie["dhw"]["running"],
|
421
|
+
device_class: :running)
|
422
|
+
MQTT::HomeAssistant.publish_sensor(@homie["dhw"]["water-temperature"],
|
423
|
+
device_class: :temperature)
|
424
|
+
MQTT::HomeAssistant.publish_number(@homie["dhw"]["set-point"])
|
425
|
+
end
|
426
|
+
|
427
|
+
MQTT::HomeAssistant.publish_sensor(@homie["humidistat"]["relative-humidity"],
|
428
|
+
device_class: :humidity)
|
429
|
+
if @abc.humidistat.humidifier?
|
430
|
+
MQTT::HomeAssistant.publish_humidifier(
|
431
|
+
@homie["humidistat"]["humidifier-running"],
|
432
|
+
device_class: :humidifier,
|
433
|
+
name: "Humidifier",
|
434
|
+
id: "humidifier",
|
435
|
+
target_property: @homie["humidistat"]["humidification-target"],
|
436
|
+
mode_property: @homie["humidistat"]["humidifier-mode"]
|
437
|
+
)
|
438
|
+
end
|
439
|
+
if @abc.humidistat.dehumidifier? || @abc.compressor.is_a?(Aurora::Compressor::VSDrive)
|
440
|
+
property = if @abc.humidistat.dehumidifier?
|
441
|
+
@homie["humidistat"]["dehumidifier-running"]
|
442
|
+
else
|
443
|
+
# yeah, this isn't right, but we have to give HASS _something_
|
444
|
+
@homie["humidistat"]["humidifier-running"]
|
445
|
+
end
|
446
|
+
MQTT::HomeAssistant.publish_humidifier(
|
447
|
+
property,
|
448
|
+
device_class: :dehumidifier,
|
449
|
+
name: "Dehumidifier",
|
450
|
+
id: "dehumidifier",
|
451
|
+
target_property: @homie["humidistat"]["dehumidification-target"],
|
452
|
+
mode_property: @homie["humidistat"]["dehumidifier-mode"]
|
453
|
+
)
|
454
|
+
end
|
455
|
+
|
456
|
+
@abc.zones.each_with_index do |zone, i|
|
457
|
+
homie_zone = @homie["zone#{i + 1}"]
|
458
|
+
MQTT::HomeAssistant.publish_climate(
|
459
|
+
action_property: homie_zone["current-mode"],
|
460
|
+
current_temperature_property: homie_zone["ambient-temperature"],
|
461
|
+
fan_mode_property: homie_zone["target-fan-mode"],
|
462
|
+
mode_property: homie_zone["target-mode"],
|
463
|
+
temperature_high_property: homie_zone["cooling-target-temperature"],
|
464
|
+
temperature_low_property: homie_zone["heating-target-temperature"],
|
465
|
+
templates: {
|
466
|
+
action_template: <<~JINJA
|
467
|
+
{% if value.startswith('h') %}
|
468
|
+
heating
|
469
|
+
{% elif value.startswith('c') %}
|
470
|
+
cooling
|
471
|
+
{% elif value == 'standby' %}
|
472
|
+
idle
|
473
|
+
{% endif %}
|
474
|
+
JINJA
|
475
|
+
}
|
476
|
+
)
|
477
|
+
MQTT::HomeAssistant.publish_binary_sensor(homie_zone["current-fan-mode"],
|
478
|
+
device_class: :running)
|
479
|
+
MQTT::HomeAssistant.publish_select(homie_zone["fan-intermittent-on"],
|
480
|
+
entity_category: :config)
|
481
|
+
MQTT::HomeAssistant.publish_select(homie_zone["fan-intermittent-off"],
|
482
|
+
entity_category: :config)
|
483
|
+
|
484
|
+
next unless zone.is_a?(Aurora::IZ2Zone)
|
485
|
+
|
486
|
+
MQTT::HomeAssistant.publish_sensor(homie_zone["priority"],
|
487
|
+
entity_category: :diagnostic)
|
488
|
+
MQTT::HomeAssistant.publish_sensor(homie_zone["size"],
|
489
|
+
entity_category: :diagnostic)
|
490
|
+
MQTT::HomeAssistant.publish_sensor(homie_zone["normalized-size"],
|
491
|
+
entity_category: :diagnostic)
|
492
|
+
end
|
493
|
+
end
|
322
494
|
end
|
323
495
|
end
|
324
496
|
|
@@ -328,7 +500,7 @@ logger.level = log_level
|
|
328
500
|
abc.modbus_slave.logger = logger
|
329
501
|
|
330
502
|
device = "aurora-#{abc.serial_number}"
|
331
|
-
homie = MQTT::Homie::Device.new(device, "
|
503
|
+
homie = MQTT::Homie::Device.new(device, "WaterFurnace", mqtt: mqtt_uri)
|
332
504
|
homie.logger = logger
|
333
505
|
|
334
506
|
MQTTBridge.new(abc, homie)
|
data/lib/aurora/abc_client.rb
CHANGED
@@ -92,14 +92,14 @@ module Aurora
|
|
92
92
|
when 3 then Blower::FiveSpeed.new(self, registers[404])
|
93
93
|
else; Blower::PSC.new(self, registers[404])
|
94
94
|
end
|
95
|
-
@pump = if (3..5).
|
95
|
+
@pump = if (3..5).cover?(raw_registers[413])
|
96
96
|
Pump::VSPump.new(self,
|
97
97
|
registers[413])
|
98
98
|
else
|
99
99
|
Pump::GenericPump.new(self,
|
100
100
|
registers[413])
|
101
101
|
end
|
102
|
-
@dhw = DHW.new(self) if (-999..999).
|
102
|
+
@dhw = DHW.new(self) if (-999..999).cover?(registers[1114])
|
103
103
|
@humidistat = Humidistat.new(self,
|
104
104
|
@abc_dipswitches[:accessory_relay] == :humidifier,
|
105
105
|
@axb_dipswitches[:accessory_relay2] == :dehumidifier)
|
@@ -171,7 +171,7 @@ module Aurora
|
|
171
171
|
@fp2 = registers[20]
|
172
172
|
@locked_out = registers[25] & 0x8000
|
173
173
|
@error = registers[25] & 0x7fff
|
174
|
-
@derated = (41..46).
|
174
|
+
@derated = (41..46).cover?(@error)
|
175
175
|
@safe_mode = [47, 48, 49, 72, 74].include?(@error)
|
176
176
|
@aux_heat_watts = registers[1151]
|
177
177
|
@total_watts = registers[1153]
|
@@ -212,7 +212,7 @@ module Aurora
|
|
212
212
|
end
|
213
213
|
|
214
214
|
def line_voltage=(value)
|
215
|
-
raise ArgumentError unless (90..635).
|
215
|
+
raise ArgumentError unless (90..635).cover?(value)
|
216
216
|
|
217
217
|
@modbus_slave.holding_registers[112] = value
|
218
218
|
end
|
@@ -227,13 +227,13 @@ module Aurora
|
|
227
227
|
pump_speed: :with_compressor,
|
228
228
|
aux_heat: false)
|
229
229
|
raise ArgumentError, "mode must be :off, :heating, or :cooling" unless %i[off heating cooling].include?(mode)
|
230
|
-
raise ArgumentError, "compressor speed must be between 0 and 12" unless (0..12).
|
230
|
+
raise ArgumentError, "compressor speed must be between 0 and 12" unless (0..12).cover?(compressor_speed)
|
231
231
|
|
232
|
-
unless blower_speed == :with_compressor || (0..12).
|
232
|
+
unless blower_speed == :with_compressor || (0..12).cover?(blower_speed)
|
233
233
|
raise ArgumentError,
|
234
234
|
"blower speed must be :with_compressor or between 0 and 12"
|
235
235
|
end
|
236
|
-
unless pump_speed == :with_compressor || (0..100).
|
236
|
+
unless pump_speed == :with_compressor || (0..100).cover?(pump_speed)
|
237
237
|
raise ArgumentError,
|
238
238
|
"pump speed must be :with_compressor or between 0 and 100"
|
239
239
|
end
|
@@ -273,7 +273,7 @@ module Aurora
|
|
273
273
|
def inspect
|
274
274
|
"#<Aurora::ABCClient #{(instance_variables - [:@modbus_slave]).map do |iv|
|
275
275
|
"#{iv}=#{instance_variable_get(iv).inspect}"
|
276
|
-
end.join(
|
276
|
+
end.join(", ")}>"
|
277
277
|
end
|
278
278
|
end
|
279
279
|
end
|
data/lib/aurora/blower.rb
CHANGED
data/lib/aurora/component.rb
CHANGED
data/lib/aurora/compressor.rb
CHANGED
data/lib/aurora/dhw.rb
CHANGED
@@ -5,7 +5,7 @@ require "aurora/component"
|
|
5
5
|
module Aurora
|
6
6
|
class DHW < Component
|
7
7
|
attr_reader :enabled, :running, :set_point, :water_temperature
|
8
|
-
|
8
|
+
alias_method :running?, :running
|
9
9
|
|
10
10
|
def registers_to_read
|
11
11
|
[400..401, 1114]
|
@@ -23,7 +23,7 @@ module Aurora
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def set_point=(value) # rubocop:disable Naming/AccessorMethodName
|
26
|
-
raise ArgumentError unless (100..140).
|
26
|
+
raise ArgumentError unless (100..140).cover?(value)
|
27
27
|
|
28
28
|
raw_value = (value * 10).to_i
|
29
29
|
holding_registers[401] = raw_value
|
data/lib/aurora/humidistat.rb
CHANGED
@@ -7,8 +7,8 @@ module Aurora
|
|
7
7
|
attr_reader :humidifier_running, :humidifier_mode, :humidification_target,
|
8
8
|
:dehumidifier_running, :dehumidifier_mode, :dehumidification_target,
|
9
9
|
:relative_humidity
|
10
|
-
|
11
|
-
|
10
|
+
alias_method :humidifier_running?, :humidifier_running
|
11
|
+
alias_method :dehumidifer_running?, :dehumidifier_running
|
12
12
|
|
13
13
|
def initialize(abc, has_humidifier, has_dehumidifier)
|
14
14
|
super(abc)
|
@@ -82,8 +82,8 @@ module Aurora
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def set_humidistat_targets(humidification_target, dehumidification_target)
|
85
|
-
raise ArgumentError unless (15..50).
|
86
|
-
raise ArgumentError unless (35..65).
|
85
|
+
raise ArgumentError unless (15..50).cover?(humidification_target)
|
86
|
+
raise ArgumentError unless (35..65).cover?(dehumidification_target)
|
87
87
|
|
88
88
|
holding_registers[abc.iz2? ? 21_115 : 12_310] = (humidification_target << 8) + dehumidification_target
|
89
89
|
@humidification_target = humidification_target
|
data/lib/aurora/iz2_zone.rb
CHANGED
@@ -15,18 +15,18 @@ module Aurora
|
|
15
15
|
end
|
16
16
|
|
17
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
|
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
21
|
[base1..(base1 + 1), base2..(base2 + 2), base3]
|
22
22
|
end
|
23
23
|
|
24
24
|
def refresh(registers)
|
25
|
-
@ambient_temperature = registers[31_007 + (zone_number - 1) * 3]
|
25
|
+
@ambient_temperature = registers[31_007 + ((zone_number - 1) * 3)]
|
26
26
|
|
27
|
-
config1 = registers[31_008 + (zone_number - 1) * 3]
|
28
|
-
config2 = registers[31_009 + (zone_number - 1) * 3]
|
29
|
-
config3 = registers[31_200 + (zone_number - 1) * 3]
|
27
|
+
config1 = registers[31_008 + ((zone_number - 1) * 3)]
|
28
|
+
config2 = registers[31_009 + ((zone_number - 1) * 3)]
|
29
|
+
config3 = registers[31_200 + ((zone_number - 1) * 3)]
|
30
30
|
|
31
31
|
@target_fan_mode = config1[:fan]
|
32
32
|
@fan_intermittent_on = config1[:on_time]
|
@@ -45,28 +45,28 @@ module Aurora
|
|
45
45
|
def target_mode=(value)
|
46
46
|
return unless (raw_value = Aurora::HEATING_MODE.invert[value])
|
47
47
|
|
48
|
-
holding_registers[21_202 + (zone_number - 1) * 9] = raw_value
|
48
|
+
holding_registers[21_202 + ((zone_number - 1) * 9)] = raw_value
|
49
49
|
@target_mode = value
|
50
50
|
end
|
51
51
|
|
52
52
|
def target_fan_mode=(value)
|
53
53
|
return unless (raw_value = Aurora::FAN_MODE.invert[value])
|
54
54
|
|
55
|
-
holding_registers[21_205 + (zone_number - 1) * 9] = raw_value
|
55
|
+
holding_registers[21_205 + ((zone_number - 1) * 9)] = raw_value
|
56
56
|
@target_fan_mode = value
|
57
57
|
end
|
58
58
|
|
59
59
|
def fan_intermittent_on=(value)
|
60
60
|
return unless value >= 0 && value <= 25 && (value % 5).zero?
|
61
61
|
|
62
|
-
holding_registers[21_206 + (zone_number - 1) * 9] = value
|
62
|
+
holding_registers[21_206 + ((zone_number - 1) * 9)] = value
|
63
63
|
@fan_intermittent_on = value
|
64
64
|
end
|
65
65
|
|
66
66
|
def fan_intermittent_off=(value)
|
67
67
|
return unless value >= 0 && value <= 40 && (value % 5).zero?
|
68
68
|
|
69
|
-
holding_registers[21_207 + (zone_number - 1) * 9] = value
|
69
|
+
holding_registers[21_207 + ((zone_number - 1) * 9)] = value
|
70
70
|
@fan_intermittent_off = value
|
71
71
|
end
|
72
72
|
|
@@ -74,7 +74,7 @@ module Aurora
|
|
74
74
|
return unless value >= 40 && value <= 90
|
75
75
|
|
76
76
|
raw_value = (value * 10).to_i
|
77
|
-
holding_registers[21_203 + (zone_number - 1) * 9] = raw_value
|
77
|
+
holding_registers[21_203 + ((zone_number - 1) * 9)] = raw_value
|
78
78
|
@heating_target_temperature = value
|
79
79
|
end
|
80
80
|
|
@@ -82,7 +82,7 @@ module Aurora
|
|
82
82
|
return unless value >= 54 && value <= 99
|
83
83
|
|
84
84
|
raw_value = (value * 10).to_i
|
85
|
-
holding_registers[21_204 + (zone_number - 1) * 9] = raw_value
|
85
|
+
holding_registers[21_204 + ((zone_number - 1) * 9)] = raw_value
|
86
86
|
@cooling_target_temperature = value
|
87
87
|
end
|
88
88
|
end
|
data/lib/aurora/mock_abc.rb
CHANGED
data/lib/aurora/modbus/slave.rb
CHANGED
@@ -4,14 +4,14 @@ module Aurora
|
|
4
4
|
module ModBus
|
5
5
|
module Slave
|
6
6
|
def read_multiple_holding_registers(*ranges)
|
7
|
-
values = if ranges.any?
|
7
|
+
values = if ranges.any?(Range)
|
8
8
|
addrs_and_lengths = ranges.map do |r|
|
9
9
|
r = Array(r)
|
10
10
|
[r.first, r.last - r.first + 1]
|
11
11
|
end.flatten
|
12
|
-
query("A#{addrs_and_lengths.pack(
|
12
|
+
query("A#{addrs_and_lengths.pack("n*")}").unpack("n*")
|
13
13
|
else
|
14
|
-
query("B#{ranges.pack(
|
14
|
+
query("B#{ranges.pack("n*")}").unpack("n*")
|
15
15
|
end
|
16
16
|
ranges.map { |r| Array(r) }.flatten.zip(values).to_h
|
17
17
|
end
|
data/lib/aurora/pump.rb
CHANGED
@@ -6,7 +6,7 @@ module Aurora
|
|
6
6
|
module Pump
|
7
7
|
class GenericPump < Component
|
8
8
|
attr_reader :type, :watts, :waterflow, :running
|
9
|
-
|
9
|
+
alias_method :running?, :running
|
10
10
|
|
11
11
|
def initialize(abc, type)
|
12
12
|
super(abc)
|
@@ -28,7 +28,7 @@ module Aurora
|
|
28
28
|
|
29
29
|
class VSPump < GenericPump
|
30
30
|
attr_reader :speed, :minimum_speed, :maximum_speed, :manual_control
|
31
|
-
|
31
|
+
alias_method :manual_control?, :manual_control
|
32
32
|
|
33
33
|
def registers_to_read
|
34
34
|
super + [321..325]
|
data/lib/aurora/registers.rb
CHANGED
@@ -108,7 +108,7 @@ module Aurora
|
|
108
108
|
48 => "EEV OD Comm Error", # Com with EEV is interupted EEV has gone independent mode
|
109
109
|
49 => "Cabinet Temperature Sensor", # Ambient Temperature (Tamb) is <-76 or > 212 F and out of range or invalid
|
110
110
|
51 => "Discharge Temp Sensor", # Discharge Sensor (Sd) is > 280 F or invalid (-76 to 392 F)
|
111
|
-
52 => "Suction
|
111
|
+
52 => "Suction Pressure Sensor", # Suction Pressure (P0) is invalid (0 to 232 psi)
|
112
112
|
53 => "Condensing Pressure Sensor", # Low condensing pressure (PD) or invalid (0 to 870 psi) Retry 10x.
|
113
113
|
54 => "Low Supply Voltage", # Supply Voltage is <180 V (190V to reset) or powered off/on too quickly (<30 sec.).
|
114
114
|
55 => "Out of Envelope", # Comp Operating out of envelope (P0) more than 90 sec. Retry 10x.
|
@@ -550,7 +550,7 @@ module Aurora
|
|
550
550
|
REGISTER_FORMATS = {
|
551
551
|
"%ds" => [1, 6, 9, 15, 84, 85, 110],
|
552
552
|
"%dV" => [16, 112, 3331, 3424, 3523],
|
553
|
-
"%0.1f
|
553
|
+
"%0.1f°F" => [19, 20, 401, 501, 502, 567, 740, 745, 746, 747, 900, 903,
|
554
554
|
1109, 1110, 1111, 1112, 1113, 1114, 1124, 1125, 1134, 1135, 1136,
|
555
555
|
3325, 3326, 3327, 3330, 3522, 3903, 3905, 3906,
|
556
556
|
12_619, 12_620,
|
@@ -587,9 +587,9 @@ module Aurora
|
|
587
587
|
|
588
588
|
def zone_registers
|
589
589
|
(1..6).map do |i|
|
590
|
-
base1 = 21_202 + (i - 1) * 9
|
591
|
-
base2 = 31_007 + (i - 1) * 3
|
592
|
-
base3 = 31_200 + (i - 1) * 3
|
590
|
+
base1 = 21_202 + ((i - 1) * 9)
|
591
|
+
base2 = 31_007 + ((i - 1) * 3)
|
592
|
+
base3 = 31_200 + ((i - 1) * 3)
|
593
593
|
{
|
594
594
|
base1 => "Zone #{i} Heating Mode (write)",
|
595
595
|
(base1 + 1) => "Zone #{i} Heating Setpoint (write)",
|
data/lib/aurora/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waterfurnace_aurora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.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: 2021-
|
11
|
+
date: 2021-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ccutrer-serialport
|
@@ -25,25 +25,25 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: mqtt-homeassistant
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
- - ">="
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 0.0.2
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
43
|
+
version: '0'
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 0.0.2
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: net-telnet-rfc2217
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,28 +98,56 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - "~>"
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
101
|
+
version: '11.0'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - "~>"
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: '
|
108
|
+
version: '11.0'
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: rubocop
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
113
|
- - "~>"
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version: '1.
|
115
|
+
version: '1.23'
|
116
116
|
type: :development
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
120
|
- - "~>"
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: '1.
|
122
|
+
version: '1.23'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: rubocop-performance
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '1.12'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '1.12'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: rubocop-rake
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0.6'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - "~>"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0.6'
|
123
151
|
description:
|
124
152
|
email: cody@cutrer.com'
|
125
153
|
executables:
|
@@ -157,7 +185,8 @@ files:
|
|
157
185
|
homepage: https://github.com/ccutrer/waterfurnace_aurora
|
158
186
|
licenses:
|
159
187
|
- MIT
|
160
|
-
metadata:
|
188
|
+
metadata:
|
189
|
+
rubygems_mfa_required: 'true'
|
161
190
|
post_install_message:
|
162
191
|
rdoc_options: []
|
163
192
|
require_paths:
|