def send_message!(payload, wait_for: wait_for, wait_timeout: Config.message_wait_timeout, retry_interval: Config.message_retry_interval, &block)
      if Thread.current[:sync_enabled]
        raise "Cannot use synchronous methods inside a sync block"
      end

      result = nil
      begin
        block ||= Proc.new { |msg| true }
        proc = -> (payload) {
          result = block.call(payload)
        }
        add_hook(wait_for, proc)
        try_until -> { result }, timeout: wait_timeout, timeout_exception: TimeoutError, action_interval: retry_interval, signal: @message_signal do
          send_message(payload)
        end
        result
      rescue TimeoutError
        backtrace = caller_locations(2).map { |c| c.to_s }
        caller_method = caller_locations(2, 1).first.label
        ex = MessageTimeout.new("#{caller_method}: Timeout exceeded waiting for response from #{self}")
        ex.device = self
        ex.set_backtrace(backtrace)
        raise ex
      ensure
        remove_hook(wait_for, proc)
      end
    end
def send_message!(payload, wait_for: wait_for, wait_timeout: Config.message_wait_timeout, retry_interval: Config.message_retry_interval, &block)
      if Thread.current[:sync_enabled]
        raise "Cannot use synchronous methods inside a sync block"
      end

      result = nil
      begin
        block ||= Proc.new { |msg| true }
        proc = -> (payload) {
          result = block.call(payload)
        }
        add_hook(wait_for, proc)
        try_until -> { result }, timeout: wait_timeout, timeout_exception: TimeoutError, action_interval: retry_interval, signal: @message_signal do
          send_message(payload)
        end
        result
      rescue TimeoutError
        backtrace = caller_locations(2).map { |c| c.to_s }
        caller_method = caller_locations(2, 1).first.label
        ex = MessageTimeout.new("#{caller_method}: Timeout exceeded waiting for response from #{self}")
        ex.device = self
        ex.set_backtrace(backtrace)
        raise ex
      ensure
        remove_hook(wait_for, proc)
      end
    end
Queues a message to be sent to the Light and waits for a response
 @param payload [Protocol::Payload] the payload to send
 @param wait_for: [Class] the payload class to wait for
 @param wait_timeout: [Numeric] wait timeout
 @param block: [Proc] the block that is executed when the expected `wait_for` payload comes back. If the return value is false or nil, it will try to send the message again.
 @return [Object] the truthy result of `block` is returned.
 @raise [MessageTimeout] if the device doesn't respond in time