balboa_worldwide_app 1.3.0 → 2.0.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/bwa_client +41 -0
- data/exe/bwa_mqtt_bridge +394 -0
- data/{bin → exe}/bwa_proxy +3 -2
- data/{bin → exe}/bwa_server +3 -2
- data/lib/balboa_worldwide_app.rb +3 -1
- data/lib/bwa/client.rb +121 -91
- data/lib/bwa/crc.rb +3 -1
- data/lib/bwa/discovery.rb +18 -17
- data/lib/bwa/logger.rb +9 -7
- data/lib/bwa/message.rb +67 -53
- data/lib/bwa/messages/configuration.rb +3 -1
- data/lib/bwa/messages/configuration_request.rb +3 -1
- data/lib/bwa/messages/control_configuration.rb +12 -9
- data/lib/bwa/messages/control_configuration_request.rb +13 -11
- data/lib/bwa/messages/filter_cycles.rb +50 -22
- data/lib/bwa/messages/ready.rb +3 -1
- data/lib/bwa/messages/{set_temperature.rb → set_target_temperature.rb} +5 -3
- data/lib/bwa/messages/set_temperature_scale.rb +5 -3
- data/lib/bwa/messages/set_time.rb +4 -2
- data/lib/bwa/messages/status.rb +51 -44
- data/lib/bwa/messages/toggle_item.rb +29 -27
- data/lib/bwa/proxy.rb +17 -18
- data/lib/bwa/server.rb +16 -14
- data/lib/bwa/version.rb +3 -1
- metadata +70 -24
- data/bin/bwa_client +0 -43
- data/bin/bwa_mqtt_bridge +0 -614
| @@ -1,14 +1,16 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class ControlConfiguration < Message
         | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x24".force_encoding(Encoding::ASCII_8BIT)
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x24").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 21
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_accessor :model, :version
         | 
| 8 10 |  | 
| 9 11 | 
             
                  def initialize
         | 
| 10 12 | 
             
                    super
         | 
| 11 | 
            -
                    @model =  | 
| 13 | 
            +
                    @model = ""
         | 
| 12 14 | 
             
                    @version = 0
         | 
| 13 15 | 
             
                  end
         | 
| 14 16 |  | 
| @@ -23,15 +25,17 @@ module BWA | |
| 23 25 | 
             
                end
         | 
| 24 26 |  | 
| 25 27 | 
             
                class ControlConfiguration2 < Message
         | 
| 26 | 
            -
                  MESSAGE_TYPE = "\xbf\x2e".force_encoding(Encoding::ASCII_8BIT)
         | 
| 28 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x2e").force_encoding(Encoding::ASCII_8BIT)
         | 
| 27 29 | 
             
                  MESSAGE_LENGTH = 6
         | 
| 28 30 |  | 
| 29 | 
            -
                  attr_accessor :pumps, :lights, : | 
| 31 | 
            +
                  attr_accessor :pumps, :lights, :circulation_pump, :blower, :mister, :aux
         | 
| 30 32 |  | 
| 31 33 | 
             
                  def initialize
         | 
| 34 | 
            +
                    super
         | 
| 35 | 
            +
             | 
| 32 36 | 
             
                    self.pumps = Array.new(6, 0)
         | 
| 33 37 | 
             
                    self.lights = Array.new(2, false)
         | 
| 34 | 
            -
                    self. | 
| 38 | 
            +
                    self.circulation_pump = false
         | 
| 35 39 | 
             
                    self.blower = 0
         | 
| 36 40 | 
             
                    self.mister = false
         | 
| 37 41 | 
             
                    self.aux = Array.new(2, false)
         | 
| @@ -51,7 +55,7 @@ module BWA | |
| 51 55 | 
             
                    lights[1] = ((flags >> 6) & 0x03 != 0)
         | 
| 52 56 | 
             
                    flags = data[3].ord
         | 
| 53 57 | 
             
                    self.blower = flags & 0x03
         | 
| 54 | 
            -
                    self. | 
| 58 | 
            +
                    self.circulation_pump = ((flags >> 6) & 0x03 != 0)
         | 
| 55 59 | 
             
                    flags = data[4].ord
         | 
| 56 60 | 
             
                    self.mister = (flags & 0x30 != 0)
         | 
| 57 61 | 
             
                    aux[0] = (flags & 0x01 != 0)
         | 
| @@ -59,17 +63,16 @@ module BWA | |
| 59 63 | 
             
                  end
         | 
| 60 64 |  | 
| 61 65 | 
             
                  def inspect
         | 
