homie-mqtt 1.4.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df54d2ae01eb1d1972e4d0f5fb40d05286969feff5ad83547476be6d11db05e2
4
- data.tar.gz: 719a2c270af518fd2ee7d7da4941a211da1f4af90d1e5f0daae2a0c50fd1616f
3
+ metadata.gz: ac2d4aeded4ffe715b8de38705b648c3aa2c80d378f57435f7e5bd854f8eac22
4
+ data.tar.gz: d4503b114004ebed3cd4987ecc1466ff0c3e6637d474477fb8f9e43eaf4e91b0
5
5
  SHA512:
6
- metadata.gz: 19fdcadf299dbe73d3bafca37e32d65b27edb006569ae80f27ecae036e6da17370c9e1b0af405f0517fd6649f5cc0c5bcb75912f00ec2560971d17385502408f
7
- data.tar.gz: b92d4b4cb05cc96b1a4b0d7e0254476f05db8be89f48d969277bbb09ae56cfcc7e597f5f9ccede42f5279d034bda7a85fe36ad1d652155cf3e38aac961c02667
6
+ metadata.gz: 02f74510916e8fb1d0ef8d40b3aea41320e9e12973175fb41b004598ab84038f16df3b171bf0c88e22e8fa894096871de17add5ca5aa37194bbda27e1cadecae
7
+ data.tar.gz: ffe27a55cf9e3e561a9469b17931b989e589a319b3e9e1aa976641640510bcbabe7f71988688922bd7ce77077f79f50ccf85f742a08d34bd73667bfc93eca5fc
data/lib/homie-mqtt.rb CHANGED
@@ -1,16 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MQTT
4
- module Homie
5
- class << self
6
- def escape_id(id)
7
- id.downcase.gsub(/[^a-z0-9\-]/, '-').sub(/^[^a-z0-9]+/, '')
8
- end
9
- end
10
- end
11
- end
12
-
13
- require 'mqtt/homie/base'
14
- require 'mqtt/homie/device'
15
- require 'mqtt/homie/node'
16
- require 'mqtt/homie/property'
3
+ require "mqtt/homie"
@@ -9,18 +9,19 @@ module MQTT
9
9
 
10
10
  def initialize(id, name)
11
11
  raise ArgumentError, "Invalid Homie ID '#{id}'" unless id.is_a?(String) && id =~ Regexp.new("^#{REGEX}$")
12
+
12
13
  @id = id
13
14
  @name = name
14
15
  end
15
16
 
16
17
  def name=(value)
17
- if name != value
18
- name = value
19
- if @published
20
- device.init do
21
- mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
22
- end
23
- end
18
+ return if name == value
19
+
20
+ name = value
21
+ return unless @published
22
+
23
+ device.init do
24
+ mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
24
25
  end
25
26
  end
26
27
  end
@@ -1,28 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mqtt'
3
+ require "mqtt"
4
+ require "ruby2_keywords"
4
5
 
5
6
  module MQTT
6
7
  module Homie
7
8
  class Device < Base
9
+ # the Homie spec version
10
+ VERSION = "4.0.0"
11
+
8
12
  attr_reader :root_topic, :state, :mqtt
13
+ attr_accessor :logger, :out_of_band_topic_proc
9
14
 
10
15
  def initialize(id, name, root_topic: nil, mqtt: nil, clear_topics: true, &block)
11
16
  super(id, name)
12
- @root_topic = @root_topic || "homie"
17
+ @root_topic = root_topic || "homie"
13
18
  @state = :init
14
19
  @nodes = {}
15
20
  @published = false
16
- @block = block
21
+ @out_of_band_topic_proc = block
17
22
  mqtt = MQTT::Client.new(mqtt) if mqtt.is_a?(String)
18
23
  @mqtt = mqtt || MQTT::Client.new
19
24
  @mqtt.set_will("#{topic}/$state", "lost", retain: true, qos: 1)
