Class: BWA::Client

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/bwa/client.rb

Constant Summary collapse

HEATING_MODES =
%I[ready rest ready_in_rest].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri) ⇒ Client

Returns a new instance of Client.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/bwa/client.rb', line 36

def initialize(uri)
  uri = URI.parse(uri)
  case uri.scheme
  when "tcp"
    require "socket"
    @io = TCPSocket.new(uri.host, uri.port || 4257)
  when "telnet", "rfc2217"
    require "net/telnet/rfc2217"
    @io = Net::Telnet::RFC2217.new("Host" => uri.host, "Port" => uri.port || 23, "baud" => 115_200)
    @queue = []
  else
    require "ccutrer-serialport"
    @io = CCutrer::SerialPort.new(uri.path, baud: 115_200)
    @queue = []
  end
  @src = 0x0a
  @buffer = +""
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration.



13
14
15
# File 'lib/bwa/client.rb', line 13

def configuration
  @configuration
end

#control_configurationObject (readonly)

Returns the value of attribute control_configuration.



13
14
15
# File 'lib/bwa/client.rb', line 13

def control_configuration
  @control_configuration
end

#filter_cyclesObject (readonly)

Returns the value of attribute filter_cycles.



13
14
15
# File 'lib/bwa/client.rb', line 13

def filter_cycles
  @filter_cycles
end

#statusObject (readonly)

Returns the value of attribute status.



13
14
15
# File 'lib/bwa/client.rb', line 13

def status
  @status
end

Instance Method Details

#blower=(desired) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/bwa/client.rb', line 197

def blower=(desired)
  return unless status && configuration

  desired = 0 if desired == false
  desired = configuration.blower if desired == true
  desired = [desired, configuration.blower].min
  times = (desired - status.blower) % (configuration.blower + 1)
  times.times do
    toggle_blower
    sleep(0.1)
  end
end

#drain_message_queueObject



101
102
103
# File 'lib/bwa/client.rb', line 101

def drain_message_queue
  poll while messages_pending?
end

#full_configuration?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/bwa/client.rb', line 55

def full_configuration?
  status && control_configuration && configuration && filter_cycles
end

#heating_mode=(desired) ⇒ Object

Raises:

  • (ArgumentError)


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/bwa/client.rb', line 259

def heating_mode=(desired)
  raise ArgumentError, "heating_mode must be :ready or :rest" unless %I[ready rest].include?(desired)
  return unless status

  times = if (status.heating_mode == :ready && desired == :rest) ||
             (status.heating_mode == :rest && desired == :ready) ||
             (status.heating_mode == :ready_in_rest && desired == :rest)
            1
          elsif status.heating_mode == :ready_in_rest && desired == :ready
            2
          else
            0
          end
  times.times { toggle_heating_mode }
end

#hold=(desired) ⇒ Object



210
211
212
213
214
215
# File 'lib/bwa/client.rb', line 210

def hold=(desired)
  return unless status
  return if status.hold == desired

  toggle_hold
end

#messages_pending?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/bwa/client.rb', line 97

def messages_pending?
  !!@io.wait_readable(0)
end

#mister=(desired) ⇒ Object



190
191
192
193
194
195
# File 'lib/bwa/client.rb', line 190

def mister=(desired)
  return unless status
  return if status.mister == desired

  toggle_mister
end

#pollObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/bwa/client.rb', line 59

def poll
  message = bytes_read = nil
  loop do
    message, bytes_read = Message.parse(@buffer)
    # discard how much we read
    @buffer = @buffer[bytes_read..-1] if bytes_read
    method = @io.respond_to?(:readpartial) ? :readpartial : :read
    unless message
      # one EOF is just serial ports saying they have no data;
      # several EOFs in a row is the file is dead and gone
      eofs = 0
      begin
        @buffer.concat(@io.__send__(method, 64 * 1024))
      rescue EOFError
        eofs += 1
        raise if eofs == 5

        @io.wait_readable
        retry
      end
      next
    end
    break
  end

  if message.is_a?(Messages::Ready) && (msg = @queue&.shift)
    unless BWA.verbosity < 1 && msg[3..4] == Messages::ControlConfigurationRequest::MESSAGE_TYPE
      BWA.logger.debug "wrote: #{BWA.raw2str(msg)}"
    end
    @io.write(msg)
  end
  @status = message.dup if message.is_a?(Messages::Status)
  @filter_cycles = message.dup if message.is_a?(Messages::FilterCycles)
  @control_configuration = message.dup if message.is_a?(Messages::ControlConfiguration)
  @configuration = message.dup if message.is_a?(Messages::ControlConfiguration2)
  message
end

#request_configurationObject



121
122
123
# File 'lib/bwa/client.rb', line 121

def request_configuration
  send_message(Messages::ConfigurationRequest.new)
