somfy_sdn 2.1.5 → 2.2.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/somfy_sdn +69 -0
- data/lib/sdn/cli/mqtt/group.rb +12 -10
- data/lib/sdn/cli/mqtt/motor.rb +19 -14
- data/lib/sdn/cli/mqtt/p_queue.rb +18 -0
- data/lib/sdn/cli/mqtt/read.rb +125 -126
- data/lib/sdn/cli/mqtt/subscriptions.rb +186 -140
- data/lib/sdn/cli/mqtt/write.rb +39 -34
- data/lib/sdn/cli/mqtt.rb +84 -53
- data/lib/sdn/cli/provisioner.rb +56 -33
- data/lib/sdn/cli/simulator.rb +99 -65
- data/lib/sdn/client.rb +38 -24
- data/lib/sdn/message/control.rb +60 -30
- data/lib/sdn/message/get.rb +6 -2
- data/lib/sdn/message/helpers.rb +23 -22
- data/lib/sdn/message/ilt2/get.rb +6 -3
- data/lib/sdn/message/ilt2/master_control.rb +10 -7
- data/lib/sdn/message/ilt2/post.rb +7 -5
- data/lib/sdn/message/ilt2/set.rb +28 -19
- data/lib/sdn/message/post.rb +3 -5
- data/lib/sdn/message/set.rb +48 -22
- data/lib/sdn/message.rb +50 -34
- data/lib/sdn/version.rb +3 -1
- data/lib/sdn.rb +18 -12
- data/lib/somfy_sdn.rb +3 -1
- metadata +43 -13
- data/bin/somfy_sdn +0 -60
| @@ -1,153 +1,199 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module SDN
         | 
| 2 4 | 
             
              module CLI
         | 
| 3 5 | 
             
                class MQTT
         | 
| 4 6 | 
             
                  module Subscriptions
         | 
| 5 7 | 
             
                    def handle_message(topic, value)
         | 
| 6 | 
            -
                      SDN.logger.info " | 
| 7 | 
            -
                       | 
| 8 | 
            -
             | 
| 9 | 
            -
                        property | 
| 10 | 
            -
                         | 
| 11 | 
            -
                         | 
| 12 | 
            -
                         | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
                         | 
| 16 | 
            -
                         | 
| 17 | 
            -
                         | 
| 18 | 
            -
                         | 
| 19 | 
            -
                         | 
| 20 | 
            -
                         | 
| 21 | 
            -
             | 
| 22 | 
            -
                         | 
| 8 | 
            +
                      SDN.logger.info "Got #{value.inspect} at #{topic}"
         | 
| 9 | 
            +
                      unless (match = topic.match(%r{^#{Regexp.escape(@base_topic)}/
         | 
| 10 | 
            +
                      (?<addr>\h{6})/
         | 
| 11 | 
            +
                        (?<property>discover|
         | 
| 12 | 
            +
                        label|
         | 
| 13 | 
            +
                        control|
         | 
| 14 | 
            +
                        jog-(?<jog_type>pulses|ms)|
         | 
| 15 | 
            +
                        position-pulses|
         | 
| 16 | 
            +
                        position-percent|
         | 
| 17 | 
            +
                        ip|
         | 
| 18 | 
            +
                        reset|
         | 
| 19 | 
            +
                        (?<speed_type>up-speed|down-speed|slow-speed)|
         | 
| 20 | 
            +
                        up-limit|
         | 
| 21 | 
            +
                        down-limit|
         | 
| 22 | 
            +
                        direction|i
         | 
| 23 | 
            +
                        p(?<ip>\d+)-(?<ip_type>pulses|percent)|
         | 
| 24 | 
            +
                        groups)/
         | 
| 25 | 
            +
                        set$}x))
         | 
| 26 | 
            +
                        return
         | 
| 27 | 
            +
                      end
         | 
| 23 28 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
                              motor&.node_type == :st50ilt2 ? ns::SetMotorPosition.new(addr, :stop) : Message::Stop.new(addr)
         | 