20
25
 
21
26
  @mqtt.on_reconnect do
22
27
  each do |node|
23
- node.each do |property|
24
- property.subscribe
25
- end
28
+ node.each(&:subscribe)
26
29
  end
27
30
  mqtt.publish("#{topic}/$state", :init, retain: true, qos: 1)
28
31
  mqtt.publish("#{topic}/$state", state, retain: true, qos: 1) unless state == :init
@@ -32,6 +35,10 @@ module MQTT
32
35
  self.clear_topics if clear_topics
33
36
  end
34
37
 
38
+ def inspect
39
+ "#<MQTT::Homie::Device #{topic} name=#{name.inspect}, $state=#{state.inspect}>"
40
+ end
41
+
35
42
  def device
36
43
  self
37
44
  end
@@ -40,11 +47,11 @@ module MQTT
40
47
  "#{root_topic}/#{id}"
41
48
  end
42
49
 
43
- def node(id, *args, **kwargs)
50
+ ruby2_keywords def node(id, *args)
44
51
  raise ArgumentError, "Node '#{id}' already exists" if @nodes.key?(id)
45
52
 
46
53
  init do |prior_state|
47
- node = Node.new(self, id, *args, **kwargs)
54
+ node = Node.new(self, id, *args)
48
55
 
49
56
  @nodes[id] = node
50
57
  yield node if block_given?
@@ -58,10 +65,11 @@ module MQTT
58
65
 
59
66
  def remove_node(id)
60
67
  return false unless (node = @nodes[id])
68
+
61
69
  init do
62
70
  node.unpublish
63
71
  @nodes.delete(id)
64
- mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if @published
72
+ mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if published?
65
73
  end
66
74
  true
67
75
  end
@@ -74,11 +82,19 @@ module MQTT
74
82
  @nodes.each_value(&block)
75
83
  end
76
84
 
85
+ def count
86
+ @nodes.count
87
+ end
88
+
89
+ def published?
90
+ @published
91
+ end
92
+
77
93
  def publish
78
- return if @published
94
+ return if published?
79
95
 
80
96
  mqtt.batch_publish do
81
- mqtt.publish("#{topic}/$homie", "4.0.0", retain: true, qos: 1)
97
+ mqtt.publish("#{topic}/$homie", VERSION, retain: true, qos: 1)
82
98
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
83
99
  mqtt.publish("#{topic}/$state", @state.to_s, retain: true, qos: 1)
84
100
 
@@ -87,12 +103,13 @@ module MQTT
87
103
  Thread.current.report_on_exception = false
88
104
 
89
105
  mqtt.get do |packet|
106
+ logger&.debug("received packet at #{packet.topic} with payload #{packet.payload.inspect}")
90
107
  match = packet.topic.match(topic_regex)
91
108
  node = @nodes[match[:node]] if match
92
109
  property = node[match[:property]] if node
93
110
 
94
111
  unless property&.settable?
95
- @block&.call(packet.topic, packet.payload)
112
+ @out_of_band_topic_proc&.call(packet.topic, packet.payload)
96
113
  next
97
114
  end
98
115
 
@@ -102,6 +119,9 @@ module MQTT
102
119
 
103
120
  mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1)
104
121
  @nodes.each_value(&:publish)
122
+
123
+ yield if block_given?
124
+
105
125
  mqtt.publish("#{topic}/$state", (@state = :ready).to_s, retain: true, qos: 1)
106
126
  end
107
127
 
@@ -122,26 +142,24 @@ module MQTT
122
142
  end
123
143
 
124
144
  def init
125
- if state == :init
126
- return yield state
127
- end
145
+ return yield state if state == :init
128
146
 
129
147
  prior_state = state
130
- mqtt.publish("#{topic}/$state", (state = :init).to_s, retain: true, qos: 1)
148
+ mqtt.publish("#{topic}/$state", (@state = :init).to_s, retain: true, qos: 1)
131
149
  result = nil
