homie-mqtt 1.5.0 → 1.6.2

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: 8552d2aca44043208c3b3cd06fff9d5376515103d7de423926713441acecd6e0
4
- data.tar.gz: a27b5fe2fe50e2975708c308ed9a0f9b5b7d2469667741fe092210adcda8582a
3
+ metadata.gz: 20210b0338d6fa60e38cea5fbb830a26ae4c9d3a919ab8e7c1d373893afbc792
4
+ data.tar.gz: 479bbfe1fad83e2d872b319ab5deb22b394ed3ab846876acce0ae46e71b06435
5
5
  SHA512:
6
- metadata.gz: b10c773d61781b4fb2e5595056e1b5e41373ec579bcf0a152f0c5dc763c3973ad09914964caaaf9c619b079e6cf15f4dc923122caf214f571741b8b6934a8317
7
- data.tar.gz: dd8069070124dea54d81f3fc0095b9cce1d28d77ed655d7162182c0a11cdfecbb93cc40c97ea3778b3ebd35508cf960fdfcdd2594cac87f3621fdf11e64845c0
6
+ metadata.gz: 5ef7fddffafe4f8dfc4cd44551f1d3c1c867bc10762c706121571e3dc3207bb25170edb7054f4058f01393707c7772999335bfe2e0fc47806533f0f6ff6229c4
7
+ data.tar.gz: 34a8a0aae900bcdef55a03ad878f5261655cbf45e62758cfb72dc658fd0263f962902fc21db6e083f4bbc486928131b754b43c14cbaaa89773105dabfaaceb00
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"
@@ -19,8 +19,10 @@ module MQTT
19
19
  @nodes = {}
20
20
  @published = false
21
21
  @out_of_band_topic_proc = block
22
- mqtt = MQTT::Client.new(mqtt) if mqtt.is_a?(String)
23
- @mqtt = mqtt || MQTT::Client.new
22
+ # retry forever
23
+ mqtt = MQTT::Client.new(mqtt, reconnect_limit: nil) if mqtt.is_a?(String)
24
+ mqtt = MQTT::Client.new(reconnect_limit: nil, **mqtt) if mqtt.is_a?(Hash)
25
+ @mqtt = mqtt || MQTT::Client.new(reconnect_limit: nil)
24
26
  @mqtt.set_will("#{topic}/$state", "lost", retain: true, qos: 1)
25
27
 
26
28
  @mqtt.on_reconnect do
@@ -69,7 +71,7 @@ module MQTT
69
71
  init do
70
72
  node.unpublish
71
73
  @nodes.delete(id)
72
- mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if @published
74
+ mqtt.publish("#{topic}/$nodes", @nodes.keys.join(","), retain: true, qos: 1) if published?
73
75
  end
74
76
  true
75
77
  end
@@ -86,8 +88,12 @@ module MQTT
86
88
  @nodes.count
87
89
  end
88
90
 
91
+ def published?
92
+ @published
93
+ end
94
+
89
95
  def publish
90
- return if @published
96
+ return if published?
91
97
 
92
98
  mqtt.batch_publish do
93
99
  mqtt.publish("#{topic}/$homie", VERSION, retain: true, qos: 1)
@@ -141,17 +147,17 @@ module MQTT
141
147
  return yield state if state == :init
142
148
 
143
149
  prior_state = state
144
- mqtt.publish("#{topic}/$state", (self.state = :init).to_s, retain: true, qos: 1)
150
+ mqtt.publish("#{topic}/$state", (@state = :init).to_s, retain: true, qos: 1)
145
151
  result = nil
146
152
  mqtt.batch_publish do
147
153
  result = yield prior_state
148
154
  end
149
- mqtt.publish("#{topic}/$state", (self.state = :ready).to_s, retain: true, qos: 1)
155
+ mqtt.publish("#{topic}/$state", (@state = :ready).to_s, retain: true, qos: 1)
150
156
  result
151
157
  end
152
158
 
153
159
  def clear_topics
154
- raise ArgumentError, "cannot clear topics once published" if @published
160
+ raise ArgumentError, "cannot clear topics once published" if published?
155
161
 
156
162
  @mqtt.subscribe("#{topic}/#")
157
163
  @mqtt.unsubscribe("#{topic}/#", wait_for_ack: true)
@@ -44,7 +44,7 @@ module MQTT
44
44
  init do
45
45
  property.unpublish
46
46
  @properties.delete(id)
47
- 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?
48
48
  end
49
49
  true
50
50
  end
@@ -70,9 +70,13 @@ module MQTT
70
70
  end
71
71
  end
72
72
 