| 42 | 
            -
                            when 'next_ip'
         | 
| 43 | 
            -
                              motor&.node_type == :st50ilt2 ? ns::SetMotorPosition.new(addr, :next_ip_down) :
         | 
| 44 | 
            -
                                Message::MoveOf.new(addr, :next_ip)
         | 
| 45 | 
            -
                            when 'previous_ip'
         | 
| 46 | 
            -
                              motor&.node_type == :st50ilt2 ? ns::SetMotorPosition.new(addr, :next_ip_up) :
         | 
| 47 | 
            -
                                Message::MoveOf.new(addr, :previous_ip)
         | 
| 48 | 
            -
                            when 'wink'
         | 
| 49 | 
            -
                              Message::Wink.new(addr)
         | 
| 50 | 
            -
                            when 'refresh'
         | 
| 51 | 
            -
                              follow_up = nil
         | 
| 52 | 
            -
                              (motor&.node_type == :st50ilt2 ? ns::GetMotorPosition : Message::GetMotorStatus).
         | 
| 53 | 
            -
                                new(addr)
         | 
| 54 | 
            -
                            end
         | 
| 55 | 
            -
                          when /jog-(?:pulses|ms)/
         | 
| 56 | 
            -
                            value = value.to_i
         | 
| 57 | 
            -
                            (motor&.node_type == :st50ilt2 ? ns::SetMotorPosition : Message::MoveOf).
         | 
| 58 | 
            -
                              new(addr, "jog_#{value < 0 ? :up : :down }_#{match[:jog_type]}".to_sym, value.abs)
         | 
| 59 | 
            -
                          when 'reset'
         | 
| 60 | 
            -
                            return unless Message::SetFactoryDefault::RESET.keys.include?(value.to_sym)
         | 
| 61 | 
            -
                            Message::SetFactoryDefault.new(addr, value.to_sym)
         | 
| 62 | 
            -
                          when 'position-pulses', 'position-percent', 'ip'
         | 
| 63 | 
            -
                            if value == 'REFRESH'
         | 
| 64 | 
            -
                              follow_up = nil
         | 
| 65 | 
            -
                              (motor&.node_type == :st50ilt2 ? ns::GetMotorPosition : Message::GetMotorStatus).
         | 
| 66 | 
            -
                                new(addr)
         | 
| 67 | 
            -
                            else
         | 
| 68 | 
            -
                              (motor&.node_type == :st50ilt2 ? ns::SetMotorPosition : Message::MoveTo).
         | 
| 69 | 
            -
                                new(addr, property.sub('position-', 'position_').to_sym, value.to_i)
         | 
| 70 | 
            -
                            end
         | 
| 71 | 
            -
                          when 'direction'
         | 
| 72 | 
            -
                            return if is_group
         | 
| 73 | 
            -
                            follow_up = Message::GetMotorDirection.new(addr)
         | 
| 74 | 
            -
                            return unless %w{standard reversed}.include?(value)
         | 
| 75 | 
            -
                            Message::SetMotorDirection.new(addr, value.to_sym)
         | 
| 76 | 
            -
                          when 'up-limit', 'down-limit'
         | 
| 77 | 
            -
                            return if is_group
         | 
| 78 | 
            -
                            if %w{delete current_position jog_ms jog_pulses}.include?(value)
         | 
| 79 | 
            -
                              type = value.to_sym
         | 
| 80 | 
            -
                              value = 10
         | 
| 81 | 
            -
                            else
         | 
| 82 | 
            -
                              type = :specified_position
         | 
| 83 | 
            -
                            end
         | 
| 84 | 
            -
                            target = property == 'up-limit' ? :up : :down
         | 
| 85 | 
            -
                            follow_up = Message::GetMotorLimits.new(addr)
         | 
| 86 | 
            -
                            Message::SetMotorLimits.new(addr, type, target, value.to_i)
         | 