132
150
  mqtt.batch_publish do
133
151
  result = yield prior_state
134
152
  end
135
- mqtt.publish("#{topic}/$state", (state = :ready).to_s, retain: true, qos: 1)
153
+ mqtt.publish("#{topic}/$state", (@state = :ready).to_s, retain: true, qos: 1)
136
154
  result
137
155
  end
138
156
 
139
157
  def clear_topics
140
- raise ArgumentError, "cannot clear topics once published" if @published
158
+ raise ArgumentError, "cannot clear topics once published" if published?
141
159
 
142
160
  @mqtt.subscribe("#{topic}/#")
143
161
  @mqtt.unsubscribe("#{topic}/#", wait_for_ack: true)
144
- while !@mqtt.queue_empty?
162
+ until @mqtt.queue_empty?
145
163
  packet = @mqtt.get
146
164
  @mqtt.publish(packet.topic, retain: true, qos: 0)
147
165
  end
@@ -13,14 +13,25 @@ module MQTT
13
13
  @published = false
14
14
  end
15
15
 
16
+ def inspect
17
+ "#<MQTT::Homie::Node #{topic} name=#{full_name.inspect}, type=#{type.inspect}>"
18
+ end
19
+
20
+ def full_name
21
+ return name if device.count == 1
22
+
23
+ "#{device.name} #{name}"
24
+ end
25
+
16
26
  def topic
17
27
  "#{device.topic}/#{id}"
18
28
  end
19
29
 
20
- def property(*args, **kwargs, &block)
30
+ ruby2_keywords def property(*args, &block)
21
31
  device.init do |prior_state|
22
- property = Property.new(self, *args, **kwargs, &block)
32
+ property = Property.new(self, *args, &block)
23
33
  raise ArgumentError, "Property '#{property.id}' already exists on '#{id}'" if @properties.key?(property.id)
34
+
24
35
  @properties[property.id] = property
25
36
  property.publish if prior_state == :ready
26
37
  property
@@ -29,10 +40,11 @@ module MQTT
29
40
 
30
41
  def remove_property(id)
31
42
  return false unless (property = @properties[id])
43
+
32
44
  init do
33
45
  property.unpublish
34
46
  @properties.delete(id)
35
- mqtt.publish("#{topic}/$properties", @properties.keys.join(","), retain: true, qos: 1) if @published
47
+ mqtt.publish("#{topic}/$properties", @properties.keys.join(","), retain: true, qos: 1) if published?
36
48
  end
37
49
  true
38
50
  end
@@ -58,9 +70,13 @@ module MQTT
58
70
  end
59
71
  end
60
72
 
73
+ def published?
74
+ @published
75
+ end
76
+
61
77
  def publish
62
78
  mqtt.batch_publish do
63
- unless @published
79
+ unless published?
64
80
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
65
81
  mqtt.publish("#{topic}/$type", @type.to_s, retain: true, qos: 1)
66
82
  @published = true
@@ -72,7 +88,8 @@ module MQTT
72
88
  end
73
89
 
74
90
  def unpublish
75
- return unless @published
91
+ return unless published?
92
+
76
93
  @published = false
77
94
 
78
95
  mqtt.publish("#{topic}/$name", retain: true, qos: 0)
@@ -5,33 +5,61 @@ module MQTT
5
5
  class Property < Base
6
6
  attr_reader :node, :datatype, :format, :unit, :value
7
7
 
8
- def initialize(node, id, name, datatype, value = nil, format: nil, retained: true, unit: nil, &block)
9
- raise ArgumentError, "Invalid Homie datatype" unless %i[string integer float boolean enum color datetime duration].include?(datatype)
8
+ def initialize(node,
9
+ id,
10
+ name,
11
+ datatype,
12
+ value = nil,
13
+ format: nil,
14
+ retained: true,
15
+ unit: nil,
16
+ non_standard_value_check: nil,
17
+ &block)
18
+ raise ArgumentError, "Invalid Homie datatype" unless %i[string
19
+ integer
20
+ float
21
+ boolean
22
+ enum
23
+ color
24
+ datetime
25
+ duration].include?(datatype)
10
26
  raise ArgumentError, "retained must be boolean" unless [true, false].include?(retained)
