homie-mqtt 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8552d2aca44043208c3b3cd06fff9d5376515103d7de423926713441acecd6e0
4
- data.tar.gz: a27b5fe2fe50e2975708c308ed9a0f9b5b7d2469667741fe092210adcda8582a
3
+ metadata.gz: ac2d4aeded4ffe715b8de38705b648c3aa2c80d378f57435f7e5bd854f8eac22
4
+ data.tar.gz: d4503b114004ebed3cd4987ecc1466ff0c3e6637d474477fb8f9e43eaf4e91b0
5
5
  SHA512:
6
- metadata.gz: b10c773d61781b4fb2e5595056e1b5e41373ec579bcf0a152f0c5dc763c3973ad09914964caaaf9c619b079e6cf15f4dc923122caf214f571741b8b6934a8317
7
- data.tar.gz: dd8069070124dea54d81f3fc0095b9cce1d28d77ed655d7162182c0a11cdfecbb93cc40c97ea3778b3ebd35508cf960fdfcdd2594cac87f3621fdf11e64845c0
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"
@@ -69,7 +69,7 @@ module MQTT
69
69
  init do
70
70
  node.unpublish
71
71
  @nodes.delete(id)
72
- 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?
73
73
  end
74
74
  true
75
75
  end
@@ -86,8 +86,12 @@ module MQTT
86
86
  @nodes.count
87
87
  end
88
88
 
89
+ def published?
90
+ @published
91
+ end
92
+
89
93
  def publish
90
- return if @published
94
+ return if published?
91
95
 
92
96
  mqtt.batch_publish do
93
97
  mqtt.publish("#{topic}/$homie", VERSION, retain: true, qos: 1)
@@ -141,17 +145,17 @@ module MQTT
141
145
  return yield state if state == :init
142
146
 
143
147
  prior_state = state
144
- mqtt.publish("#{topic}/$state", (self.state = :init).to_s, retain: true, qos: 1)
148
+ mqtt.publish("#{topic}/$state", (@state = :init).to_s, retain: true, qos: 1)
145
149
  result = nil
146
150
  mqtt.batch_publish do
147
151
  result = yield prior_state
148
152
  end
149
- mqtt.publish("#{topic}/$state", (self.state = :ready).to_s, retain: true, qos: 1)
153
+ mqtt.publish("#{topic}/$state", (@state = :ready).to_s, retain: true, qos: 1)
150
154
  result
151
155
  end
152
156
 
153
157
  def clear_topics
154
- raise ArgumentError, "cannot clear topics once published" if @published
158
+ raise ArgumentError, "cannot clear topics once published" if published?
155
159
 
156
160
  @mqtt.subscribe("#{topic}/#")
157
161
  @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
 
@@ -5,24 +5,26 @@ 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
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
10
25
  duration].include?(datatype)
11
26
  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
27
  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
28
  if !value.nil? && !retained
27
29
  raise ArgumentError, "an initial value cannot be provided for a non-retained property"
28
30
  end
@@ -31,11 +33,12 @@ module MQTT
31
33
 
32
34
  @node = node
33
35
  @datatype = datatype
34
- @format = format
36
+ self.format = format
35
37
  @retained = retained
36
38
  @unit = unit
37
39
  @value = value
38
40
  @published = false
41
+ @non_standard_value_check = non_standard_value_check
39
42
  @block = block
40
43
  end
41
44
 
@@ -77,14 +80,14 @@ module MQTT
77
80
  return if @value == value
78
81
 
79
82
  @value = value if retained?
80
- publish_value if @published
83
+ publish_value if published?
81
84
  end
82
85
 
83
86
  def unit=(unit)
84
87
  return if unit == @unit
85
88
 
86
89
  @unit = unit
87
- return unless @published
90
+ return unless published?
88
91
 
89
92
  device.init do
90
93
  mqtt.publish("#{topic}/$unit", unit.to_s, retain: true, qos: 1)
@@ -94,8 +97,24 @@ module MQTT
94
97
  def format=(format)
95
98
  return if format == @format
96
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
+
97
116
  @format = format
98
- return unless @published
117
+ return unless published?
99
118
 
100
119
  device.init do
101
120
  mqtt.publish("#{topic}/$format", format.to_s, retain: true, qos: 1)
@@ -114,56 +133,54 @@ module MQTT
114
133
  end
115
134
 
116
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
117
160
  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)
132
- when :enum
133
- return unless range.include?(value)
161
+ when :integer, :float, :enum
162
+ casted_value = nil if format && !range.include?(casted_value)
134
163
  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
164
+ casted_value = nil if (format == "rgb" && value.max > 255) ||
165
+ (format == "hsb" && (value.first > 360 || value[1..2].max > 100))
156
166
  end
157
167
 
158
- @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)
159
172
  end
160
173
 
161
174
  def mqtt
162
175
  node.mqtt
163
176
  end
164
177
 
178
+ def published?
179
+ @published
180
+ end
181
+
165
182
  def publish
166
- return if @published
183
+ return if published?
167
184
 
168
185
  mqtt.batch_publish do
169
186
  mqtt.publish("#{topic}/$name", name, retain: true, qos: 1)
@@ -184,7 +201,7 @@ module MQTT
184
201
  end
185
202
 
186
203
  def unpublish
187
- return unless @published
204
+ return unless published?
188
205
 
189
206
  @published = false
190
207
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module MQTT
4
4
  module Homie
5
- VERSION = "1.5.0"
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.5.0
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-12-08 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
@@ -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