| 87 | 
            -
                          when /^ip\d-(?:pulses|percent)$/
         | 
| 88 | 
            -
                            return if is_group
         | 
| 89 | 
            -
                            ip = match[:ip].to_i
         | 
| 90 | 
            -
                            return unless (1..16).include?(ip)
         | 
| 91 | 
            -
                            follow_up = ns::GetMotorIP.new(addr, ip)
         | 
| 29 | 
            +
                      addr = Message.parse_address(match[:addr])
         | 
| 30 | 
            +
                      property = match[:property]
         | 
| 31 | 
            +
                      # not homie compliant; allows linking the position-percent property
         | 
| 32 | 
            +
                      # directly to an OpenHAB rollershutter channel
         | 
| 33 | 
            +
                      if property == "position-percent" && value =~ /^(?:UP|DOWN|STOP)$/i
         | 
| 34 | 
            +
                        property = "control"
         | 
| 35 | 
            +
                        value = value.downcase
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                      mqtt_addr = Message.print_address(addr).delete(".")
         | 
| 38 | 
            +
                      motor = @motors[mqtt_addr]
         | 
| 39 | 
            +
                      is_group = Message.group_address?(addr)
         | 
| 40 | 
            +
                      follow_up = if motor&.node_type == :st50ilt2
         | 
| 41 | 
            +
                                    Message::ILT2::GetMotorPosition.new(addr)
         | 
| 42 | 
            +
                                  else
         | 
| 43 | 
            +
                                    Message::GetMotorStatus.new(addr)
         | 
| 44 | 
            +
                                  end
         | 
| 45 | 
            +
                      ns = (motor&.node_type == :st50ilt2) ? Message::ILT2 : Message
         | 
| 92 46 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
                                 | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
                                 | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 47 | 
            +
                      message = case property
         | 
| 48 | 
            +
                                when "discover"
         | 
| 49 | 
            +
                                  follow_up = nil
         | 
| 50 | 
            +
                                  if value == "discover"
         | 
| 51 | 
            +
                                    # discovery is low priority, and longer timeout
         | 
| 52 | 
            +
                                    enqueue(MessageAndRetries.new(Message::GetNodeAddr.new(addr), 1, 50))
         | 
| 53 | 
            +
                                  end
         | 
| 54 | 
            +
                                  nil
         | 
| 55 | 
            +
                                when "label"
         | 
| 56 | 
            +
                                  follow_up = Message::GetNodeLabel.new(addr)
         | 
| 57 | 
            +
                                  ns::SetNodeLabel.new(addr, value) unless is_group
         | 
| 58 | 
            +
                                when "control"
         | 
| 59 | 
            +
                                  case value
         | 
| 60 | 
            +
                                  when "up", "down"
         | 
| 61 | 
            +
                                    ((motor&.node_type == :st50ilt2) ? ns::SetMotorPosition : Message::MoveTo)
         | 
| 62 | 
            +
                                .new(addr, "#{value}_limit".to_sym)
         | 
| 63 | 
            +
                                  when "stop"
         | 
| 64 | 
            +
                                    if motor&.node_type == :st50ilt2
         | 
| 65 | 
            +
                                      ns::SetMotorPosition.new(addr,
         | 
| 66 | 
            +
                                                               :stop)
         | 
| 67 | 
            +
                                    else
         | 
| 68 | 
            +
                                      Message::Stop.new(addr)
         | 
| 69 | 
            +
                                    end
         | 
| 70 | 
            +
                                  when "next_ip"
         | 
| 71 | 
            +
                                    if motor&.node_type == :st50ilt2
         | 
| 72 | 
            +
                                      ns::SetMotorPosition.new(addr, :next_ip_down)
         | 
| 73 | 
            +
                                    else
         | 
| 74 | 
            +
                                      Message::MoveOf.new(addr, :next_ip)
         | 
| 75 | 
            +
                                    end
         | 
| 76 | 
            +
                                  when "previous_ip"
         | 
