mqtt-homie-homeassistant 1.0.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
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ea47bfb9fc5d373702f2edf0bd746412d12cd884132d87f098fdd29a5b552b51
|
4
|
+
data.tar.gz: a229e5225e2a77daadb9caca7edb547da464211dc0f66aa3840429015970e39a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4df1f4dff3da9e5becc45c539720383b7f0f9fed40125412a03b668b5048fff2a9206a01f831f140e986c0a5844d4ae016b5586228ae0d4b1a1710dd49097b9
|
7
|
+
data.tar.gz: 73d1824ec2f29d95414368a1fbbc360c0a250ce54e0a0fecfc93c2c4dd1d2086fcca7f71c2c7b3e33e545c331d69d31da237ff1a8ec15b3f0b0d548218175e5b
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MQTT
|
4
|
+
module Homie
|
5
|
+
module HomeAssistant
|
6
|
+
module Device
|
7
|
+
def self.included(klass)
|
8
|
+
super
|
9
|
+
klass.attr_accessor :home_assistant_device, :home_assistant_discovery_prefix
|
10
|
+
end
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
def base_hass_config(config)
|
14
|
+
config[:availability] = [{
|
15
|
+
topic: "#{topic}/$state",
|
16
|
+
payload_available: "ready",
|
17
|
+
payload_not_available: "lost"
|
18
|
+
}]
|
19
|
+
config[:device] ||= {}
|
20
|
+
config[:device][:name] ||= name
|
21
|
+
config[:device][:identifiers] ||= id
|
22
|
+
config[:device][:sw_version] ||= MQTT::Homie::Device::VERSION
|
23
|
+
config[:node_id] = id
|
24
|
+
config[:qos] = 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Device.include(HomeAssistant::Device)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MQTT
|
4
|
+
module Homie
|
5
|
+
module HomeAssistant
|
6
|
+
module Node
|
7
|
+
def hass_climate(action_property: nil,
|
8
|
+
current_humidity_property: nil,
|
9
|
+
current_temperature_property: nil,
|
10
|
+
fan_mode_property: nil,
|
11
|
+
mode_property: nil,
|
12
|
+
power_property: nil,
|
13
|
+
preset_mode_property: nil,
|
14
|
+
swing_mode_property: nil,
|
15
|
+
target_humidity_property: nil,
|
16
|
+
temperature_property: nil,
|
17
|
+
temperature_high_property: nil,
|
18
|
+
temperature_low_property: nil,
|
19
|
+
**kwargs)
|
20
|
+
if power_property && power_property.datatype != :boolean
|
21
|
+
raise ArgumentError, "Power property must be a boolean"
|
22
|
+
end
|
23
|
+
|
24
|
+
temperature_property = resolve_property(temperature_property)
|
25
|
+
temperature_high_property = resolve_property(temperature_high_property)
|
26
|
+
temperature_low_property = resolve_property(temperature_low_property)
|
27
|
+
temp_properties = [
|
28
|
+
temperature_property,
|
29
|
+
temperature_high_property,
|
30
|
+
temperature_low_property
|
31
|
+
].compact
|
32
|
+
unless (temp_ranges = temp_properties.map(&:range).compact).empty?
|
33
|
+
min = temp_ranges.map(&:begin).min
|
34
|
+
max = temp_ranges.map(&:end).max
|
35
|
+
kwargs[:temp_range] = min..max
|
36
|
+
end
|
37
|
+
kwargs[:temperature_unit] = temp_properties.map(&:unit).compact.first
|
38
|
+
if power_property
|
39
|
+
kwargs[:payload_off] = "false"
|
40
|
+
kwargs[:payload_on] = "true"
|
41
|
+
end
|
42
|
+
|
43
|
+
hass_property(kwargs, action_property, :action, read_only: true)
|
44
|
+
hass_property(kwargs, current_humidity_property, :current_humidity, read_only: true)
|
45
|
+
hass_property(kwargs, current_temperature_property, :current_temperature, read_only: true)
|
46
|
+
hass_enum(kwargs, fan_mode_property, :fan_mode)
|
47
|
+
hass_enum(kwargs, mode_property, :mode, MQTT::HomeAssistant::DEFAULTS[:climate][:modes])
|
48
|
+
hass_property(kwargs, power_property, :power)
|
49
|
+
hass_enum(kwargs, preset_mode_property, :preset_mode)
|
50
|
+
hass_enum(kwargs, swing_mode_property, :swing_mode)
|
51
|
+
hass_property(kwargs, target_humidity_property, :target_humidity)
|
52
|
+
hass_property(kwargs, temperature_property, :temperature)
|
53
|
+
hass_property(kwargs, temperature_high_property, :temperature_high)
|
54
|
+
hass_property(kwargs, temperature_low_property, :temperature_low)
|
55
|
+
publish_hass_component(platform: :climate, **kwargs)
|
56
|
+
end
|
57
|
+
|
58
|
+
def hass_fan(property,
|
59
|
+
oscillation_property: nil,
|
60
|
+
preset_mode_property: nil,
|
61
|
+
**kwargs)
|
62
|
+
hass_property(kwargs, property)
|
63
|
+
hass_property(kwargs, oscillation_property, :oscillation)
|
64
|
+
hass_enum(kwargs, preset_mode_property, :preset_mode)
|
65
|
+
publish_hass_component(platform: :fan, **kwargs)
|
66
|
+
end
|
67
|
+
|
68
|
+
def hass_humidifier(property,
|
69
|
+
target_humidity_property: nil,
|
70
|
+
mode_property: nil,
|
71
|
+
**kwargs)
|
72
|
+
hass_property(kwargs, property)
|
73
|
+
hass_property(kwargs, target_humidity_property, :target_humidity)
|
74
|
+
hass_property(kwargs, mode_property, :mode)
|
75
|
+
publish_hass_component(platform: :humidifier,
|
76
|
+
payload_off: "false",
|
77
|
+
payload_on: "true",
|
78
|
+
**kwargs)
|
79
|
+
end
|
80
|
+
|
81
|
+
def hass_light(property = nil,
|
82
|
+
brightness_property: nil,
|
83
|
+
color_mode_property: nil,
|
84
|
+
color_temp_property: nil,
|
85
|
+
effect_property: nil,
|
86
|
+
hs_property: nil,
|
87
|
+
rgb_property: nil,
|
88
|
+
white_property: nil,
|
89
|
+
xy_property: nil,
|
90
|
+
**kwargs)
|
91
|
+
# automatically infer a brightness-only light and adjust config
|
92
|
+
if brightness_property && property.nil?
|
93
|
+
property = brightness_property
|
94
|
+
kwargs[:on_command_type] = :brightness
|
95
|
+
end
|
96
|
+
case property.datatype
|
97
|
+
when :boolean
|
98
|
+
kwargs[:payload_off] = "false"
|
99
|
+
kwargs[:payload_on] = "true"
|
100
|
+
when :integer
|
101
|
+
kwargs[:payload_off] = "0"
|
102
|
+
when :float
|
103
|
+
kwargs[:payload_off] = "0.0"
|
104
|
+
end
|
105
|
+
kwargs[:brightness_scale] = brightness_property.range.end if brightness_property&.range
|
106
|
+
kwargs[:effect_list] = effect_property.range if effect_property&.datatype == :enum
|
107
|
+
kwargs[:mireds_range] = color_temp_property.range if color_temp_property.unit == "mired"
|
108
|
+
kwargs[:white_scale] = white_property.range.end if white_property&.range
|
109
|
+
|
110
|
+
hass_property(kwargs, property)
|
111
|
+
hass_property(kwargs, brightness_property, :brightness)
|
112
|
+
hass_property(kwargs, color_mode_property, :color_mode)
|
113
|
+
hass_property(kwargs, color_temp_property, :color_temp)
|
114
|
+
hass_property(kwargs, effect_property, :effect)
|
115
|
+
hass_property(kwargs, hs_property, :hs)
|
116
|
+
hass_property(kwargs, rgb_property, :rgb)
|
117
|
+
hass_property(kwargs, white_property, :white)
|
118
|
+
hass_property(kwargs, xy_property, :xy)
|
119
|
+
publish_hass_component(platform: :light, **kwargs)
|
120
|
+
end
|
121
|
+
|
122
|
+
def hass_water_heater(
|
123
|
+
current_temperature_property: nil,
|
124
|
+
mode_property: nil,
|
125
|
+
power_property: nil,
|
126
|
+
temperature_property: nil,
|
127
|
+
**kwargs)
|
128
|
+
temperature_property = resolve_property(temperature_property)
|
129
|
+
current_temperature_property = resolve_property(current_temperature_property)
|
130
|
+
temp_properties = [
|
131
|
+
temperature_property,
|
132
|
+
current_temperature_property
|
133
|
+
].compact
|
134
|
+
kwargs[:range] = temperature_property&.range
|
135
|
+
kwargs[:temperature_unit] = temp_properties.map(&:unit).compact.first
|
136
|
+
if power_property
|
137
|
+
kwargs[:payload_off] = "false"
|
138
|
+
kwargs[:payload_on] = "true"
|
139
|
+
end
|
140
|
+
hass_property(kwargs, current_temperature_property, :current_temperature, read_only: true)
|
141
|
+
hass_enum(kwargs, mode_property, :mode, MQTT::HomeAssistant::DEFAULTS[:water_heater][:modes])
|
142
|
+
hass_property(kwargs, power_property, :power)
|
143
|
+
hass_property(kwargs, temperature_property, :temperature)
|
144
|
+
publish_hass_component(platform: :water_heater, **kwargs)
|
145
|
+
end
|
146
|
+
|
147
|
+
def publish
|
148
|
+
super.tap do
|
149
|
+
@pending_hass_registrations&.each do |(object_id, kwargs)|
|
150
|
+
device.mqtt.publish_hass_component(object_id, **kwargs)
|
151
|
+
end
|
152
|
+
@pending_hass_registrations = nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def resolve_property(property)
|
159
|
+
return if property.nil?
|
160
|
+
|
161
|
+
orig_property = property
|
162
|
+
property = self[property] if property.is_a?(String)
|
163
|
+
raise ArgumentError, "Unknown property #{orig_property}" if property.nil?
|
164
|
+
|
165
|
+
property
|
166
|
+
end
|
167
|
+
|
168
|
+
def hass_property(config, property, prefix = nil, read_only: false, templates: {})
|
169
|
+
resolve_property(property)&.hass_property(config, prefix, read_only: read_only, templates: templates)
|
170
|
+
end
|
171
|
+
|
172
|
+
def hass_enum(config, property, prefix = nil, valid_set = nil)
|
173
|
+
return if property.nil?
|
174
|
+
|
175
|
+
property = resolve_property(property)
|
176
|
+
hass_property(config, property, prefix)
|
177
|
+
|
178
|
+
return unless property.datatype == :enum
|
179
|
+
|
180
|
+
values = property.range
|
181
|
+
values &= valid_set if valid_set
|
182
|
+
config[:"#{prefix}s"] = values
|
183
|
+
end
|
184
|
+
|
185
|
+
def publish_hass_component(device: nil, discovery_prefix: nil, object_id: nil, **kwargs)
|
186
|
+
discovery_prefix ||= self.device.home_assistant_discovery_prefix
|
187
|
+
device = self.device.home_assistant_device.merge(device || {}) if self.device.home_assistant_device
|
188
|
+
|
189
|
+
object_id ||= id
|
190
|
+
kwargs[:name] ||= name
|
191
|
+
kwargs[:device] = device
|
192
|
+
kwargs[:discovery_prefix] ||= discovery_prefix
|
193
|
+
kwargs[:unique_id] ||= "#{self.device.id}_#{object_id}"
|
194
|
+
self.device.base_hass_config(kwargs)
|
195
|
+
if published?
|
196
|
+
self.device.mqtt.publish_hass_component(object_id, **kwargs)
|
197
|
+
else
|
198
|
+
pending_hass_registrations << [object_id, kwargs]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def pending_hass_registrations
|
203
|
+
@pending_hass_registrations ||= []
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
Node.prepend(HomeAssistant::Node)
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MQTT
|
4
|
+
module Homie
|
5
|
+
module HomeAssistant
|
6
|
+
module Property
|
7
|
+
def initialize(*args, hass: nil, **kwargs)
|
8
|
+
super(*args, **kwargs)
|
9
|
+
|
10
|
+
return unless hass
|
11
|
+
|
12
|
+
case hass
|
13
|
+
when Symbol
|
14
|
+
public_send("hass_#{hass}")
|
15
|
+
when Hash
|
16
|
+
raise ArgumentError, "hass must only contain one item" unless hass.length == 1
|
17
|
+
|
18
|
+
public_send("hass_#{hass.first.first}", **hass.first.last)
|
19
|
+
else
|
20
|
+
raise ArgumentError, "hass must be a Symbol or a Hash of HASS device type to additional HASS options"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def hass_binary_sensor(**kwargs)
|
25
|
+
raise ArgumentError, "Property must be a boolean" unless datatype == :boolean
|
26
|
+
raise ArgumentError, "Property must not be settable" if settable?
|
27
|
+
|
28
|
+
hass_property(kwargs)
|
29
|
+
publish_hass_component(platform: :binary_sensor,
|
30
|
+
payload_off: "false",
|
31
|
+
payload_on: "true",
|
32
|
+
**kwargs)
|
33
|
+
end
|
34
|
+
|
35
|
+
def hass_fan(**kwargs)
|
36
|
+
raise ArgumentError, "Property must be a boolean" unless datatype == :boolean
|
37
|
+
raise ArgumentError, "Property must be settable" unless settable?
|
38
|
+
|
39
|
+
hass_property(kwargs)
|
40
|
+
publish_hass_component(platform: :fan,
|
41
|
+
payload_off: "false",
|
42
|
+
payload_on: "true",
|
43
|
+
**kwargs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hass_light(**kwargs)
|
47
|
+
case datatype
|
48
|
+
when :boolean
|
49
|
+
kwargs[:payload_off] = "false"
|
50
|
+
kwargs[:payload_on] = "true"
|
51
|
+
when :integer
|
52
|
+
kwargs[:payload_off] = "0"
|
53
|
+
when :float
|
54
|
+
kwargs[:payload_off] = "0.0"
|
55
|
+
end
|
56
|
+
|
57
|
+
hass_property(kwargs)
|
58
|
+
publish_hass_component(platform: :light, **kwargs)
|
59
|
+
end
|
60
|
+
|
61
|
+
def hass_number(**kwargs)
|
62
|
+
raise ArgumentError, "Property must be an integer or a float" unless %i[integer float].include?(datatype)
|
63
|
+
|
64
|
+
hass_property(kwargs)
|
65
|
+
kwargs[:range] = range if range
|
66
|
+
kwargs[:unit_of_measurement] = unit if unit
|
67
|
+
|
68
|
+
publish_hass_component(platform: :number, **kwargs)
|
69
|
+
end
|
70
|
+
|
71
|
+
def hass_scene(**kwargs)
|
72
|
+
unless datatype == :enum && range.length == 1
|
73
|
+
raise ArgumentError, "Property must be an enum with a single value"
|
74
|
+
end
|
75
|
+
raise ArgumentError, "Property must be settable" unless settable?
|
76
|
+
|
77
|
+
publish_hass_component(platform: :scene,
|
78
|
+
command_topic: "#{topic}/set",
|
79
|
+
payload_on: range.first,
|
80
|
+
**kwargs)
|
81
|
+
end
|
82
|
+
|
83
|
+
def hass_select(**kwargs)
|
84
|
+
raise ArgumentError, "Property must be an enum" unless datatype == :enum
|
85
|
+
raise ArgumentError, "Property must be settable" unless settable?
|
86
|
+
|
87
|
+
hass_property(kwargs)
|
88
|
+
publish_hass_component(platform: :select, options: range, **kwargs)
|
89
|
+
end
|
90
|
+
|
91
|
+
def hass_sensor(**kwargs)
|
92
|
+
if datatype == :enum
|
93
|
+
kwargs[:device_class] = :enum
|
94
|
+
kwargs[:options] = range
|
95
|
+
end
|
96
|
+
|
97
|
+
publish_hass_component(platform: :sensor,
|
98
|
+
state_topic: topic,
|
99
|
+
**kwargs)
|
100
|
+
end
|
101
|
+
|
102
|
+
def hass_switch(**kwargs)
|
103
|
+
raise ArgumentError, "Property must be a boolean" unless datatype == :boolean
|
104
|
+
|
105
|
+
hass_property(kwargs)
|
106
|
+
publish_hass_component(platform: :switch,
|
107
|
+
payload_off: "false",
|
108
|
+
payload_on: "true",
|
109
|
+
**kwargs)
|
110
|
+
end
|
111
|
+
|
112
|
+
def publish
|
113
|
+
super.tap do
|
114
|
+
@pending_hass_registrations&.each do |(object_id, kwargs)|
|
115
|
+
device.mqtt.publish_hass_component(object_id, **kwargs)
|
116
|
+
end
|
117
|
+
@pending_hass_registrations = nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @!visibility private
|
122
|
+
def hass_property(config, prefix = nil, read_only: false, templates: {})
|
123
|
+
prefix = "#{prefix}_" if prefix
|
124
|
+
state_prefix = "state_" unless read_only
|
125
|
+
config[:"#{prefix}#{state_prefix}topic"] = topic if retained?
|
126
|
+
if !read_only && settable?
|
127
|
+
config[:"#{prefix}command_topic"] = "#{topic}/set"
|
128
|
+
config[:"#{prefix}command_template"] = "{{ value | round(0) }}" if datatype == :integer
|
129
|
+
end
|
130
|
+
config.merge!(templates.slice(:"#{prefix}template", :"#{prefix}command_template"))
|
131
|
+
end
|
132
|
+
|
133
|
+
# @!visibility private
|
134
|
+
def hass_enum(config, prefix = nil, valid_set = nil)
|
135
|
+
prefix = "#{prefix}_" if prefix
|
136
|
+
|
137
|
+
return unless datatype == :enum
|
138
|
+
|
139
|
+
modes = range
|
140
|
+
modes &= valid_set if valid_set
|
141
|
+
config[:"#{prefix}modes"] = modes
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def publish_hass_component(device: nil, discovery_prefix: nil, object_id: nil, **kwargs)
|
147
|
+
discovery_prefix ||= self.device.home_assistant_discovery_prefix
|
148
|
+
device = self.device.home_assistant_device.merge(device || {}) if self.device.home_assistant_device
|
149
|
+
|
150
|
+
object_id ||= "#{node.id}_#{id}"
|
151
|
+
kwargs[:name] ||= "#{node.name} #{name}"
|
152
|
+
kwargs[:device] = device
|
153
|
+
kwargs[:discovery_prefix] ||= discovery_prefix
|
154
|
+
kwargs[:unique_id] ||= "#{self.device.id}_#{object_id}"
|
155
|
+
self.device.base_hass_config(kwargs)
|
156
|
+
if published?
|
157
|
+
self.device.mqtt.publish_hass_component(object_id, **kwargs)
|
158
|
+
else
|
159
|
+
pending_hass_registrations << [object_id, kwargs]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def pending_hass_registrations
|
164
|
+
@pending_hass_registrations ||= []
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
Property.prepend(HomeAssistant::Property)
|
169
|
+
end
|
170
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mqtt-homie-homeassistant
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cody Cutrer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-01-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: homie-mqtt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mqtt-homeassistant
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
description:
|
56
|
+
email: cody@cutrer.com'
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- lib/mqtt-homie-homeassistant.rb
|
62
|
+
- lib/mqtt/homie/home_assistant/device.rb
|
63
|
+
- lib/mqtt/homie/home_assistant/node.rb
|
64
|
+
- lib/mqtt/homie/home_assistant/property.rb
|
65
|
+
- lib/mqtt/homie/home_assistant/version.rb
|
66
|
+
homepage: https://github.com/ccutrer/ruby-mqtt-homie-homeassistant
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata:
|
70
|
+
rubygems_mfa_required: 'true'
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '2.5'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.5.11
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Library for publishing device auto-discovery configuration for Homie devices
|
90
|
+
to Home Assistant as well.
|
91
|
+
test_files: []
|