class MQTT::Homie::Client

homieiot.github.io/specification/

Constants

DEFAULT_ROOT_TOPIC

Attributes

device[R]
host[RW]
root_topic[RW]

Public Class Methods

new(options = {}) click to toggle source
# File lib/mqtt/homie/client.rb, line 11
def initialize(options = {})
  @device = options[:device]
  @host = options[:host]
  @root_topic = options[:root_topic] || DEFAULT_ROOT_TOPIC

  raise "device required" unless @device

  # next version of homie doesn't use stats or firmware details
  @use_stats = true
  if options[:develop]
    @device.use_stats = false
    @device.use_fw = false
    @use_stats = false
  end

  # observe all node properties so we can publish values when they change
  @device.nodes.each do |node|
    node.properties.each do |property|
      property.add_observer(self)
    end
  end
end

Public Instance Methods

connect() click to toggle source
# File lib/mqtt/homie/client.rb, line 34
def connect
  return if connected?

  @device.state = :init
  @client = create_mqtt_client
  @client.connect

  publish(@device, topic)
  publish_statistics if @use_stats

  @threads = []

  # run a thread to publish statistics
  @threads << Thread.new { run_statistics } if @use_stats

  # run a thread to listen for settings
  @threads << Thread.new { run_set_listener }

  @device.state = :ready
  publish_state
end
connected?() click to toggle source
# File lib/mqtt/homie/client.rb, line 71
def connected?
  @device.state == :ready
end
disconnect() click to toggle source
# File lib/mqtt/homie/client.rb, line 56
def disconnect
  @device.state = :disconnected
  publish_state

  @client.disconnect
  @client = nil

  @threads.each { |i| i[:done] = true }
  @threads = []
end
topic() click to toggle source
# File lib/mqtt/homie/client.rb, line 67
def topic
  @root_topic + "/" + @device.id
end
update(time, object) click to toggle source
# File lib/mqtt/homie/client.rb, line 75
def update(time, object)
  if object.kind_of?(MQTT::Homie::Property)
    publish_property_value(object)
  end
end

Private Instance Methods

create_mqtt_client() click to toggle source
# File lib/mqtt/homie/client.rb, line 83
def create_mqtt_client
  client = ::MQTT::Client.new
  client.host = @host
  client.will_topic = topic + "/$state"
  client.will_payload = :lost
  client.will_retain = true
  client
end
debug(message) click to toggle source
# File lib/mqtt/homie/client.rb, line 168
def debug(message)
  MQTT::Homie.debug(message)
end
find_property_by_set_topic(set_topic) click to toggle source
# File lib/mqtt/homie/client.rb, line 125
def find_property_by_set_topic(set_topic)
  @device.nodes.each do |node|
    node.properties.each do |property|
      return property if set_topic == topic + "/" + node.topic + "/" + property.topic + "/set"
    end
  end
  nil
end
publish(object, prefix = nil) click to toggle source
# File lib/mqtt/homie/client.rb, line 153
def publish(object, prefix = nil)
  data = {}
  if object.respond_to?(:homie_attributes)
    data = object.homie_attributes
  else
    data = object
  end

  data.each do |k, v|
    topic = prefix + "/" + k
    debug("mqtt publish #{topic} -> #{v}")
    @client.publish(topic, v, true)
  end
end
publish_property_value(property) click to toggle source
# File lib/mqtt/homie/client.rb, line 138
def publish_property_value(property)
  node = @device.nodes.find { |i| i.properties.include?(property) }
  data = {
    property.id => property.value,
  }
  publish(data, topic + "/" + node.topic)
end
publish_state() click to toggle source
# File lib/mqtt/homie/client.rb, line 146
def publish_state
  data = {
    "$state" => @device.state,
  }
  publish(data, topic)
end
publish_statistics() click to toggle source
# File lib/mqtt/homie/client.rb, line 134
def publish_statistics
  publish(@device.stats, topic + "/$stats")
end
run_set_listener() click to toggle source
# File lib/mqtt/homie/client.rb, line 92
def run_set_listener
  # subscribe to 'set' topics for all settable properties
  @device.nodes.each do |node|
    node.properties.each do |property|
      if property.settable?
        set_topic = topic + "/" + node.topic + "/" + property.topic + "/set"
        debug("subscribe #{set_topic}")
        @client.subscribe(set_topic) if @client
      end
    end
  end

  if @client
    @client.get do |topic, message|
      debug("received message: #{topic}, message: #{message}")
      property = find_property_by_set_topic(topic)
      property.value = message if property
      break if Thread.current[:done]
    end
  end
  debug("set listener thread exiting")
end
run_statistics() click to toggle source
# File lib/mqtt/homie/client.rb, line 115
def run_statistics
  while !Thread.current[:done]
    publish_statistics

    # halve interval, if we miss a notification then we will be marked as offline
    sleep @device.stats.interval / 2
  end
  debug("statistics thread exiting")
end