11
- format = format.join(",") if format.is_a?(Array) && datatype == :enum
12
- if %i{integer float}.include?(datatype) && format.is_a?(Range)
13
- raise ArgumentError "only inclusive ranges are supported" if format.exclude_end?
14
- format = "#{format.begin}:#{format.end}"
15
- end
16
- raise ArgumentError, "format must be nil or a string" unless format.nil? || format.is_a?(String)
17
27
  raise ArgumentError, "unit must be nil or a string" unless unit.nil? || unit.is_a?(String)
18
- raise ArgumentError, "format is required for enums" if datatype == :enum && format.nil?
19
- raise ArgumentError, "format is required for colors" if datatype == :color && format.nil?
20
- raise ArgumentError, "format must be either rgb or hsv for colors" if datatype == :color && !%w{rgb hsv}.include?(format.to_s)
21
- raise ArgumentError, "an initial value cannot be provided for a non-retained property" if !value.nil? && !retained
28
+ if !value.nil? && !retained
29
+ raise ArgumentError, "an initial value cannot be provided for a non-retained property"
30
+ end
22
31
 
23
32
  super(id, name)
24
33
 
25
34
  @node = node
26
35
  @datatype = datatype
27
- @format = format
36
+ self.format = format
28
37
  @retained = retained
29
38
  @unit = unit
30
39
  @value = value
31
40
  @published = false
41
+ @non_standard_value_check = non_standard_value_check
32
42
  @block = block
33
43
  end
34
44
 
45
+ def inspect
46
+ result = +"#<MQTT::Homie::Property #{topic} name=#{full_name.inspect}, datatype=#{datatype.inspect}"
47
+ result << ", format=#{format.inspect}" if format
48
+ result << ", unit=#{unit.inspect}" if unit
49
+ result << ", settable=true" if settable?
50
+ result << if retained?
51
+ ", value=#{value.inspect}"
52
+ else
53
+ ", retained=false"
54
+ end
55
+ result << ">"
56
+ result.freeze
57
+ end
58
+
59
+ def full_name
60
+ "#{node.full_name} #{name}"
61
+ end
62
+
35
63
  def device
36
64
  node.device
37
65
  end
@@ -49,89 +77,110 @@ module MQTT
49
77
  end
50
78
 
51
79
  def value=(value)
52
- if @value != value
53
- @value = value if retained?
54
- publish_value if @published
55
- end
80
+ return if @value == value
81
+
82
+ @value = value if retained?
83
+ publish_value if published?
56
84
  end
57
85
 
58
86
  def unit=(unit)
59
- if unit != @unit
60
- @unit = unit
61
- if @published
62
- device.init do
63
- mqtt.publish("#{topic}/$unit", unit.to_s, retain: true, qos: 1)
64
- end
65
- end
87
+ return if unit == @unit
88
+
89
+ @unit = unit
90
+ return unless published?
91
+
92
+ device.init do
93
+ mqtt.publish("#{topic}/$unit", unit.to_s, retain: true, qos: 1)
66
94
  end
67
95
  end
68
96
 
69
97
  def format=(format)