73
+ def published?
74
+ @published
75
+ end
76
+
73
77
  def publish
74
78
  mqtt.batch_publish do
75
- unless @published
79
+ unless published?
76
80
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
77
81
  mqtt.publish("#{topic}/$type", @type.to_s, retain: true, qos: 1)
78
82
  @published = true
@@ -84,7 +88,7 @@ module MQTT
84
88
  end
85
89
 
86
90
  def unpublish
87
- return unless @published
91
+ return unless published?
88
92
 
89
93
  @published = false
90
94
 
@@ -1,28 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "time"
4
+
3
5
  module MQTT
4
6
  module Homie
5
7
  class Property < Base
6
8
  attr_reader :node, :datatype, :format, :unit, :value
7
9
 
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
10
+ def initialize(node,
11
+ id,
12
+ name,
13
+ datatype,
14
+ value = nil,
15
+ format: nil,
16
+ retained: true,
17
+ unit: nil,
18
+ non_standard_value_check: nil,
19
+ &block)
20
+ raise ArgumentError, "Invalid Homie datatype" unless %i[string
21
+ integer
22
+ float
23
+ boolean
24
+ enum
25
+ color
26
+ datetime
10
27
  duration].include?(datatype)
11
28
  raise ArgumentError, "retained must be boolean" unless [true, false].include?(retained)
12
-
13
- format = format.join(",") if format.is_a?(Array) && datatype == :enum
14
- if %i[integer float].include?(datatype) && format.is_a?(Range)
15
- raise ArgumentError "only inclusive ranges are supported" if format.exclude_end?
16
-
17
- format = "#{format.begin}:#{format.end}"
18
- end
19
- raise ArgumentError, "format must be nil or a string" unless format.nil? || format.is_a?(String)
20
29
  raise ArgumentError, "unit must be nil or a string" unless unit.nil? || unit.is_a?(String)
21
- raise ArgumentError, "format is required for enums" if datatype == :enum && format.nil?
22
- raise ArgumentError, "format is required for colors" if datatype == :color && format.nil?
23
- if datatype == :color && !%w[rgb hsv].include?(format.to_s)
24
- raise ArgumentError, "format must be either rgb or hsv for colors"
25
- end
26
30
  if !value.nil? && !retained
27
31
  raise ArgumentError, "an initial value cannot be provided for a non-retained property"
28
32
  end
@@ -31,11 +35,12 @@ module MQTT
31
35
 
32
36
  @node = node
33
37
  @datatype = datatype
34
- @format = format
38
+ self.format = format
35
39
  @retained = retained
36
40
  @unit = unit
37
41
  @value = value
38
42
  @published = false
43
+ @non_standard_value_check = non_standard_value_check
39
44
  @block = block
40
45
  end
41
46
 
@@ -77,14 +82,14 @@ module MQTT
77
82
  return if @value == value
78
83
 
79
84
  @value = value if retained?
80
- publish_value if @published
85
+ publish_value if published?
81
86
  end
82
87
 
83
88
  def unit=(unit)
84
89
  return if unit == @unit
85
90
 
86
91
  @unit = unit
87
- return unless @published
92
+ return unless published?
88
93
 
89
94
  device.init do
90
95
  mqtt.publish("#{topic}/$unit", unit.to_s, retain: true, qos: 1)
@@ -94,8 +99,24 @@ module MQTT
94
99
  def format=(format)
95
100
  return if format == @format
96
101
 
102
+ format = format.join(",") if format.is_a?(Array) && datatype == :enum
103
+ if %i[integer float].include?(datatype) && format.is_a?(Range)
104
+ raise ArgumentError, "only inclusive ranges are supported" if format.last.is_a?(Float) && format.exclude_end?
105
+
106
+ last = format.end
107
+ last -= 1 if format.exclude_end?
108
+
109
+ format = "#{format.begin}:#{last}"
110
+ end
111
+ raise ArgumentError, "format must be nil or a string" unless format.nil? || format.is_a?(String)
112
+ raise ArgumentError, "format is required for enums" if datatype == :enum && format.nil?
113
+ raise ArgumentError, "format is required for colors" if datatype == :color && format.nil?
114
+ if datatype == :color && !%w[rgb hsv].include?(format.to_s)
115
+ raise ArgumentError, "format must be either rgb or hsv for colors"
116
+ end
117
+
97
118
  @format = format
98
- return unless @published
119
+ return unless published?
99
120
 
100
121
  device.init do
101
122
  mqtt.publish("#{topic}/$format", format.to_s, retain: true, qos: 1)
@@ -114,56 +135,56 @@ module MQTT
114
135
  end
115
136
 