| 77 | 
            +
                                    if motor&.node_type == :st50ilt2
         | 
| 78 | 
            +
                                      ns::SetMotorPosition.new(addr, :next_ip_up)
         | 
| 79 | 
            +
                                    else
         | 
| 80 | 
            +
                                      Message::MoveOf.new(addr, :previous_ip)
         | 
| 81 | 
            +
                                    end
         | 
| 82 | 
            +
                                  when "wink"
         | 
| 83 | 
            +
                                    Message::Wink.new(addr)
         | 
| 84 | 
            +
                                  when "refresh"
         | 
| 85 | 
            +
                                    follow_up = nil
         | 
| 86 | 
            +
                                    ((motor&.node_type == :st50ilt2) ? ns::GetMotorPosition : Message::GetMotorStatus)
         | 
| 87 | 
            +
                                .new(addr)
         | 
| 88 | 
            +
                                  end
         | 
| 89 | 
            +
                                when /jog-(?:pulses|ms)/
         | 
| 90 | 
            +
                                  value = value.to_i
         | 
| 91 | 
            +
                                  ((motor&.node_type == :st50ilt2) ? ns::SetMotorPosition : Message::MoveOf)
         | 
| 92 | 
            +
                                .new(addr, "jog_#{value.negative? ? :up : :down}_#{match[:jog_type]}".to_sym, value.abs)
         | 
| 93 | 
            +
                                when "reset"
         | 
| 94 | 
            +
                                  return unless Message::SetFactoryDefault::RESET.key?(value.to_sym)
         | 
| 136 95 |  | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 96 | 
            +
                                  Message::SetFactoryDefault.new(addr, value.to_sym)
         | 
| 97 | 
            +
                                when "position-pulses", "position-percent", "ip"
         | 
| 98 | 
            +
                                  if value == "REFRESH"
         | 
| 99 | 
            +
                                    follow_up = nil
         | 
| 100 | 
            +
                                    ((motor&.node_type == :st50ilt2) ? ns::GetMotorPosition : Message::GetMotorStatus)
         | 
| 101 | 
            +
                                      .new(addr)
         | 
| 102 | 
            +
                                  else
         | 
| 103 | 
            +
                                    ((motor&.node_type == :st50ilt2) ? ns::SetMotorPosition : Message::MoveTo)
         | 
| 104 | 
            +
                                      .new(addr, property.sub("position-", "position_").to_sym, value.to_i)
         | 
| 105 | 
            +
                                  end
         | 
| 106 | 
            +
                                when "direction"
         | 
| 107 | 
            +
                                  return if is_group
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                                  follow_up = Message::GetMotorDirection.new(addr)
         | 
| 110 | 
            +
                                  return unless %w[standard reversed].include?(value)
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                                  Message::SetMotorDirection.new(addr, value.to_sym)
         | 
| 113 | 
            +
                                when "up-limit", "down-limit"
         | 
| 114 | 
            +
                                  return if is_group
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                                  if %w[delete current_position jog_ms jog_pulses].include?(value)
         | 
| 117 | 
            +
                                    type = value.to_sym
         | 
| 118 | 
            +
                                    value = 10
         | 
| 119 | 
            +
                                  else
         | 
| 120 | 
            +
                                    type = :specified_position
         | 
| 121 | 
            +
                                  end
         | 
| 122 | 
            +
                                  target = (property == "up-limit") ? :up : :down
         | 
| 123 | 
            +
                                  follow_up = Message::GetMotorLimits.new(addr)
         | 
| 124 | 
            +
                                  Message::SetMotorLimits.new(addr, type, target, value.to_i)
         | 
| 125 | 
            +
                                when /^ip\d-(?:pulses|percent)$/
         | 
| 126 | 
            +
                                  return if is_group
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                                  ip = match[:ip].to_i
         | 
