Class: MQTT::Homie::Property

Inherits:
Base
  • Object
show all
Defined in:
lib/mqtt/homie/property.rb

Constant Summary

Constants inherited from Base

Base::REGEX

Instance Attribute Summary collapse

Attributes inherited from Base

#id, #name

Instance Method Summary collapse

Constructor Details

#initialize(node, id, name, datatype, value = nil, format: nil, retained: true, unit: nil, non_standard_value_check: nil, optimistic: false, &block) ⇒ Property

Returns a new instance of Property.

Raises:

  • (ArgumentError)


10
11
12
13
14
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
40
41
42
43
44
45
46
47
# File 'lib/mqtt/homie/property.rb', line 10

def initialize(node,
               id,
               name,
               datatype,
               value = nil,
               format: nil,
               retained: true,
               unit: nil,
               non_standard_value_check: nil,
               optimistic: false,
               &block)
  raise ArgumentError, "Invalid Homie datatype" unless %i[string
                                                          integer
                                                          float
                                                          boolean
                                                          enum
                                                          color
                                                          datetime
                                                          duration].include?(datatype)
  raise ArgumentError, "retained must be boolean" unless [true, false].include?(retained)
  raise ArgumentError, "unit must be nil or a string" unless unit.nil? || unit.is_a?(String)
  if !value.nil? && !retained
    raise ArgumentError, "an initial value cannot be provided for a non-retained property"
  end

  super(id, name)

  @node = node
  @datatype = datatype
  self.format = format
  @retained = retained
  @unit = unit
  @value = value
  @published = false
  @non_standard_value_check = non_standard_value_check
  @optimistic = optimistic
  @block = block
end

Instance Attribute Details

#datatypeObject (readonly)

Returns the value of attribute datatype.



8
9
10
# File 'lib/mqtt/homie/property.rb', line 8

def datatype
  @datatype
end

#formatObject

Returns the value of attribute format.



8
9
10
# File 'lib/mqtt/homie/property.rb', line 8

def format
  @format
end

#nodeObject (readonly)

Returns the value of attribute node.



8
9
10
# File 'lib/mqtt/homie/property.rb', line 8

def node
  @node
end

#unitObject

Returns the value of attribute unit.



8
9
10
# File 'lib/mqtt/homie/property.rb', line 8

def unit
  @unit
end

#valueObject

Returns the value of attribute value.



8
9
10
# File 'lib/mqtt/homie/property.rb', line 8

def value
  @value
end

Instance Method Details

#deviceObject



68
69
70
# File 'lib/mqtt/homie/property.rb', line 68

def device
  node.device
end

#full_nameObject



64
65
66
# File 'lib/mqtt/homie/property.rb', line 64

def full_name
  "#{node.full_name} #{name}"
end

#inspectObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/mqtt/homie/property.rb', line 49

def inspect
  result = +"#<MQTT::Homie::Property #{topic} name=#{full_name.inspect}, datatype=#{datatype.inspect}"
  result << ", format=#{format.inspect}" if format
  result << ", unit=#{unit.inspect}" if unit
  result << ", settable=true" if settable?
  result << if retained?
              ", value=#{value.inspect}"
            else
              ", retained=false"
            end
  result << ", optimistic=true" if optimistic?
  result << ">"
  result.freeze
end

#mqttObject



186
187
188
# File 'lib/mqtt/homie/property.rb', line 186

def mqtt
  node.mqtt
end

#optimistic?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/mqtt/homie/property.rb', line 84

def optimistic?
  @optimistic
end

#publishObject



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/mqtt/homie/property.rb', line 194

def publish
  return if published?

  mqtt.batch_publish do
    if device.metadata?
      mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
      mqtt.publish("#{topic}/$datatype", datatype.to_s, retain: true, qos: 1)
      mqtt.publish("#{topic}/$format", format, retain: true, qos: 1) if format
      mqtt.publish("#{topic}/$settable", "true", retain: true, qos: 1) if settable?
      mqtt.publish("#{topic}/$retained", "false", retain: true, qos: 1) unless retained?
      mqtt.publish("#{topic}/$unit", unit, retain: true, qos: 1) if unit
    end
    publish_value(value) unless value.nil?
    subscribe
  end

  @published = true
end

#published?Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/mqtt/homie/property.rb', line 190

def published?
  @published
end

#rangeObject



133
134
135
136
137
138
139
140
141
142
# File 'lib/mqtt/homie/property.rb', line 133

def range
  return nil unless format

  case datatype
  when :enum then format.split(",")
  when :integer then Range.new(*format.split(":").map(&:to_i))
  when :float then Range.new(*format.split(":").map(&:to_f))
  else; raise MethodNotImplemented
  end
end

#retained?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/mqtt/homie/property.rb', line 76

def retained?
  @retained
end

#set(value) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/mqtt/homie/property.rb', line 144

def set(value)
  casted_value = case datatype
                 when :boolean
                   %w[true false].include?(value) ? value == "true" : nil
                 when :integer
                   /^-?\d+$/.match?(value) && value.to_i
                 when :float
                   /^-?(?:\d+|\d+\.|\.\d+|\d+\.\d+)(?:[eE]-?\d+)?$/.match?(value) && value.to_f
                 when :enum
                   value
                 when :color
                   /^\d{1,3},\d{1,3},\d{1,3}$/.match?(value) && value = value.split(",").map(&:to_i)
                 when :datetime
                   begin
                     value = Time.parse(value)
                   rescue ArgumentError
                     nil
                   end
                 when :duration
                   begin
                     value = ActiveSupport::Duration.parse(value)
                   rescue ActiveSupport::Duration::ISO8601Parser::ParsingError
                     nil
                   end
                 end
  case datatype
  when :integer, :float
    casted_value = nil if format && !range.cover?(casted_value)
  when :enum
    casted_value = nil if format && !range.include?(casted_value)
  when :color
    casted_value = nil if (format == "rgb" && value.max > 255) ||
                          (format == "hsb" && (value.first > 360 || value[1..2].max > 100))
  end

  casted_value = @non_standard_value_check&.call(value) if casted_value.nil?
  return if casted_value.nil?

  (@block.arity == 2) ? @block.call(casted_value, self) : @block.call(casted_value)
  self.value = casted_value if optimistic?
end

#settable?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/mqtt/homie/property.rb', line 80

def settable?
  !!@block
end

#subscribeObject



213
214
215
# File 'lib/mqtt/homie/property.rb', line 213

def subscribe
  mqtt.subscribe("#{topic}/set") if settable?
end

#topicObject



72
73
74
# File 'lib/mqtt/homie/property.rb', line 72

def topic
  "#{node.topic}/#{id}"
end

#unpublishObject



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/mqtt/homie/property.rb', line 217

def unpublish
  return unless published?

  @published = false

  if device.metadata?
    mqtt.publish("#{topic}/$name", retain: true, qos: 0)
    mqtt.publish("#{topic}/$datatype", retain: true, qos: 0)
    mqtt.publish("#{topic}/$format", retain: true, qos: 0) if format
    mqtt.publish("#{topic}/$settable", retain: true, qos: 0) if settable?
    mqtt.publish("#{topic}/$retained", retain: true, qos: 0) unless retained?
    mqtt.publish("#{topic}/$unit", retain: true, qos: 0) if unit
  end
  mqtt.unsubscribe("#{topic}/set") if settable?
  mqtt.publish(topic, retain: retained?, qos: 0) if !value.nil? && retained?
end