116
137
  def set(value)
138
+ casted_value = case datatype
139
+ when :boolean
140
+ %w[true false].include?(value) ? value == "true" : nil
141
+ when :integer
142
+ /^-?\d+$/.match?(value) && value.to_i
143
+ when :float
144
+ /^-?(?:\d+|\d+\.|\.\d+|\d+\.\d+)(?:[eE]-?\d+)?$/.match?(value) && value.to_f
145
+ when :enum
146
+ value
147
+ when :color
148
+ /^\d{1,3},\d{1,3},\d{1,3}$/.match?(value) && value = value.split(",").map(&:to_i)
149
+ when :datetime
150
+ begin
151
+ value = Time.parse(value)
152
+ rescue ArgumentError
153
+ nil
154
+ end
155
+ when :duration
156
+ begin
157
+ value = ActiveSupport::Duration.parse(value)
158
+ rescue ActiveSupport::Duration::ISO8601Parser::ParsingError
159
+ nil
160
+ end
161
+ end
117
162
  case datatype
118
- when :boolean
119
- return unless %w[true false].include?(value)
120
-
121
- value = value == "true"
122
- when :integer
123
- return unless /^-?\d+$/.match?(value)
124
-
125
- value = value.to_i
126
- return if format && !range.include?(value)
127
- when :float
128
- return unless /^-?(?:\d+|\d+\.|\.\d+|\d+\.\d+)(?:[eE]-?\d+)?$/.match?(value)
129
-
130
- value = value.to_f
131
- return if format && !range.include?(value)
163
+ when :integer, :float
164
+ casted_value = nil if format && !range.cover?(casted_value)
132
165
  when :enum
133
- return unless range.include?(value)
166
+ casted_value = nil if format && !range.include?(casted_value)
134
167
  when :color
135
- return unless /^\d{1,3},\d{1,3},\d{1,3}$/.match?(value)
136
-
137
- value = value.split(",").map(&:to_i)
138
- case format
139
- when "rgb"
140
- return if value.max > 255
141
- when "hsv"
142
- return if value.first > 360 || value[1..2].max > 100
143
- end
144
- when :datetime
145
- begin
146
- value = Time.parse(value)
147
- rescue ArgumentError
148
- return
149
- end
150
- when :duration
151
- begin
152
- value = ActiveSupport::Duration.parse(value)
153
- rescue ActiveSupport::Duration::ISO8601Parser::ParsingError
154
- return
155
- end
168
+ casted_value = nil if (format == "rgb" && value.max > 255) ||
169
+ (format == "hsb" && (value.first > 360 || value[1..2].max > 100))
156
170
  end
157
171
 
158
- @block.arity == 2 ? @block.call(value, self) : @block.call(value)
172
+ casted_value = @non_standard_value_check&.call(value) if casted_value.nil?
173
+ return if casted_value.nil?
174
+
175
+ @block.arity == 2 ? @block.call(casted_value, self) : @block.call(casted_value)
159
176
  end
160
177
 
161
178
  def mqtt
162
179
  node.mqtt
163
180
  end
164
181
 
182
+ def published?
183
+ @published
184
+ end
185
+
165
186
  def publish
166
- return if @published
187
+ return if published?
167
188
 
168
189
  mqtt.batch_publish do
169
190
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
@@ -184,7 +205,7 @@ module MQTT
184
205
  end
185
206
 
186
207
  def unpublish
187
- return unless @published
208
+ return unless published?
188
209
 
189
210
  @published = false
190
211
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module MQTT
4
4
  module Homie
5
- VERSION = "1.5.0"
5
+ VERSION = "1.6.2"
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.5.0
4
+ version: 1.6.2
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-12-08 00:00:00.000000000 Z
11
+ date: 2022-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mqtt-ccutrer
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '1.0'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.0.1
22
+ version: 1.0.3
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '1.0'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 1.0.1
32
+ version: 1.0.3
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: ruby2_keywords
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -121,6 +121,7 @@ extensions: []
121
121
  extra_rdoc_files: []
122
122
  files:
123
123
  - lib/homie-mqtt.rb
124
+ - lib/mqtt/homie.rb
124
125
  - lib/mqtt/homie/base.rb
125
126
  - lib/mqtt/homie/device.rb
126
127
  - lib/mqtt/homie/node.rb
@@ -146,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  - !ruby/object:Gem::Version
147
148
  version: '0'
148
149
  requirements: []
149
- rubygems_version: 3.1.2
150
+ rubygems_version: 3.3.5
150
151
  signing_key:
151
152
  specification_version: 4
152
153
  summary: Library for publishing devices that conform to the Homie spec.