| 129 | 
            +
                                  return unless (1..16).cover?(ip)
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                                  follow_up = ns::GetMotorIP.new(addr, ip)
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                                  if motor&.node_type == :st50ilt2
         | 
| 134 | 
            +
                                    value = if value == "delete"
         | 
| 135 | 
            +
                                              nil
         | 
| 136 | 
            +
                                            elsif value == "current_position"
         | 
| 137 | 
            +
                                              motor.position_pulses
         | 
| 138 | 
            +
                                            elsif match[:ip_type] == "pulses"
         | 
| 139 | 
            +
                                              value.to_i
         | 
| 140 | 
            +
                                            else
         | 
| 141 | 
            +
                                              value.to_f / motor.down_limit * 100
         | 
| 142 | 
            +
                                            end
         | 
| 143 | 
            +
                                    ns::SetMotorIP.new(addr, ip, value)
         | 
| 144 | 
            +
                                  else
         | 
| 145 | 
            +
                                    type = if value == "delete"
         | 
| 146 | 
            +
                                             :delete
         | 
| 147 | 
            +
                                           elsif value == "current_position"
         | 
| 148 | 
            +
                                             :current_position
         | 
| 149 | 
            +
                                           elsif match[:ip_type] == "pulses"
         | 
| 150 | 
            +
                                             :position_pulses
         | 
| 151 | 
            +
                                           else
         | 
| 152 | 
            +
                                             :position_percent
         | 
| 153 | 
            +
                                           end
         | 
| 154 | 
            +
                                    Message::SetMotorIP.new(addr, type, ip, value.to_i)
         | 
| 155 | 
            +
                                  end
         | 
| 156 | 
            +
                                when "up-speed", "down-speed", "slow-speed"
         | 
| 157 | 
            +
                                  return if is_group
         | 
| 158 | 
            +
                                  return unless motor
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                                  follow_up = Message::GetMotorRollingSpeed.new(addr)
         | 
| 161 | 
            +
                                  message = Message::SetMotorRollingSpeed.new(addr,
         | 
| 162 | 
            +
                                                                              up_speed: motor.up_speed,
         | 
| 163 | 
            +
                                                                              down_speed: motor.down_speed,
         | 
| 164 | 
            +
                                                                              slow_speed: motor.slow_speed)
         | 
| 165 | 
            +
                                  message.send(:"#{property.sub("-", "_")}=", value.to_i)
         | 
| 166 | 
            +
                                  message
         | 
| 167 | 
            +
                                when "groups"
         | 
| 168 | 
            +
                                  return if is_group
         | 
| 169 | 
            +
                                  return unless motor
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                                  messages = motor.set_groups(value)
         | 
| 172 | 
            +
                                  @mutex.synchronize do
         | 
| 173 | 
            +
                                    messages.each { |m| @queue.push(MessageAndRetries.new(m, 5, 0)) }
         | 
| 174 | 
            +
                                    @cond.signal
         | 
| 175 | 
            +
                                  end
         | 
| 176 | 
            +
                                  nil
         | 
| 177 | 
            +
                                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                      if motor && [Message::MoveTo,
         | 
| 180 | 
            +
                                   Message::Move,
         | 
| 181 | 
            +
                                   Message::Wink,
         | 
| 182 | 
            +
                                   Message::Stop].include?(message.class)
         | 
| 183 | 
            +
                        motor.last_action = message.class
         | 
| 184 | 
            +
                      end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                      return unless message
         | 
| 140 187 |  | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
                            @cond.signal
         | 
| 149 | 
            -
                          end
         | 
| 188 | 
            +
                      message.ack_requested = true unless /^SDN::Message::Get/.match?(message.class.name)
         | 
| 189 | 
            +
                      @mutex.synchronize do
         | 
| 190 | 
            +
                        @queue.push(MessageAndRetries.new(message, 5, 0))
         | 
| 191 | 
            +
                        if follow_up && @queue.none? do |mr|
         | 
| 192 | 
            +
                             mr.message == follow_up
         | 