end

#request_control_infoObject



129
130
131
# File 'lib/bwa/client.rb', line 129

def request_control_info
  send_message(Messages::ControlConfigurationRequest.new(1))
end

#request_control_info2Object



125
126
127
# File 'lib/bwa/client.rb', line 125

def request_control_info2
  send_message(Messages::ControlConfigurationRequest.new(2))
end

#request_filter_configurationObject



133
134
135
# File 'lib/bwa/client.rb', line 133

def request_filter_configuration
  send_message(Messages::ControlConfigurationRequest.new(3))
end

#send_message(message) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/bwa/client.rb', line 105

def send_message(message)
  message.src = @src
  full_message = message.serialize
  unless BWA.verbosity < 1 && message.is_a?(Messages::ControlConfigurationRequest)
    BWA.logger.info "  to spa: #{message.inspect}"
  end
  if @queue
    @queue.push(full_message)
  else
    unless BWA.verbosity < 1 && message.is_a?(Messages::ControlConfigurationRequest)
      BWA.logger.debug "wrote: #{BWA.raw2str(full_message)}"
    end
    @io.write(full_message)
  end
end

#set_pump(index, desired) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/bwa/client.rb', line 165

def set_pump(index, desired)
  return unless status && configuration

  desired = 0 if desired == false
  desired = configuration.pumps[index] if desired == true
  desired = [desired, configuration.pumps[index]].min
  times = (desired - status.pumps[index]) % (configuration.pumps[index] + 1)
  times.times do
    toggle_pump(index)
    sleep(0.1)
  end
end

#set_time(hour, minute, twenty_four_hour_time: false) ⇒ Object



227
228
229
# File 'lib/bwa/client.rb', line 227

def set_time(hour, minute, twenty_four_hour_time: false)
  send_message(Messages::SetTime.new(hour, minute, twenty_four_hour_time))
end

#target_temperature=(desired) ⇒ Object

high range is 80-106 for F, 26-40 for C (by 0.5) low range is 50-99 for F, 10-26 for C (by 0.5)



219
220
221
222
223
224
225
# File 'lib/bwa/client.rb', line 219

def target_temperature=(desired)
  return unless status
  return if status.target_temperature == desired

  desired *= 2 if (status && status.temperature_scale == :celsius) || desired < 50
  send_message(Messages::SetTargetTemperature.new(desired.round))
end

#temperature_range=(desired) ⇒ Object



247
248
249
250
251
252
# File 'lib/bwa/client.rb', line 247

def temperature_range=(desired)
  return unless status
  return if status.temperature_range == desired

  toggle_temperature_range
end

#temperature_scale=(scale) ⇒ Object

Raises:

  • (ArgumentError)


231
232
233
234
235
# File 'lib/bwa/client.rb', line 231

def temperature_scale=(scale)
  raise ArgumentError, "scale must be :fahrenheit or :celsius" unless %I[fahrenheit celsius].include?(scale)

  send_message(Messages::SetTemperatureScale.new(scale))
end

#toggle_aux(index) ⇒ Object



149
150
151
# File 'lib/bwa/client.rb', line 149

def toggle_aux(index)
  toggle_item(index + 0x16)
end

#toggle_blowerObject



157
158
159
# File 'lib/bwa/client.rb', line 157

def toggle_blower
  toggle_item(:blower)
end

#toggle_heating_modeObject



254
255
256
# File 'lib/bwa/client.rb', line 254

def toggle_heating_mode
  toggle_item(:heating_mode)
end

#toggle_holdObject



161
162
163
# File 'lib/bwa/client.rb', line 161

def toggle_hold
  toggle_item(:hold)
end

#toggle_item(item) ⇒ Object



137
138
139
# File 'lib/bwa/client.rb', line 137

def toggle_item(item)
  send_message(Messages::ToggleItem.new(item))
end

#toggle_light(index) ⇒ Object



145
146
147
# File 'lib/bwa/client.rb', line 145

def toggle_light(index)
  toggle_item(index + 0x11)
end

#toggle_misterObject



153
154
155
# File 'lib/bwa/client.rb', line 153

def toggle_mister
  toggle_item(:mister)
end

#toggle_pump(index) ⇒ Object



141
142
143
# File 'lib/bwa/client.rb', line 141

def toggle_pump(index)
  toggle_item(index + 0x04)
end

#toggle_temperature_rangeObject



243
244
245
# File 'lib/bwa/client.rb', line 243

def toggle_temperature_range
  toggle_item(0x50)
end

#update_filter_cycles(new_filter_cycles) ⇒ Object



237
238
239
240
241
# File 'lib/bwa/client.rb', line 237

def update_filter_cycles(new_filter_cycles)
  send_message(new_filter_cycles)
  @filter_cycles = new_filter_cycles.dup
  request_filter_configuration
end