70
- if format != @format
71
- @format = format
72
- if @published
73
- device.init do
74
- mqtt.publish("#{topic}/$format", format.to_s, retain: true, qos: 1)
75
- end
76
- end
98
+ return if format == @format
99
+
100
+ format = format.join(",") if format.is_a?(Array) && datatype == :enum
101
+ if %i[integer float].include?(datatype) && format.is_a?(Range)
102
+ raise ArgumentError, "only inclusive ranges are supported" if format.last.is_a?(Float) && format.exclude_end?
103
+
104
+ last = format.end
105
+ last -= 1 if format.exclude_end?
106
+
107
+ format = "#{format.begin}:#{last}"
108
+ end
109
+ raise ArgumentError, "format must be nil or a string" unless format.nil? || format.is_a?(String)
110
+ raise ArgumentError, "format is required for enums" if datatype == :enum && format.nil?
111
+ raise ArgumentError, "format is required for colors" if datatype == :color && format.nil?
112
+ if datatype == :color && !%w[rgb hsv].include?(format.to_s)
113
+ raise ArgumentError, "format must be either rgb or hsv for colors"
114
+ end
115
+
116
+ @format = format
117
+ return unless published?
118
+
119
+ device.init do
120
+ mqtt.publish("#{topic}/$format", format.to_s, retain: true, qos: 1)
77
121
  end
78
122
  end
79
123
 
80
124
  def range
125
+ return nil unless format
126
+
81
127
  case datatype
82
- when :enum; format.split(',')
83
- when :integer; Range.new(*format.split(':').map(&:to_i))
84
- when :float; Range.new(*format.split(':').map(&:to_f))
128
+ when :enum then format.split(",")
129
+ when :integer then Range.new(*format.split(":").map(&:to_i))
130
+ when :float then Range.new(*format.split(":").map(&:to_f))
85
131
  else; raise MethodNotImplemented
86
132
  end
87
133
  end
88
134
 
89
135
  def set(value)
136
+ casted_value = case datatype
137
+ when :boolean
138
+ %w[true false].include?(value) ? value == "true" : nil
139
+ when :integer
140
+ /^-?\d+$/.match?(value) && value.to_i
141
+ when :float
142
+ /^-?(?:\d+|\d+\.|\.\d+|\d+\.\d+)(?:[eE]-?\d+)?$/.match?(value) && value.to_f
143
+ when :enum
144
+ value
145
+ when :color
146
+ /^\d{1,3},\d{1,3},\d{1,3}$/.match?(value) && value = value.split(",").map(&:to_i)
147
+ when :datetime
148
+ begin
149
+ value = Time.parse(value)
150
+ rescue ArgumentError
151
+ nil
152
+ end
153
+ when :duration
154
+ begin
155
+ value = ActiveSupport::Duration.parse(value)
156
+ rescue ActiveSupport::Duration::ISO8601Parser::ParsingError
157
+ nil
158
+ end
159
+ end
90
160
  case datatype
91
- when :boolean
92
- return unless %w{true false}.include?(value)
93
- value = value == 'true'
94
- when :integer
95
- return unless value =~ /^-?\d+$/
96
- value = value.to_i
97
- return unless range.include?(value) if format
98
- when :float
99
- return unless value =~ /^-?(?:\d+|\d+\.|\.\d+|\d+\.\d+)(?:[eE]-?\d+)?$/
100
- value = value.to_f
101
- return unless range.include?(value) if format
102
- when :enum
103
- return unless range.include?(value)
161
+ when :integer, :float, :enum
162
+ casted_value = nil if format && !range.include?(casted_value)
104
163
  when :color
105
- return unless value =~ /^\d{1,3},\d{1,3},\d{1,3}$/
106
- value = value.split(',').map(&:to_i)
107
- if format == 'rgb'
108
- return if value.max > 255
109
- elsif format == 'hsv'
110
- return if value.first > 360 || value[1..2].max > 100
111
- end
112
- when :datetime
113
- begin
114
- value = Time.parse(value)
115
- rescue ArgumentError
116
- return
117
- end
118
- when :duration
119
- begin
120
- value = ActiveSupport::Duration.parse(value)
121
- rescue ActiveSupport::Duration::ISO8601Parser::ParsingError
122
- return
123
- end
164
+ casted_value = nil if (format == "rgb" && value.max > 255) ||
165
+ (format == "hsb" && (value.first > 360 || value[1..2].max > 100))
124
166
  end