| 193 | 
            +
                           end
         | 
| 194 | 
            +
                          @queue.push(MessageAndRetries.new(follow_up, 5, 1))
         | 
| 150 195 | 
             
                        end
         | 
| 196 | 
            +
                        @cond.signal
         | 
| 151 197 | 
             
                      end
         | 
| 152 198 | 
             
                    end
         | 
| 153 199 | 
             
                  end
         | 
    
        data/lib/sdn/cli/mqtt/write.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module SDN
         | 
| 2 4 | 
             
              module CLI
         | 
| 3 5 | 
             
                class MQTT
         | 
| @@ -12,23 +14,25 @@ module SDN | |
| 12 14 | 
             
                          if @response_pending
         | 
| 13 15 | 
             
                            while @response_pending
         | 
| 14 16 | 
             
                              remaining_wait = @response_pending - Time.now.to_f
         | 
| 15 | 
            -
                              if remaining_wait | 
| 16 | 
            -
                                SDN.logger.debug " | 
| 17 | 
            +
                              if remaining_wait.negative?
         | 
| 18 | 
            +
                                SDN.logger.debug "Timed out waiting on response"
         | 
| 17 19 | 
             
                                @response_pending = nil
         | 
| 18 20 | 
             
                                @broadcast_pending = nil
         | 
| 19 21 | 
             
                                if @prior_message && @prior_message&.remaining_retries != 0
         | 
| 20 | 
            -
                                  SDN.logger.debug " | 
| 21 | 
            -
                                  if Message. | 
| 22 | 
            -
                                    SDN.logger.debug " | 
| 22 | 
            +
                                  SDN.logger.debug "Retrying #{@prior_message.remaining_retries} more times ..."
         | 
| 23 | 
            +
                                  if Message.group_address?(@prior_message.message.src) && !@pending_group_motors.empty?
         | 
| 24 | 
            +
                                    SDN.logger.debug "Re-targetting group message to individual motors"
         | 
| 23 25 | 
             
                                    @pending_group_motors.each do |addr|
         | 
| 24 26 | 
             
                                      new_message = @prior_message.message.dup
         | 
| 25 27 | 
             
                                      new_message.src = [0, 0, 1]
         | 
| 26 28 | 
             
                                      new_message.dest = Message.parse_address(addr)
         | 
| 27 | 
            -
                                      @ | 
| 29 | 
            +
                                      @queue.push(MessageAndRetries.new(new_message,
         | 
| 30 | 
            +
                                                                        @prior_message.remaining_retries,
         | 
| 31 | 
            +
                                                                        @prior_message.priority))
         | 
| 28 32 | 
             
                                    end
         | 
| 29 33 | 
             
                                    @pending_group_motors = []
         | 
| 30 34 | 
             
                                  else
         | 
| 31 | 
            -
                                    @ | 
| 35 | 
            +
                                    @queue.push(@prior_message)
         | 
| 32 36 | 
             
                                  end
         | 
| 33 37 | 
             
                                  @prior_message = nil
         | 
| 34 38 | 
             
                                end
         | 
| @@ -38,53 +42,54 @@ module SDN | |
| 38 42 | 
             
                            end
         | 
| 39 43 | 
             
                          end
         | 
| 40 44 |  | 
| 41 | 
            -
                           | 
| 42 | 
            -
                          if message_and_retries
         | 
| 43 | 
            -
                             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 45 | 
            +
                          message_and_retries = @queue.shift
         | 
| 46 | 
            +
                          if message_and_retries && (
         | 
| 47 | 
            +
                            message_and_retries.message.ack_requested ||
         | 
| 48 | 
            +
                            message_and_retries.message.class.name =~ /^SDN::Message::Get/)
         | 
| 49 | 
            +
                            @response_pending = Time.now.to_f + WAIT_TIME
         | 
| 50 | 
            +
                            @pending_group_motors = if Message.group_address?(message_and_retries.message.src)
         | 
