mqtt-homie 0.1.1 → 0.1.2
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 +4 -4
- data/.gitignore +2 -0
- data/README.md +67 -65
- data/lib/mqtt/homie/client.rb +173 -173
- data/lib/mqtt/homie/device.rb +108 -108
- data/lib/mqtt/homie/device_builder.rb +38 -38
- data/lib/mqtt/homie/homie_attribute.rb +125 -125
- data/lib/mqtt/homie/homie_object.rb +17 -17
- data/lib/mqtt/homie/network.rb +43 -42
- data/lib/mqtt/homie/node.rb +26 -26
- data/lib/mqtt/homie/property.rb +48 -48
- data/lib/mqtt/homie/version.rb +5 -5
- data/lib/mqtt/homie.rb +29 -29
- data/mqtt-homie.gemspec +36 -37
- metadata +25 -41
- data/Gemfile.lock +0 -45
data/lib/mqtt/homie/device.rb
CHANGED
@@ -1,108 +1,108 @@
|
|
1
|
-
require "sys/uname"
|
2
|
-
require "socket"
|
3
|
-
|
4
|
-
module MQTT
|
5
|
-
module Homie
|
6
|
-
class Device < HomieObject
|
7
|
-
class << self
|
8
|
-
include Network
|
9
|
-
end
|
10
|
-
|
11
|
-
HOMIE_VERSION = "3.0.1"
|
12
|
-
DEFAULT_STAT_REFRESH = 60 # seconds
|
13
|
-
DEFAULT_IMPLEMENTATION = "mqtt-homie-#{VERSION}"
|
14
|
-
|
15
|
-
class Firmware < HomieObject
|
16
|
-
class << self
|
17
|
-
def default_fw_name
|
18
|
-
uname.sysname rescue uname.caption rescue "Unknown"
|
19
|
-
end
|
20
|
-
|
21
|
-
def default_fw_version
|
22
|
-
uname.release rescue uname.build_number rescue "Unknown"
|
23
|
-
end
|
24
|
-
|
25
|
-
def uname
|
26
|
-
@uname ||= Sys::Uname.uname
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
homie_attr :name, default: default_fw_name, required: true
|
31
|
-
homie_attr :version, default: default_fw_version, required: true
|
32
|
-
end
|
33
|
-
|
34
|
-
# statistics should be sent every interval seconds
|
35
|
-
# homie/device_id/$stats
|
36
|
-
class Statistics < HomieObject
|
37
|
-
homie_attr :interval, required: true, default: 60
|
38
|
-
homie_attr :boot_time, default: lambda { |i| Time.now }, hidden: true
|
39
|
-
homie_attr :signal, datatype: Integer
|
40
|
-
homie_attr :cputemp, datatype: Integer
|
41
|
-
homie_attr :cpuload, datatype: Float
|
42
|
-
homie_attr :battery, datatype: Integer
|
43
|
-
homie_attr :freeheap, datatype: Integer
|
44
|
-
homie_attr :supply, datatype: Float
|
45
|
-
|
46
|
-
def homie_attributes
|
47
|
-
super.merge("uptime" => (Time.now - @boot_time).to_i)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
attr_reader :fw, :stats
|
52
|
-
attr_accessor :use_stats, :use_fw
|
53
|
-
|
54
|
-
homie_id
|
55
|
-
homie_attr :name, required: true
|
56
|
-
homie_attr :state, default: :init, required: true
|
57
|
-
homie_attr :nodes, datatype: Array, default: [], immutable: true
|
58
|
-
homie_attr :localip, default: default_localip, required: true
|
59
|
-
homie_attr :mac, default: default_mac, required: true
|
60
|
-
homie_attr :implementation, default: DEFAULT_IMPLEMENTATION
|
61
|
-
|
62
|
-
def initialize(options = {})
|
63
|
-
super(options)
|
64
|
-
@stats = Statistics.new(options)
|
65
|
-
@fw = Firmware.new(subhash(options, "fw_"))
|
66
|
-
|
67
|
-
@use_stats = options.include?(:use_stats) ? options[:use_stats] : true
|
68
|
-
@use_fw = options.include?(:use_fw) ? options[:use_fw] : true
|
69
|
-
end
|
70
|
-
|
71
|
-
def node(id)
|
72
|
-
@nodes.find { |i| i.id == id }
|
73
|
-
end
|
74
|
-
|
75
|
-
# device attributes must be sent when connection to broker is established or re-established
|
76
|
-
# homie/device_id/
|
77
|
-
def homie_attributes
|
78
|
-
data = super.merge({
|
79
|
-
"$homie" => HOMIE_VERSION,
|
80
|
-
})
|
81
|
-
|
82
|
-
data.merge!({
|
83
|
-
"$fw/name" => @fw.name,
|
84
|
-
"$fw/version" => @fw.version,
|
85
|
-
}) if @use_fw
|
86
|
-
|
87
|
-
@nodes.each do |node|
|
88
|
-
node.homie_attributes.each do |k, v|
|
89
|
-
data[node.topic + "/" + k] = v
|
90
|
-
end
|
91
|
-
end
|
92
|
-
data
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def subhash(data, prefix)
|
98
|
-
result = {}
|
99
|
-
data.each do |key, value|
|
100
|
-
next unless key.to_s.start_with?(prefix)
|
101
|
-
key = key.to_s.sub(/^#{prefix}/, "")
|
102
|
-
result[key.to_sym] = value
|
103
|
-
end
|
104
|
-
result
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
1
|
+
require "sys/uname"
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
module MQTT
|
5
|
+
module Homie
|
6
|
+
class Device < HomieObject
|
7
|
+
class << self
|
8
|
+
include Network
|
9
|
+
end
|
10
|
+
|
11
|
+
HOMIE_VERSION = "3.0.1"
|
12
|
+
DEFAULT_STAT_REFRESH = 60 # seconds
|
13
|
+
DEFAULT_IMPLEMENTATION = "mqtt-homie-#{VERSION}"
|
14
|
+
|
15
|
+
class Firmware < HomieObject
|
16
|
+
class << self
|
17
|
+
def default_fw_name
|
18
|
+
uname.sysname rescue uname.caption rescue "Unknown"
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_fw_version
|
22
|
+
uname.release rescue uname.build_number rescue "Unknown"
|
23
|
+
end
|
24
|
+
|
25
|
+
def uname
|
26
|
+
@uname ||= Sys::Uname.uname
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
homie_attr :name, default: default_fw_name, required: true
|
31
|
+
homie_attr :version, default: default_fw_version, required: true
|
32
|
+
end
|
33
|
+
|
34
|
+
# statistics should be sent every interval seconds
|
35
|
+
# homie/device_id/$stats
|
36
|
+
class Statistics < HomieObject
|
37
|
+
homie_attr :interval, required: true, default: 60
|
38
|
+
homie_attr :boot_time, default: lambda { |i| Time.now }, hidden: true
|
39
|
+
homie_attr :signal, datatype: Integer
|
40
|
+
homie_attr :cputemp, datatype: Integer
|
41
|
+
homie_attr :cpuload, datatype: Float
|
42
|
+
homie_attr :battery, datatype: Integer
|
43
|
+
homie_attr :freeheap, datatype: Integer
|
44
|
+
homie_attr :supply, datatype: Float
|
45
|
+
|
46
|
+
def homie_attributes
|
47
|
+
super.merge("uptime" => (Time.now - @boot_time).to_i)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :fw, :stats
|
52
|
+
attr_accessor :use_stats, :use_fw
|
53
|
+
|
54
|
+
homie_id
|
55
|
+
homie_attr :name, required: true
|
56
|
+
homie_attr :state, default: :init, required: true
|
57
|
+
homie_attr :nodes, datatype: Array, default: [], immutable: true
|
58
|
+
homie_attr :localip, default: default_localip, required: true
|
59
|
+
homie_attr :mac, default: default_mac, required: true
|
60
|
+
homie_attr :implementation, default: DEFAULT_IMPLEMENTATION
|
61
|
+
|
62
|
+
def initialize(options = {})
|
63
|
+
super(options)
|
64
|
+
@stats = Statistics.new(options)
|
65
|
+
@fw = Firmware.new(subhash(options, "fw_"))
|
66
|
+
|
67
|
+
@use_stats = options.include?(:use_stats) ? options[:use_stats] : true
|
68
|
+
@use_fw = options.include?(:use_fw) ? options[:use_fw] : true
|
69
|
+
end
|
70
|
+
|
71
|
+
def node(id)
|
72
|
+
@nodes.find { |i| i.id == id }
|
73
|
+
end
|
74
|
+
|
75
|
+
# device attributes must be sent when connection to broker is established or re-established
|
76
|
+
# homie/device_id/
|
77
|
+
def homie_attributes
|
78
|
+
data = super.merge({
|
79
|
+
"$homie" => HOMIE_VERSION,
|
80
|
+
})
|
81
|
+
|
82
|
+
data.merge!({
|
83
|
+
"$fw/name" => @fw.name,
|
84
|
+
"$fw/version" => @fw.version,
|
85
|
+
}) if @use_fw
|
86
|
+
|
87
|
+
@nodes.each do |node|
|
88
|
+
node.homie_attributes.each do |k, v|
|
89
|
+
data[node.topic + "/" + k] = v
|
90
|
+
end
|
91
|
+
end
|
92
|
+
data
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def subhash(data, prefix)
|
98
|
+
result = {}
|
99
|
+
data.each do |key, value|
|
100
|
+
next unless key.to_s.start_with?(prefix)
|
101
|
+
key = key.to_s.sub(/^#{prefix}/, "")
|
102
|
+
result[key.to_sym] = value
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -1,38 +1,38 @@
|
|
1
|
-
module MQTT
|
2
|
-
module Homie
|
3
|
-
class DeviceBuilder
|
4
|
-
def initialize(options = {})
|
5
|
-
@nodes = []
|
6
|
-
@device_options = options
|
7
|
-
end
|
8
|
-
|
9
|
-
# create device and return it
|
10
|
-
def build
|
11
|
-
build_node if @node_data
|
12
|
-
MQTT::Homie::Device.new(@device_options.merge(nodes: @nodes))
|
13
|
-
end
|
14
|
-
|
15
|
-
def node(options = {})
|
16
|
-
raise "node key/value list expected" unless options.kind_of?(Hash)
|
17
|
-
build_node if @node_data
|
18
|
-
@node_data = options
|
19
|
-
@properties = []
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def property(options = {})
|
24
|
-
raise "property key/value list expected" unless options.kind_of?(Hash)
|
25
|
-
@properties << MQTT::Homie::Property.new(options)
|
26
|
-
self
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def build_node
|
32
|
-
@nodes << MQTT::Homie::Node.new(@node_data.merge(properties: @properties))
|
33
|
-
@node_data = nil
|
34
|
-
@propertes = nil
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
1
|
+
module MQTT
|
2
|
+
module Homie
|
3
|
+
class DeviceBuilder
|
4
|
+
def initialize(options = {})
|
5
|
+
@nodes = []
|
6
|
+
@device_options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
# create device and return it
|
10
|
+
def build
|
11
|
+
build_node if @node_data
|
12
|
+
MQTT::Homie::Device.new(@device_options.merge(nodes: @nodes))
|
13
|
+
end
|
14
|
+
|
15
|
+
def node(options = {})
|
16
|
+
raise "node key/value list expected" unless options.kind_of?(Hash)
|
17
|
+
build_node if @node_data
|
18
|
+
@node_data = options
|
19
|
+
@properties = []
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def property(options = {})
|
24
|
+
raise "property key/value list expected" unless options.kind_of?(Hash)
|
25
|
+
@properties << MQTT::Homie::Property.new(options)
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def build_node
|
32
|
+
@nodes << MQTT::Homie::Node.new(@node_data.merge(properties: @properties))
|
33
|
+
@node_data = nil
|
34
|
+
@propertes = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,125 +1,125 @@
|
|
1
|
-
module MQTT
|
2
|
-
module Homie
|
3
|
-
module HomieAttribute
|
4
|
-
def self.included(base)
|
5
|
-
base.send :include, InstanceMethods
|
6
|
-
base.extend ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
def homie_attr(name, options = {})
|
11
|
-
# define accessors
|
12
|
-
attr_reader name
|
13
|
-
|
14
|
-
unless options[:immutable]
|
15
|
-
define_method("#{name}=") { |value| homie_attr_set(name, value) }
|
16
|
-
end
|
17
|
-
|
18
|
-
# record attribute data
|
19
|
-
@homie_attribute_list ||= []
|
20
|
-
@homie_attribute_list << [name.to_sym, options]
|
21
|
-
end
|
22
|
-
|
23
|
-
def homie_id
|
24
|
-
homie_attr :id, required: true, validate: lambda { |i| valid_id?(i) }, immutable: true, hidden: true
|
25
|
-
end
|
26
|
-
|
27
|
-
def homie_has_id?
|
28
|
-
!!homie_attr_list.detect { |i| i[0] == :id }
|
29
|
-
end
|
30
|
-
|
31
|
-
def homie_attr_list
|
32
|
-
@homie_attribute_list || []
|
33
|
-
end
|
34
|
-
|
35
|
-
def homie_attr_options(name)
|
36
|
-
data = homie_attr_list.find { |i| i[0] == name } || []
|
37
|
-
data[1] || {}
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
module InstanceMethods
|
42
|
-
|
43
|
-
# initialize all homie attributes from the given hash
|
44
|
-
def homie_attr_init(data = {})
|
45
|
-
self.class.homie_attr_list.each do |name, options|
|
46
|
-
#puts "name: #{name}, default: #{options[:default]}, options: #{options.inspect}"
|
47
|
-
value = data.include?(name) ? data[name] : options[:default]
|
48
|
-
value = value.call(self) if value.kind_of?(Proc)
|
49
|
-
homie_attr_set(name, value)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# set attribute without validation
|
54
|
-
def homie_attr_set!(name, value)
|
55
|
-
instance_variable_set("@#{name}", value)
|
56
|
-
end
|
57
|
-
|
58
|
-
# set attribute with validation
|
59
|
-
def homie_attr_set(name, value)
|
60
|
-
homie_attr_validate(name, value)
|
61
|
-
homie_attr_set!(name, value)
|
62
|
-
end
|
63
|
-
|
64
|
-
def homie_attributes
|
65
|
-
data = {}
|
66
|
-
# if this object has an id, it needs a $ attribute prefix.
|
67
|
-
# otherwise assume it is a hierarchical attribute like $stats/* or $fw/*
|
68
|
-
attrib_prefix = self.class.homie_has_id? ? "$" : ""
|
69
|
-
self.class.homie_attr_list.each do |name, options|
|
70
|
-
next if options[:hidden]
|
71
|
-
key = options[:topic] || (attrib_prefix + name.to_s)
|
72
|
-
value = instance_variable_get("@#{name}")
|
73
|
-
next if value == nil
|
74
|
-
data[key] = value.kind_of?(Array) ? value.collect { |i| i.id }.join(",") : value
|
75
|
-
end
|
76
|
-
data
|
77
|
-
end
|
78
|
-
|
79
|
-
# attribute validation
|
80
|
-
def homie_attr_validate(name, value)
|
81
|
-
options = self.class.homie_attr_options(name)
|
82
|
-
|
83
|
-
if value.nil?
|
84
|
-
required = options[:required]
|
85
|
-
required = required.call(self) if required.kind_of?(Proc)
|
86
|
-
raise "#{name} is required for #{object_type} #{@id}" if required
|
87
|
-
end
|
88
|
-
|
89
|
-
datatype = options[:datatype]
|
90
|
-
if datatype && !value.nil? && !datatype_match?(datatype, value)
|
91
|
-
raise "expected #{name} to be a #{datatype} for #{object_type} #{@id}"
|
92
|
-
end
|
93
|
-
|
94
|
-
enum = options[:enum]
|
95
|
-
if enum.kind_of?(Array) && !value.nil? && !enum.include?(value.to_sym)
|
96
|
-
raise "expected #{name} (#{value}) to be one of #{enum.join(",")}"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
private
|
101
|
-
|
102
|
-
def object_type
|
103
|
-
self.class.name.split("::").last
|
104
|
-
end
|
105
|
-
|
106
|
-
def valid_id?(id)
|
107
|
-
id && id.kind_of?(String) && id.match(/^[-a-z0-9]+$/) && !id.start_with?("-")
|
108
|
-
end
|
109
|
-
|
110
|
-
def datatype_match?(datatype, value)
|
111
|
-
return value.kind_of?(datatype) if datatype.kind_of?(Class)
|
112
|
-
case datatype
|
113
|
-
when :boolean
|
114
|
-
return value == true || value == false
|
115
|
-
else
|
116
|
-
raise "unhandled datatype '#{datatype}'"
|
117
|
-
end
|
118
|
-
false
|
119
|
-
end
|
120
|
-
|
121
|
-
#@settable = !!set(options, :settable, default: false)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
1
|
+
module MQTT
|
2
|
+
module Homie
|
3
|
+
module HomieAttribute
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, InstanceMethods
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def homie_attr(name, options = {})
|
11
|
+
# define accessors
|
12
|
+
attr_reader name
|
13
|
+
|
14
|
+
unless options[:immutable]
|
15
|
+
define_method("#{name}=") { |value| homie_attr_set(name, value) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# record attribute data
|
19
|
+
@homie_attribute_list ||= []
|
20
|
+
@homie_attribute_list << [name.to_sym, options]
|
21
|
+
end
|
22
|
+
|
23
|
+
def homie_id
|
24
|
+
homie_attr :id, required: true, validate: lambda { |i| valid_id?(i) }, immutable: true, hidden: true
|
25
|
+
end
|
26
|
+
|
27
|
+
def homie_has_id?
|
28
|
+
!!homie_attr_list.detect { |i| i[0] == :id }
|
29
|
+
end
|
30
|
+
|
31
|
+
def homie_attr_list
|
32
|
+
@homie_attribute_list || []
|
33
|
+
end
|
34
|
+
|
35
|
+
def homie_attr_options(name)
|
36
|
+
data = homie_attr_list.find { |i| i[0] == name } || []
|
37
|
+
data[1] || {}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module InstanceMethods
|
42
|
+
|
43
|
+
# initialize all homie attributes from the given hash
|
44
|
+
def homie_attr_init(data = {})
|
45
|
+
self.class.homie_attr_list.each do |name, options|
|
46
|
+
#puts "name: #{name}, default: #{options[:default]}, options: #{options.inspect}"
|
47
|
+
value = data.include?(name) ? data[name] : options[:default]
|
48
|
+
value = value.call(self) if value.kind_of?(Proc)
|
49
|
+
homie_attr_set(name, value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# set attribute without validation
|
54
|
+
def homie_attr_set!(name, value)
|
55
|
+
instance_variable_set("@#{name}", value)
|
56
|
+
end
|
57
|
+
|
58
|
+
# set attribute with validation
|
59
|
+
def homie_attr_set(name, value)
|
60
|
+
homie_attr_validate(name, value)
|
61
|
+
homie_attr_set!(name, value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def homie_attributes
|
65
|
+
data = {}
|
66
|
+
# if this object has an id, it needs a $ attribute prefix.
|
67
|
+
# otherwise assume it is a hierarchical attribute like $stats/* or $fw/*
|
68
|
+
attrib_prefix = self.class.homie_has_id? ? "$" : ""
|
69
|
+
self.class.homie_attr_list.each do |name, options|
|
70
|
+
next if options[:hidden]
|
71
|
+
key = options[:topic] || (attrib_prefix + name.to_s)
|
72
|
+
value = instance_variable_get("@#{name}")
|
73
|
+
next if value == nil
|
74
|
+
data[key] = value.kind_of?(Array) ? value.collect { |i| i.id }.join(",") : value
|
75
|
+
end
|
76
|
+
data
|
77
|
+
end
|
78
|
+
|
79
|
+
# attribute validation
|
80
|
+
def homie_attr_validate(name, value)
|
81
|
+
options = self.class.homie_attr_options(name)
|
82
|
+
|
83
|
+
if value.nil?
|
84
|
+
required = options[:required]
|
85
|
+
required = required.call(self) if required.kind_of?(Proc)
|
86
|
+
raise "#{name} is required for #{object_type} #{@id}" if required
|
87
|
+
end
|
88
|
+
|
89
|
+
datatype = options[:datatype]
|
90
|
+
if datatype && !value.nil? && !datatype_match?(datatype, value)
|
91
|
+
raise "expected #{name} to be a #{datatype} for #{object_type} #{@id}"
|
92
|
+
end
|
93
|
+
|
94
|
+
enum = options[:enum]
|
95
|
+
if enum.kind_of?(Array) && !value.nil? && !enum.include?(value.to_sym)
|
96
|
+
raise "expected #{name} (#{value}) to be one of #{enum.join(",")}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def object_type
|
103
|
+
self.class.name.split("::").last
|
104
|
+
end
|
105
|
+
|
106
|
+
def valid_id?(id)
|
107
|
+
id && id.kind_of?(String) && id.match(/^[-a-z0-9]+$/) && !id.start_with?("-")
|
108
|
+
end
|
109
|
+
|
110
|
+
def datatype_match?(datatype, value)
|
111
|
+
return value.kind_of?(datatype) if datatype.kind_of?(Class)
|
112
|
+
case datatype
|
113
|
+
when :boolean
|
114
|
+
return value == true || value == false
|
115
|
+
else
|
116
|
+
raise "unhandled datatype '#{datatype}'"
|
117
|
+
end
|
118
|
+
false
|
119
|
+
end
|
120
|
+
|
121
|
+
#@settable = !!set(options, :settable, default: false)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
|
-
require "observer"
|
2
|
-
|
3
|
-
module MQTT
|
4
|
-
module Homie
|
5
|
-
class HomieObject
|
6
|
-
include HomieAttribute
|
7
|
-
|
8
|
-
def initialize(options = {})
|
9
|
-
homie_attr_init(options)
|
10
|
-
end
|
11
|
-
|
12
|
-
def topic
|
13
|
-
@id
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
1
|
+
require "observer"
|
2
|
+
|
3
|
+
module MQTT
|
4
|
+
module Homie
|
5
|
+
class HomieObject
|
6
|
+
include HomieAttribute
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
homie_attr_init(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def topic
|
13
|
+
@id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/mqtt/homie/network.rb
CHANGED
@@ -1,42 +1,43 @@
|
|
1
|
-
require "macaddr"
|
2
|
-
|
3
|
-
module MQTT
|
4
|
-
module Homie
|
5
|
-
module Network
|
6
|
-
def default_localip
|
7
|
-
addr = default_interface[:addresses][0] if default_interface
|
8
|
-
addr ? addr.ip_address : nil
|
9
|
-
end
|
10
|
-
|
11
|
-
def default_mac
|
12
|
-
(default_interface ? default_interface[:hwaddr] : nil) || Mac.addr
|
13
|
-
end
|
14
|
-
|
15
|
-
def default_interface
|
16
|
-
@default_interface ||= interfaces.values.
|
17
|
-
end
|
18
|
-
|
19
|
-
def interfaces
|
20
|
-
@interfaces ||= begin
|
21
|
-
interfaces = {}
|
22
|
-
|
23
|
-
|
24
|
-
ifname
|
25
|
-
|
26
|
-
|
27
|
-
data[
|
28
|
-
data[:
|
29
|
-
data[:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
1
|
+
require "macaddr"
|
2
|
+
|
3
|
+
module MQTT
|
4
|
+
module Homie
|
5
|
+
module Network
|
6
|
+
def default_localip
|
7
|
+
addr = default_interface[:addresses][0] if default_interface
|
8
|
+
addr ? addr.ip_address : nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_mac
|
12
|
+
(default_interface ? default_interface[:hwaddr] : nil) || Mac.addr
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_interface
|
16
|
+
@default_interface ||= interfaces.values.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def interfaces
|
20
|
+
@interfaces ||= begin
|
21
|
+
interfaces = {}
|
22
|
+
Socket.getifaddrs.each do |ifaddr|
|
23
|
+
ifname = ifaddr.name
|
24
|
+
next if ifname == "lo"
|
25
|
+
next unless addr = ifaddr.addr
|
26
|
+
|
27
|
+
data = interfaces[ifname] ||= { addresses: [] }
|
28
|
+
data[:name] = ifname
|
29
|
+
data[:hwaddr] = $1 if addr.inspect.match(/hwaddr=([0-9a-fA-F:]+)/) # doesn't work on windows
|
30
|
+
if (addr.ipv4? || addr.ipv6?) && usable_address?(addr)
|
31
|
+
data[:addresses].push addr
|
32
|
+
end
|
33
|
+
end
|
34
|
+
interfaces
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def usable_address?(addr)
|
39
|
+
!(addr.ipv4_loopback? || addr.ipv6_loopback? || addr.ipv4_multicast? || addr.ipv6_linklocal?)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|