| 62 | 
            -
                    result = "#<BWA::Messages::ControlConfiguration2 "
         | 
| 63 66 | 
             
                    items = []
         | 
| 64 67 |  | 
| 65 68 | 
             
                    items << "pumps=#{pumps.inspect}"
         | 
| 66 69 | 
             
                    items << "lights=#{lights.inspect}"
         | 
| 67 | 
            -
                    items << " | 
| 70 | 
            +
                    items << "circulation_pump" if circulation_pump
         | 
| 68 71 | 
             
                    items << "blower=#{blower}" if blower != 0
         | 
| 69 72 | 
             
                    items << "mister" if mister
         | 
| 70 73 | 
             
                    items << "aux=#{aux.inspect}"
         | 
| 71 74 |  | 
| 72 | 
            -
                     | 
| 75 | 
            +
                    "#<BWA::Messages::ControlConfiguration2 #{items.join(" ")}>"
         | 
| 73 76 | 
             
                  end
         | 
| 74 77 | 
             
                end
         | 
| 75 78 | 
             
              end
         | 
| @@ -1,7 +1,9 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class ControlConfigurationRequest < Message
         | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x22".force_encoding(Encoding::ASCII_8BIT)
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x22").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 3
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_accessor :type
         | 
| @@ -13,20 +15,20 @@ module BWA | |
| 13 15 |  | 
| 14 16 | 
             
                  def parse(data)
         | 
| 15 17 | 
             
                    self.type = case data
         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 18 | 
            +
                                when "\x02\x00\x00" then 1
         | 
| 19 | 
            +
                                when "\x00\x00\x01" then 2
         | 
| 20 | 
            +
                                when "\x01\x00\x00" then 3
         | 
| 21 | 
            +
                                else 0
         | 
| 22 | 
            +
                                end
         | 
| 21 23 | 
             
                  end
         | 
| 22 24 |  | 
| 23 25 | 
             
                  def serialize
         | 
| 24 26 | 
             
                    data = case type
         | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 27 | 
            +
                           when 1 then "\x02\x00\x00"
         | 
| 28 | 
            +
                           when 2 then "\x00\x00\x01"
         | 
| 29 | 
            +
                           when 3 then "\x01\x00\x00"
         | 
| 30 | 
            +
                           else "\x00\x00\x00"
         | 
| 31 | 
            +
                           end
         | 
| 30 32 | 
             
                    super(data)
         | 
| 31 33 | 
             
                  end
         | 
| 32 34 |  | 
| @@ -1,39 +1,67 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class FilterCycles < Message
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 6 | 
            +
                  attr_accessor :cycle1_start_hour, :cycle1_start_minute, :cycle1_duration,
         | 
| 7 | 
            +
                                :cycle2_enabled, :cycle2_start_hour, :cycle2_start_minute, :cycle2_duration
         | 
| 8 | 
            +
                  alias_method :cycle2_enabled?, :cycle2_enabled
         | 
| 7 9 |  | 
| 8 | 
            -
                  MESSAGE_TYPE = "\xbf\x23".force_encoding(Encoding::ASCII_8BIT)
         | 
| 10 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x23").force_encoding(Encoding::ASCII_8BIT)
         | 
| 9 11 | 
             
                  MESSAGE_LENGTH = 8
         | 
| 10 12 |  | 
| 11 13 | 
             
                  def parse(data)
         | 
| 12 | 
            -
                     | 
| 13 | 
            -
                     | 
| 14 | 
            -
                     | 
| 15 | 
            -
                     | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 20 | 
            -
                     | 
| 21 | 
            -
                     | 
| 22 | 
            -
                     | 
| 14 | 
            +
                    self.cycle1_start_hour = data[0].ord
         | 
| 15 | 
            +
                    self.cycle1_start_minute = data[1].ord
         | 
| 16 | 
            +
                    hours = data[2].ord
         | 
| 17 | 
            +
                    minutes = data[3].ord
         | 
| 18 | 
            +
                    self.cycle1_duration = (hours * 60) + minutes
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    c2_hour = data[4].ord
         | 
| 21 | 
            +
                    self.cycle2_enabled = !!(c2_hour & 0x80 == 0x80)
         | 
| 22 | 
            +
                    self.cycle2_start_hour = c2_hour & 0x7f
         | 
| 23 | 
            +
                    self.cycle2_start_minute = data[5].ord
         | 
| 24 | 
            +
                    hours = data[6].ord
         | 
| 25 | 
            +
                    minutes = data[7].ord
         | 