| 51 | 
            +
                                                      group_addr = Message.print_address(message_and_retries.message.src).delete(
         | 
| 52 | 
            +
                                                        "."
         | 
| 53 | 
            +
                                                      )
         | 
| 54 | 
            +
                                                      @groups[group_addr]&.motor_objects&.map(&:addr) || []
         | 
| 55 | 
            +
                                                    else
         | 
| 56 | 
            +
                                                      []
         | 
| 57 | 
            +
                                                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                            if message_and_retries.message.dest == BROADCAST_ADDRESS || (
         | 
| 60 | 
            +
                              Message.group_address?(message_and_retries.message.src) &&
         | 
| 61 | 
            +
                              message_and_retries.message.is_a?(Message::GetNodeAddr))
         | 
| 62 | 
            +
                              @broadcast_pending = Time.now.to_f + BROADCAST_WAIT
         | 
| 55 63 | 
             
                            end
         | 
| 56 64 | 
             
                          end
         | 
| 57 65 |  | 
| 58 66 | 
             
                          # wait until there is a message
         | 
| 59 67 | 
             
                          if @response_pending
         | 
| 60 68 | 
             
                            message_and_retries.remaining_retries -= 1
         | 
| 61 | 
            -
                            @prior_message = message_and_retries | 
| 69 | 
            +
                            @prior_message = message_and_retries
         | 
| 62 70 | 
             
                          elsif message_and_retries
         | 
| 63 | 
            -
                            @prior_message = nil | 
| 71 | 
            +
                            @prior_message = nil
         | 
| 72 | 
            +
                          elsif @auto_discover && @motors_found
         | 
| 73 | 
            +
                            message_and_retries = MessageAndRetries.new(Message::GetNodeAddr.new, 1, 50)
         | 
| 74 | 
            +
                            @motors_found = false
         | 
| 75 | 
            +
                          # nothing pending to write, and motors found on the last iteration;
         | 
| 76 | 
            +
                          # look for more motors
         | 
| 64 77 | 
             
                          else
         | 
| 65 | 
            -
                             | 
| 66 | 
            -
                              # nothing pending to write, and motors found on the last iteration;
         | 
| 67 | 
            -
                              # look for more motors
         | 
| 68 | 
            -
                              message_and_retries = MessageAndRetries.new(Message::GetNodeAddr.new, 1, 2)
         | 
| 69 | 
            -
                              @motors_found = false
         | 
| 70 | 
            -
                            else
         | 
| 71 | 
            -
                              @cond.wait(@mutex)
         | 
| 72 | 
            -
                            end
         | 
| 78 | 
            +
                            @cond.wait(@mutex)
         | 
| 73 79 | 
             
                          end
         | 
| 74 80 | 
             
                        end
         | 
| 75 81 | 
             
                        next unless message_and_retries
         | 
| 76 82 |  | 
| 77 83 | 
             
                        message = message_and_retries.message
         | 
| 78 | 
            -
                        SDN.logger.info "writing #{message.inspect}"
         | 
| 79 84 | 
             
                        # minimum time between messages
         | 
| 80 85 | 
             
                        now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
         | 
| 81 86 | 
             
                        sleep_time = 0.1 - (now - last_write_at)
         | 
| 82 | 
            -
                        sleep(sleep_time) if sleep_time | 
| 87 | 
            +
                        sleep(sleep_time) if sleep_time.positive?
         | 
| 83 88 | 
             
                        @sdn.send(message)
         | 
| 84 89 | 
             
                        last_write_at = now
         | 
| 85 90 | 
             
                      end
         | 
| 86 91 | 
             
                    rescue => e
         | 
| 87 | 
            -
                      SDN.logger.fatal " | 
| 92 | 
            +
                      SDN.logger.fatal "Failure writing: #{e}: #{e.backtrace}"
         | 
| 88 93 | 
             
                      exit 1
         | 
| 89 94 | 
             
                    end
         | 
| 90 95 | 
             
                  end
         |