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



191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/bwa/client.rb', line 191

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



95
96
97
# File 'lib/bwa/client.rb', line 95

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)


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/bwa/client.rb', line 253

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



204
205
206
207
208
209
# File 'lib/bwa/client.rb', line 204

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

  toggle_hold
end

#messages_pending?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/bwa/client.rb', line 91

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

#mister=(desired) ⇒ Object



184
185
186
187
188
189
# File 'lib/bwa/client.rb', line 184

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
# 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
      begin
        @buffer.concat(@io.__send__(method, 64 * 1024))
      rescue EOFError
        @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



115
116
117
# File 'lib/bwa/client.rb', line 115

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

#request_control_infoObject



123
124
125
# File 'lib/bwa/client.rb', line 123

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

#request_control_info2Object



119
120
121
# File 'lib/bwa/client.rb', line 119

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

#request_filter_configurationObject



127
128
129
# File 'lib/bwa/client.rb', line 127

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

#send_message(message) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/bwa/client.rb', line 99

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



159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/bwa/client.rb', line 159

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



221
222
223
# File 'lib/bwa/client.rb', line 221

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)



213
214
215
216
217
218
219
# File 'lib/bwa/client.rb', line 213

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



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

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

  toggle_temperature_range
end

#temperature_scale=(scale) ⇒ Object

Raises:

  • (ArgumentError)


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

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



143
144
145
# File 'lib/bwa/client.rb', line 143

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

#toggle_blowerObject



151
152
153
# File 'lib/bwa/client.rb', line 151

def toggle_blower
  toggle_item(:blower)
end

#toggle_heating_modeObject



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

def toggle_heating_mode
  toggle_item(:heating_mode)
end

#toggle_holdObject



155
156
157
# File 'lib/bwa/client.rb', line 155

def toggle_hold
  toggle_item(:hold)
end

#toggle_item(item) ⇒ Object



131
132
133
# File 'lib/bwa/client.rb', line 131

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

#toggle_light(index) ⇒ Object



139
140
141
# File 'lib/bwa/client.rb', line 139

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

#toggle_misterObject



147
148
149
# File 'lib/bwa/client.rb', line 147

def toggle_mister
  toggle_item(:mister)
end

#toggle_pump(index) ⇒ Object



135
136
137
# File 'lib/bwa/client.rb', line 135

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

#toggle_temperature_rangeObject



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

def toggle_temperature_range
  toggle_item(0x50)
end

#update_filter_cycles(new_filter_cycles) ⇒ Object



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

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