| 26 | 
            +
                    self.cycle2_duration = (hours * 60) + minutes
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def serialize
         | 
| 30 | 
            +
                    data = cycle1_start_hour.chr
         | 
| 31 | 
            +
                    data += cycle1_start_minute.chr
         | 
| 32 | 
            +
                    data += (cycle1_duration / 60).chr
         | 
| 33 | 
            +
                    data += (cycle1_duration % 60).chr
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    # The cycle2 start hour is merged with the cycle2 enable.
         | 
| 36 | 
            +
                    # The high order bit of the byte is a flag to indicate this so we have
         | 
| 37 | 
            +
                    #  to do a bit of different processing to set that.
         | 
| 38 | 
            +
                    # Get the filter 2 start hour
         | 
| 39 | 
            +
                    start_hour = cycle2_start_hour
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    # Check to see if we want filter 2 enabled (either because it changed or from the current configuration)
         | 
| 42 | 
            +
                    start_hour |= 0x80 if cycle2_enabled
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    data += start_hour.chr
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    data += cycle2_start_minute.chr
         | 
| 47 | 
            +
                    data += (cycle2_duration / 60).chr
         | 
| 48 | 
            +
                    data += (cycle2_duration % 60).chr
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    super(data)
         | 
| 23 51 | 
             
                  end
         | 
| 24 52 |  | 
| 25 53 | 
             
                  def inspect
         | 
| 26 | 
            -
                    result = "#<BWA::Messages::FilterCycles "
         | 
| 54 | 
            +
                    result = +"#<BWA::Messages::FilterCycles "
         | 
| 27 55 |  | 
| 28 | 
            -
                    result << " | 