125
167
 
126
- @block.arity == 2 ? @block.call(value, self) : @block.call(value)
168
+ casted_value = @non_standard_value_check&.call(value) if casted_value.nil?
169
+ return if casted_value.nil?
170
+
171
+ @block.arity == 2 ? @block.call(casted_value, self) : @block.call(casted_value)
127
172
  end
128
173
 
129
174
  def mqtt
130
175
  node.mqtt
131
176
  end
132
177
 
178
+ def published?
179
+ @published
180
+ end
181
+
133
182
  def publish
134
- return if @published
183
+ return if published?
135
184
 
136
185
  mqtt.batch_publish do
137
186
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
@@ -152,7 +201,8 @@ module MQTT
152
201
  end
153
202
 
154
203
  def unpublish
155
- return unless @published
204
+ return unless published?
205
+
156
206
  @published = false
157
207
 
158
208
  mqtt.publish("#{topic}/$name", retain: true, qos: 0)
@@ -170,8 +220,10 @@ module MQTT
170
220
  def publish_value
171
221
  serialized = value
172
222
  serialized = serialized&.iso8601 if %i[datetime duration].include?(datatype)
223
+ serialized = serialized.to_s
173
224
 
174
- mqtt.publish(topic, serialized.to_s, retain: retained?, qos: 1)
225
+ node.device.logger&.debug("publishing #{serialized.inspect} to #{topic}")
226
+ mqtt.publish(topic, serialized, retain: retained?, qos: 1)
175
227
  end
176
228
  end
177
229
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module MQTT
4
4
  module Homie
5
- VERSION = '1.4.2'
5
+ VERSION = "1.6.0"
6
6
  end
7
7
  end
data/lib/mqtt/homie.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MQTT
4
+ module Homie
5
+ class << self
6
+ def escape_id(id)
7
+ id.downcase.gsub(/[^a-z0-9\-]/, "-").sub(/^[^a-z0-9]+/, "")
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ require "mqtt/homie/base"
14
+ require "mqtt/homie/device"
15
+ require "mqtt/homie/node"
16
+ require "mqtt/homie/property"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: homie-mqtt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-26 00:00:00.000000000 Z
11
+ date: 2021-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mqtt-ccutrer
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.1
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,23 @@ dependencies:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
29
  version: '1.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: ruby2_keywords
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.0.5
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.0.5
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: byebug
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +72,48 @@ dependencies:
52
72
  - - "~>"
53
73
  - !ruby/object:Gem::Version
54
74
  version: '13.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rubocop
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.23'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.23'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rubocop-performance
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.12'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.12'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rubocop-rake
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.6'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.6'
55
117
  description:
56
118
  email: cody@cutrer.com'
57
119
  executables: []
@@ -59,6 +121,7 @@ extensions: []
59
121
  extra_rdoc_files: []
60
122
  files:
61
123
  - lib/homie-mqtt.rb
124
+ - lib/mqtt/homie.rb
62
125
  - lib/mqtt/homie/base.rb
63
126
  - lib/mqtt/homie/device.rb
64
127
  - lib/mqtt/homie/node.rb
@@ -67,7 +130,8 @@ files:
67
130
  homepage: https://github.com/ccutrer/homie-mqtt
68
131
  licenses:
69
132
  - MIT
70
- metadata: {}
133
+ metadata:
134
+ rubygems_mfa_required: 'true'
71
135
  post_install_message:
72
136
  rdoc_options: []
73
137
  require_paths:
@@ -76,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
140
  requirements:
77
141
  - - ">="
78
142
  - !ruby/object:Gem::Version
79
- version: '0'
143
+ version: '2.5'
80
144
  required_rubygems_version: !ruby/object:Gem::Requirement
81
145
  requirements:
82
146
  - - ">="