Class: MQTT::Homie::Device
Constant Summary collapse
- VERSION =
the Homie spec version
"4.0.0"
Constants inherited from Base
Instance Attribute Summary collapse
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#mqtt ⇒ Object
readonly
Returns the value of attribute mqtt.
-
#out_of_band_topic_proc ⇒ Object
Returns the value of attribute out_of_band_topic_proc.
-
#root_topic ⇒ Object
readonly
Returns the value of attribute root_topic.
-
#state ⇒ Object
Returns the value of attribute state.
Attributes inherited from Base
Instance Method Summary collapse
- #[](id) ⇒ Object
-
#clear_topics ⇒ Object
rubocop:disable Naming/PredicateMethod.
- #count ⇒ Object
- #device ⇒ Object
- #disconnect ⇒ Object
- #each(&block) ⇒ Object
- #empty? ⇒ Boolean
- #init ⇒ Object
-
#initialize(id, name, root_topic: nil, mqtt: nil, clear_topics: true, metadata: true, &block) ⇒ Device
constructor
A new instance of Device.
- #inspect ⇒ Object
- #join ⇒ Object
- #metadata? ⇒ Boolean
- #publish ⇒ Object
- #published? ⇒ Boolean
-
#remove_node(id) ⇒ Object
rubocop:disable Naming/PredicateMethod.
- #topic ⇒ Object
Constructor Details
#initialize(id, name, root_topic: nil, mqtt: nil, clear_topics: true, metadata: true, &block) ⇒ Device
Returns a new instance of Device.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/mqtt/homie/device.rb', line 15 def initialize(id, name, root_topic: nil, mqtt: nil, clear_topics: true, metadata: true, &block) super(id, name) @root_topic = root_topic || "homie" @state = :init @nodes = {} @published = false @out_of_band_topic_proc = block = # retry forever mqtt = MQTT::Client.new(mqtt, reconnect_limit: nil) if mqtt.is_a?(String) mqtt = MQTT::Client.new(reconnect_limit: nil, **mqtt) if mqtt.is_a?(Hash) @mqtt = mqtt || MQTT::Client.new(reconnect_limit: nil) @mqtt.set_will("#{topic}/$state", "lost", retain: true, qos: 1) @mqtt.on_reconnect do each do |node| node.each(&:subscribe) end mqtt.publish("#{topic}/$state", :init, retain: true, qos: 1) mqtt.publish("#{topic}/$state", state, retain: true, qos: 1) unless state == :init end @mqtt.connect self.clear_topics if clear_topics end |
Instance Attribute Details
#logger ⇒ Object
Returns the value of attribute logger.
13 14 15 |
# File 'lib/mqtt/homie/device.rb', line 13 def logger @logger end |
#mqtt ⇒ Object (readonly)
Returns the value of attribute mqtt.
12 13 14 |
# File 'lib/mqtt/homie/device.rb', line 12 def mqtt @mqtt end |
#out_of_band_topic_proc ⇒ Object
Returns the value of attribute out_of_band_topic_proc.
13 14 15 |
# File 'lib/mqtt/homie/device.rb', line 13 def out_of_band_topic_proc @out_of_band_topic_proc end |
#root_topic ⇒ Object (readonly)
Returns the value of attribute root_topic.
12 13 14 |
# File 'lib/mqtt/homie/device.rb', line 12 def root_topic @root_topic end |
#state ⇒ Object
Returns the value of attribute state.
12 13 14 |
# File 'lib/mqtt/homie/device.rb', line 12 def state @state end |
Instance Method Details
#[](id) ⇒ Object
80 81 82 |
# File 'lib/mqtt/homie/device.rb', line 80 def [](id) @nodes[id] end |
#clear_topics ⇒ Object
rubocop:disable Naming/PredicateMethod
179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/mqtt/homie/device.rb', line 179 def clear_topics # rubocop:disable Naming/PredicateMethod raise ArgumentError, "cannot clear topics once published" if published? @mqtt.subscribe("#{topic}/#") @mqtt.unsubscribe("#{topic}/#", wait_for_ack: true) until @mqtt.queue_empty? packet = @mqtt.get @mqtt.publish(packet.topic, retain: true, qos: 0) end true end |
#count ⇒ Object
88 89 90 |
# File 'lib/mqtt/homie/device.rb', line 88 def count @nodes.count end |
#device ⇒ Object
45 46 47 |
# File 'lib/mqtt/homie/device.rb', line 45 def device self end |
#disconnect ⇒ Object
153 154 155 156 157 |
# File 'lib/mqtt/homie/device.rb', line 153 def disconnect @published = false mqtt.disconnect @subscription_thread&.kill end |
#each(&block) ⇒ Object
84 85 86 |
# File 'lib/mqtt/homie/device.rb', line 84 def each(&block) @nodes.each_value(&block) end |
#empty? ⇒ Boolean
92 93 94 |
# File 'lib/mqtt/homie/device.rb', line 92 def empty? @nodes.empty? end |
#init ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/mqtt/homie/device.rb', line 166 def init return yield state if state == :init prior_state = state self.state = :init result = nil mqtt.batch_publish do result = yield prior_state end self.state = :ready result end |
#inspect ⇒ Object
41 42 43 |
# File 'lib/mqtt/homie/device.rb', line 41 def inspect "#<MQTT::Homie::Device #{topic} name=#{name.inspect}, $state=#{state.inspect}>" end |
#join ⇒ Object
159 160 161 162 163 164 |
# File 'lib/mqtt/homie/device.rb', line 159 def join @subscription_thread&.join rescue => e e.set_backtrace(e.backtrace + ["<from Homie MQTT thread>"] + caller) raise e end |
#metadata? ⇒ Boolean
100 101 102 |
# File 'lib/mqtt/homie/device.rb', line 100 def end |
#publish ⇒ Object
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 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/mqtt/homie/device.rb', line 104 def publish return if published? mqtt.batch_publish do if mqtt.publish("#{topic}/$homie", VERSION, retain: true, qos: 1) mqtt.publish("#{topic}/$name", name, retain: true, qos: 1) end mqtt.publish("#{topic}/$state", @state.to_s, retain: true, qos: 1) @subscription_thread = Thread.new do # you'll get the exception when you call `join` Thread.current.report_on_exception = false mqtt.get do |packet| logger&.debug("received packet at #{packet.topic} with payload #{packet.payload.inspect}") match = packet.topic.match(topic_regex) node = @nodes[match[:node]] if match property = node[match[:property]] if node unless property&.settable? begin @out_of_band_topic_proc&.call(packet.topic, packet.payload) rescue => e logger&.warn("Error in out of band topic proc for topic #{packet.topic} " \ "with payload #{packet.payload.inspect}: #{e.message}") end next end property.set(packet.payload) end end mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if @nodes.each_value(&:publish) yield if block_given? self.state = :ready end @published = true end |
#published? ⇒ Boolean
96 97 98 |
# File 'lib/mqtt/homie/device.rb', line 96 def published? @published end |
#remove_node(id) ⇒ Object
rubocop:disable Naming/PredicateMethod
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/mqtt/homie/device.rb', line 69 def remove_node(id) # rubocop:disable Naming/PredicateMethod return false unless (node = @nodes[id]) init do node.unpublish @nodes.delete(id) mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if published? end true end |
#topic ⇒ Object
49 50 51 |
# File 'lib/mqtt/homie/device.rb', line 49 def topic "#{root_topic}/#{id}" end |