| 29 | 
            -
                    result << self.class.format_duration( | 
| 56 | 
            +
                    result << "cycle1 "
         | 
| 57 | 
            +
                    result << self.class.format_duration(cycle1_duration)
         | 
| 30 58 | 
             
                    result << "@"
         | 
| 31 | 
            -
                    result << self.class.format_time( | 
| 59 | 
            +
                    result << self.class.format_time(cycle1_start_hour, cycle1_start_minute)
         | 
| 32 60 |  | 
| 33 | 
            -
                    result << "  | 
| 34 | 
            -
                    result << self.class.format_duration( | 
| 61 | 
            +
                    result << " cycle2(#{@cycle2_enabled ? "enabled" : "disabled"}) "
         | 
| 62 | 
            +
                    result << self.class.format_duration(cycle2_duration)
         | 
| 35 63 | 
             
                    result << "@"
         | 
| 36 | 
            -
                    result << self.class.format_time( | 
| 64 | 
            +
                    result << self.class.format_time(cycle2_start_hour, cycle2_start_minute)
         | 
| 37 65 |  | 
| 38 66 | 
             
                    result << ">"
         | 
| 39 67 | 
             
                  end
         | 
    
        data/lib/bwa/messages/ready.rb
    CHANGED
    
    
| @@ -1,7 +1,9 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 | 
            -
                class  | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x20".force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 | 
            +
                class SetTargetTemperature < Message
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x20").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 1
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_accessor :temperature
         | 
| @@ -20,7 +22,7 @@ module BWA | |
| 20 22 | 
             
                  end
         | 
| 21 23 |  | 
| 22 24 | 
             
                  def inspect
         | 
| 23 | 
            -
                    "#<BWA::Messages:: | 
| 25 | 
            +
                    "#<BWA::Messages::SetTargetTemperature #{temperature}°>"
         | 
| 24 26 | 
             
                  end
         | 
| 25 27 | 
             
                end
         | 
| 26 28 | 
             
              end
         | 
| @@ -1,7 +1,9 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class SetTemperatureScale < Message
         | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x27".force_encoding(Encoding::ASCII_8BIT)
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x27").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 2
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_accessor :scale
         | 
| @@ -12,7 +14,7 @@ module BWA | |
| 12 14 | 
             
                  end
         | 
| 13 15 |  | 
| 14 16 | 
             
                  def parse(data)
         | 
| 15 | 
            -
                    self.scale = data[1].ord  | 
| 17 | 
            +
                    self.scale = data[1].ord.zero? ? :fahrenheit : :celsius
         | 
| 16 18 | 
             
                  end
         | 
| 17 19 |  | 
| 18 20 | 
             
                  def serialize
         | 
| @@ -22,7 +24,7 @@ module BWA | |
| 22 24 | 
             
                  end
         | 
| 23 25 |  | 
| 24 26 | 
             
                  def inspect
         | 
| 25 | 
            -
                    "#<BWA::Messages::SetTemperatureScale  | 
| 27 | 
            +
                    "#<BWA::Messages::SetTemperatureScale °#{scale.to_s[0].upcase}>"
         | 
| 26 28 | 
             
                  end
         | 
| 27 29 | 
             
                end
         | 
| 28 30 | 
             
              end
         | 
| @@ -1,7 +1,9 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class SetTime < Message
         | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x21".force_encoding(Encoding::ASCII_8BIT)
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x21").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 2
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_accessor :hour, :minute, :twenty_four_hour_time
         | 
| @@ -24,7 +26,7 @@ module BWA | |
| 24 26 | 
             
                  end
         | 
| 25 27 |  | 
| 26 28 | 
             
                  def inspect
         | 
| 27 | 
            -
                    "#<BWA::Messages::SetTime #{Status.format_time(hour, minute, twenty_four_hour_time)}>"
         | 
| 29 | 
            +
                    "#<BWA::Messages::SetTime #{Status.format_time(hour, minute, twenty_four_hour_time: twenty_four_hour_time)}>"
         | 
| 28 30 | 
             
                  end
         | 
| 29 31 | 
             
                end
         | 
| 30 32 | 
             
              end
         | 
    
        data/lib/bwa/messages/status.rb
    CHANGED
    
    | @@ -1,63 +1,72 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class Status < Message
         | 
| 4 6 | 
             
                  attr_accessor :hold,
         | 
| 5 7 | 
             
                                :priming,
         | 
| 6 8 | 
             
                                :heating_mode,
         | 
| 7 | 
            -
                                :temperature_scale,
         | 
| 8 9 | 
             
                                :twenty_four_hour_time,
         | 
| 9 | 
            -
                                : | 
| 10 | 
            +
                                :filter_cycles,
         | 
| 10 11 | 
             
                                :heating,
         | 
| 11 12 | 
             
                                :temperature_range,
         | 
| 12 13 | 
             
                                :hour, :minute,
         | 
| 13 | 
            -
                                : | 
| 14 | 
            +
                                :circulation_pump,
         | 
| 14 15 | 
             
                                :blower,
         | 
| 15 16 | 
             
                                :pumps,
         | 
| 16 17 | 
             
                                :lights,
         | 
| 17 18 | 
             
                                :mister,
         | 
| 18 19 | 
             
                                :aux,
         | 
| 19 | 
            -
                                :current_temperature, | 
| 20 | 
            +
                                :current_temperature,
         | 
| 21 | 
            +
                                :target_temperature
         | 
| 22 | 
            +
                  attr_reader :temperature_scale
         | 
| 23 | 
            +
                  alias_method :hold?, :hold
         | 
| 24 | 
            +
                  alias_method :priming?, :priming
         | 
| 25 | 
            +
                  alias_method :twenty_four_hour_time?, :twenty_four_hour_time
         | 
| 26 | 
            +
                  alias_method :heating?, :heating
         | 
| 20 27 |  | 
| 21 | 
            -
                  MESSAGE_TYPE = "\xaf\x13".force_encoding(Encoding::ASCII_8BIT)
         | 
| 28 | 
            +
                  MESSAGE_TYPE = (+"\xaf\x13").force_encoding(Encoding::ASCII_8BIT)
         | 
| 22 29 | 
             
                  # additional features have been added in later versions
         | 
| 23 | 
            -
                  MESSAGE_LENGTH = 24..32
         | 
| 30 | 
            +
                  MESSAGE_LENGTH = (24..32).freeze
         | 
| 24 31 |  | 
| 25 32 | 
             
                  def initialize
         | 
| 33 | 
            +
                    super
         | 
| 34 | 
            +
             | 
| 26 35 | 
             
                    @src = 0xff
         | 
| 27 36 | 
             
                    self.hold = false
         | 
| 28 37 | 
             
                    self.priming = false
         | 
| 29 38 | 
             
                    self.heating_mode = :ready
         | 
| 30 39 | 
             
                    @temperature_scale = :fahrenheit
         | 
| 31 40 | 
             
                    self.twenty_four_hour_time = false
         | 
| 32 | 
            -
                    self. | 
| 41 | 
            +
                    self.filter_cycles = Array.new(2, false)
         | 
| 33 42 | 
             
                    self.heating = false
         | 
| 34 43 | 
             
                    self.temperature_range = :high
         | 
| 35 44 | 
             
                    self.hour = self.minute = 0
         | 
| 36 | 
            -
                    self. | 
| 45 | 
            +
                    self.circulation_pump = false
         | 
| 37 46 | 
             
                    self.pumps = Array.new(6, 0)
         | 
| 38 47 | 
             
                    self.lights = Array.new(2, false)
         | 
| 39 48 | 
             
                    self.mister = false
         | 
| 40 49 | 
             
                    self.aux = Array.new(2, false)
         | 
| 41 | 
            -
                    self. | 
| 50 | 
            +
                    self.target_temperature = 100
         | 
| 42 51 | 
             
                  end
         | 
| 43 52 |  | 
| 44 53 | 
             
                  def parse(data)
         | 
| 45 54 | 
             
                    flags = data[0].ord
         | 
| 46 | 
            -
                    self.hold = (flags & 0x05 != 0 | 
| 55 | 
            +
                    self.hold = (flags & 0x05 != 0)
         | 
| 47 56 |  | 
| 48 57 | 
             
                    flags = data[1].ord
         | 
| 49 58 | 
             
                    self.priming = (flags & 0x01 == 0x01)
         | 
| 50 59 | 
             
                    flags = data[5].ord
         | 
| 51 60 | 
             
                    self.heating_mode = case flags & 0x03
         | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 61 | 
            +
                                        when 0x00 then :ready
         | 
| 62 | 
            +
                                        when 0x01 then :rest
         | 
| 63 | 
            +
                                        when 0x02 then :ready_in_rest
         | 
| 55 64 | 
             
                                        end
         | 
| 56 65 | 
             
                    flags = data[9].ord
         | 
| 57 66 | 
             
                    self.temperature_scale = (flags & 0x01 == 0x01) ? :celsius : :fahrenheit
         | 
| 58 67 | 
             
                    self.twenty_four_hour_time = (flags & 0x02 == 0x02)
         | 
| 59 | 
            -
                     | 
| 60 | 
            -
                     | 
| 68 | 
            +
                    filter_cycles[0] = (flags & 0x04 != 0)
         | 
| 69 | 
            +
                    filter_cycles[1] = (flags & 0x08 != 0)
         | 
| 61 70 | 
             
                    flags = data[10].ord
         | 
| 62 71 | 
             
                    self.heating = (flags & 0x30 != 0)
         | 
| 63 72 | 
             
                    self.temperature_range = (flags & 0x04 == 0x04) ? :high : :low
         | 
| @@ -71,7 +80,7 @@ module BWA | |
| 71 80 | 
             
                    pumps[5] = (flags >> 2) & 0x03
         | 
| 72 81 |  | 
| 73 82 | 
             
                    flags = data[13].ord
         | 
| 74 | 
            -
                    self. | 
| 83 | 
            +
                    self.circulation_pump = (flags & 0x02 == 0x02)
         | 
| 75 84 | 
             
                    self.blower = (flags & 0x0C == 0x0C)
         | 
| 76 85 | 
             
                    flags = data[14].ord
         | 
| 77 86 | 
             
                    lights[0] = (flags & 0x03 != 0)
         | 
| @@ -83,23 +92,22 @@ module BWA | |
| 83 92 | 
             
                    self.hour = data[3].ord
         | 
| 84 93 | 
             
                    self.minute = data[4].ord
         | 
| 85 94 | 
             
                    self.current_temperature = data[2].ord
         | 
| 86 | 
            -
                    self.current_temperature = nil if  | 
| 87 | 
            -
                    self. | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
                     | 
| 95 | 
            +
                    self.current_temperature = nil if current_temperature == 0xff
         | 
| 96 | 
            +
                    self.target_temperature = data[20].ord
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    return unless temperature_scale == :celsius
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    self.current_temperature /= 2.0 if current_temperature
         | 
| 101 | 
            +
                    self.target_temperature /= 2.0 if target_temperature
         | 
| 92 102 | 
             
                  end
         | 
| 93 103 |  | 
| 94 104 | 
             
                  def serialize
         | 
| 95 105 | 
             
                    data = "\x00" * 24
         | 
| 96 106 | 
             
                    data[0] = (hold ? 0x05 : 0x00).chr
         | 
| 97 107 | 
             
                    data[1] = (priming ? 0x01 : 0x00).chr
         | 
| 98 | 
            -
                    data[5] =  | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
                                 when :ready_in_rest; 0x02
         | 
| 102 | 
            -
                               end).chr
         | 
| 108 | 
            +
                    data[5] = { ready: 0x00,
         | 
| 109 | 
            +
                                rest: 0x01,
         | 
| 110 | 
            +
                                ready_in_rest: 0x02 }[heating_mode].chr
         | 
| 103 111 | 
             
                    flags = 0
         | 
| 104 112 | 
             
                    flags |= 0x01 if temperature_scale == :celsius
         | 
| 105 113 | 
             
                    flags |= 0x02 if twenty_four_hour_time
         | 
| @@ -113,7 +121,7 @@ module BWA | |
| 113 121 | 
             
                    flags |= pump2 * 4
         | 
| 114 122 | 
             
                    data[11] = flags.chr
         | 
| 115 123 | 
             
                    flags = 0
         | 
| 116 | 
            -
                    flags |= 0x02 if  | 
| 124 | 
            +
                    flags |= 0x02 if circulation_pump
         | 
| 117 125 | 
             
                    data[13] = flags.chr
         | 
| 118 126 | 
             
                    flags = 0
         | 
| 119 127 | 
             
                    flags |= 0x03 if light1
         | 
| @@ -122,10 +130,10 @@ module BWA | |
| 122 130 | 
             
                    data[4] = minute.chr
         | 
| 123 131 | 
             
                    if temperature_scale == :celsius
         | 
| 124 132 | 
             
                      data[2] = (current_temperature ? (current_temperature * 2).to_i : 0xff).chr
         | 
| 125 | 
            -
                      data[20] = ( | 
| 133 | 
            +
                      data[20] = (target_temperature * 2).to_i.chr
         | 
| 126 134 | 
             
                    else
         | 
| 127 135 | 
             
                      data[2] = (current_temperature.to_i || 0xff).chr
         | 
| 128 | 
            -
                      data[20] =  | 
| 136 | 
            +
                      data[20] = target_temperature.to_i.chr
         | 
| 129 137 | 
             
                    end
         | 
| 130 138 |  | 
| 131 139 | 
             
                    super(data)
         | 
| @@ -135,47 +143,46 @@ module BWA | |
| 135 143 | 
             
                    if value != @temperature_scale
         | 
| 136 144 | 
             
                      if value == :fahrenheit
         | 
| 137 145 | 
             
                        if current_temperature
         | 
| 138 | 
            -
                          self.current_temperature *= 9.0/5
         | 
| 146 | 
            +
                          self.current_temperature *= 9.0 / 5
         | 
| 139 147 | 
             
                          self.current_temperature += 32
         | 
| 140 148 | 
             
                          self.current_temperature = current_temperature.round
         | 
| 141 149 | 
             
                        end
         | 
| 142 | 
            -
                        self. | 
| 143 | 
            -
                        self. | 
| 144 | 
            -
                        self. | 
| 150 | 
            +
                        self.target_temperature *= 9.0 / 5
         | 
| 151 | 
            +
                        self.target_temperature += 32
         | 
| 152 | 
            +
                        self.target_temperature = target_temperature.round
         | 
| 145 153 | 
             
                      else
         | 
| 146 154 | 
             
                        if current_temperature
         | 
| 147 155 | 
             
                          self.current_temperature -= 32
         | 
| 148 | 
            -
                          self.current_temperature *= 5.0/90
         | 
| 156 | 
            +
                          self.current_temperature *= 5.0 / 90
         | 
| 149 157 | 
             
                          self.current_temperature = (current_temperature * 2).round / 2.0
         | 
| 150 158 | 
             
                        end
         | 
| 151 | 
            -
                        self. | 
| 152 | 
            -
                        self. | 
| 153 | 
            -
                        self. | 
| 159 | 
            +
                        self.target_temperature -= 32
         | 
| 160 | 
            +
                        self.target_temperature *= 5.0 / 9
         | 
| 161 | 
            +
                        self.target_temperature = (target_temperature * 2).round / 2.0
         | 
| 154 162 | 
             
                      end
         | 
| 155 163 | 
             
                    end
         | 
| 156 164 | 
             
                    @temperature_scale = value
         | 
| 157 165 | 
             
                  end
         | 
| 158 166 |  | 
| 159 167 | 
             
                  def inspect
         | 
| 160 | 
            -
                    result = "#<BWA::Messages::Status "
         | 
| 161 168 | 
             
                    items = []
         | 
| 162 169 |  | 
| 163 170 | 
             
                    items << "hold" if hold
         | 
| 164 171 | 
             
                    items << "priming" if priming
         | 
| 165 | 
            -
                    items << self.class.format_time(hour, minute, twenty_four_hour_time)
         | 
| 166 | 
            -
                    items << "#{current_temperature ||  | 
| 167 | 
            -
                    items << " | 
| 172 | 
            +
                    items << self.class.format_time(hour, minute, twenty_four_hour_time: twenty_four_hour_time)
         | 
| 173 | 
            +
                    items << "#{current_temperature || "--"}/#{target_temperature}°#{temperature_scale.to_s[0].upcase}"
         | 
| 174 | 
            +
                    items << "filter_cycles=#{filter_cycles.inspect}"
         | 
| 168 175 | 
             
                    items << heating_mode
         | 
| 169 176 | 
             
                    items << "heating" if heating
         | 
| 170 177 | 
             
                    items << temperature_range
         | 
| 171 | 
            -
                    items << " | 
| 178 | 
            +
                    items << "circulation_pump" if circulation_pump
         | 
| 172 179 | 
             
                    items << "blower" if blower
         | 
| 173 180 | 
             
                    items << "pumps=#{pumps.inspect}"
         | 
| 174 181 | 
             
                    items << "lights=#{lights.inspect}"
         | 
| 175 182 | 
             
                    items << "aux=#{aux.inspect}"
         | 
| 176 183 | 
             
                    items << "mister" if mister
         | 
| 177 184 |  | 
| 178 | 
            -
                     | 
| 185 | 
            +
                    "#<BWA::Messages::Status #{items.join(" ")}>"
         | 
| 179 186 | 
             
                  end
         | 
| 180 187 | 
             
                end
         | 
| 181 188 | 
             
              end
         | 
| @@ -1,8 +1,29 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module BWA
         | 
| 2 4 | 
             
              module Messages
         | 
| 3 5 | 
             
                class ToggleItem < Message
         | 
| 4 | 
            -
                  MESSAGE_TYPE = "\xbf\x11".force_encoding(Encoding::ASCII_8BIT)
         | 
| 6 | 
            +
                  MESSAGE_TYPE = (+"\xbf\x11").force_encoding(Encoding::ASCII_8BIT)
         | 
| 5 7 | 
             
                  MESSAGE_LENGTH = 2
         | 
| 8 | 
            +
                  ITEMS = {
         | 
| 9 | 
            +
                    normal_operation: 0x01,
         | 
| 10 | 
            +
                    clear_notification: 0x03,
         | 
| 11 | 
            +
                    pump1: 0x04,
         | 
| 12 | 
            +
                    pump2: 0x05,
         | 
| 13 | 
            +
                    pump3: 0x06,
         | 
| 14 | 
            +
                    pump4: 0x07,
         | 
| 15 | 
            +
                    pump5: 0x08,
         | 
| 16 | 
            +
                    pump6: 0x09,
         | 
| 17 | 
            +
                    blower: 0x0c,
         | 
| 18 | 
            +
                    mister: 0x0e,
         | 
| 19 | 
            +
                    light1: 0x11,
         | 
| 20 | 
            +
                    light2: 0x12,
         | 
| 21 | 
            +
                    aux1: 0x16,
         | 
| 22 | 
            +
                    aux2: 0x17,
         | 
| 23 | 
            +
                    hold: 0x3c,
         | 
| 24 | 
            +
                    temperature_range: 0x50,
         | 
| 25 | 
            +
                    heating_mode: 0x51
         | 
| 26 | 
            +
                  }.freeze
         | 
| 6 27 |  | 
| 7 28 | 
             
                  attr_accessor :item
         | 
| 8 29 |  | 
| @@ -12,35 +33,16 @@ module BWA | |
| 12 33 | 
             
                  end
         | 
| 13 34 |  | 
| 14 35 | 
             
                  def parse(data)
         | 
| 15 | 
            -
                    self.item =  | 
| 16 | 
            -
                                  when 0x04; :pump1
         | 
| 17 | 
            -
                                  when 0x05; :pump2
         | 
| 18 | 
            -
                                  when 0x0c; :blower
         | 
| 19 | 
            -
                                  when 0x0e; :mister
         | 
| 20 | 
            -
                                  when 0x11; :light1
         | 
| 21 | 
            -
                                  when 0x3c; :hold
         | 
| 22 | 
            -
                                  when 0x50; :temperature_range
         | 
| 23 | 
            -
                                  when 0x51; :heating_mode
         | 
| 24 | 
            -
                                  else; data[0].ord
         | 
| 25 | 
            -
                                end
         | 
| 36 | 
            +
                    self.item = ITEMS.invert[data[0].ord] || data[0].ord
         | 
| 26 37 | 
             
                  end
         | 
| 27 38 |  | 
| 28 39 | 
             
                  def serialize
         | 
| 29 | 
            -
                    data = "\x00\x00"
         | 
| 30 | 
            -
                    if item.is_a? Integer
         | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                                  when :pump2; 0x05
         | 
| 36 | 
            -
                                  when :blower; 0x0c
         | 
| 37 | 
            -
                                  when :mister; 0x0e
         | 
| 38 | 
            -
                                  when :light1; 0x11
         | 
| 39 | 
            -
                                  when :hold; 0x3c
         | 
| 40 | 
            -
                                  when :temperature_range; 0x50
         | 
| 41 | 
            -
                                  when :heating_mode; 0x51
         | 
| 42 | 
            -
                                end).chr
         | 
| 43 | 
            -
                    end
         | 
| 40 | 
            +
                    data = +"\x00\x00"
         | 
| 41 | 
            +
                    data[0] = if item.is_a? Integer
         | 
| 42 | 
            +
                                item.chr
         | 
| 43 | 
            +
                              else
         | 
| 44 | 
            +
                                ITEMS[item].chr
         | 
| 45 | 
            +
                              end
         | 
| 44 46 | 
             
                    super(data)
         | 
| 45 47 | 
             
                  end
         | 
| 46 48 |  | 
    
        data/lib/bwa/proxy.rb
    CHANGED
    
    | @@ -1,32 +1,31 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
            require  | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "socket"
         | 
| 4 | 
            +
            require "bwa/logger"
         | 
| 5 | 
            +
            require "bwa/message"
         | 
| 4 6 |  | 
| 5 7 | 
             
            module BWA
         | 
| 6 8 | 
             
              class Proxy
         | 
| 7 | 
            -
                def initialize(host, port: 4257 | 
| 9 | 
            +
                def initialize(host, port: 4257)
         | 
| 8 10 | 
             
                  @host, @port = host, port
         | 
| 9 11 | 
             
                  @listen_socket = TCPServer.open(port)
         | 
| 10 12 | 
             
                end
         | 
| 11 13 |  | 
| 12 14 | 
             
                def run
         | 
| 13 | 
            -
                   | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                     | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                     | 
| 20 | 
            -
                      shuffle_messages(server_socket, client_socket, "Server")
         | 
| 21 | 
            -
                    end
         | 
| 22 | 
            -
                    t1.join
         | 
| 23 | 
            -
                    t2.join
         | 
| 24 | 
            -
                    break
         | 
| 15 | 
            +
                  client_socket = @listen_socket.accept
         | 
| 16 | 
            +
                  server_socket = TCPSocket.new(@host, @port)
         | 
| 17 | 
            +
                  t1 = Thread.new do
         | 
| 18 | 
            +
                    shuffle_messages(client_socket, server_socket, "Client")
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                  t2 = Thread.new do
         | 
| 21 | 
            +
                    shuffle_messages(server_socket, client_socket, "Server")
         | 
| 25 22 | 
             
                  end
         | 
| 23 | 
            +
                  t1.join
         | 
| 24 | 
            +
                  t2.join
         | 
| 26 25 | 
             
                end
         | 
| 27 26 |  | 
| 28 27 | 
             
                def shuffle_messages(socket1, socket2, tag)
         | 
| 29 | 
            -
                  leftover_data = "".force_encoding(Encoding::ASCII_8BIT)
         | 
| 28 | 
            +
                  leftover_data = (+"").force_encoding(Encoding::ASCII_8BIT)
         | 
| 30 29 | 
             
                  loop do
         | 
| 31 30 | 
             
                    if leftover_data.length < 2 || leftover_data.length < leftover_data[1].ord + 2
         | 
| 32 31 | 
             
                      begin
         | 
| @@ -42,7 +41,7 @@ module BWA | |
| 42 41 | 
             
                    end
         | 
| 43 42 | 
             
                    data_length = leftover_data[1].ord
         | 
| 44 43 | 
             
                    data = leftover_data[0...(data_length + 2)]
         | 
| 45 | 
            -
                    leftover_data = leftover_data[(data_length + 2)..-1] ||  | 
| 44 | 
            +
                    leftover_data = leftover_data[(data_length + 2)..-1] || ""
         | 
| 46 45 | 
             
                    begin
         | 
| 47 46 | 
             
                      message = Message.parse(data)
         | 
| 48 47 | 
             
                      BWA.logger.info "#{tag}: #{message.inspect}"
         |