mqtt-homie 0.1.0 → 0.1.1

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: 6e92a85d38e5d824f9e40a7afe8ec0bbe51f4a7a483d01fa66ee7765812b5939
4
- data.tar.gz: 56356ede9f137963ff41f26a7cc046e0223c647cec0da5703a57da165f4337ac
3
+ metadata.gz: e325ebb1aedaf50aef04bd62e84b8cb2107561f87f8aa71a9f5f037cc4d5a006
4
+ data.tar.gz: 4847fede7e1dcb105f4a869073c0a6a807cbcc0c6927059cf6465ed0f7794831
5
5
  SHA512:
6
- metadata.gz: d019acaf6ec7b635bfc50eb53be9d185b40a80926f74b36dbfbd8770ed2325d480cf27e05bf6eaeb5f37007c97ad60d4b5385e27aaba4657074409b9fd21e7ad
7
- data.tar.gz: cb4c85f3c03ea59b28a7f9ecda820a7d03a3f6f1e77cc8e2abde98daabcd21f0dea0bbdda3c9d76939c03b5e4fd80546762928a49de2e586465f62576670b69b
6
+ metadata.gz: 4b705eadfb0777b0f79f15a32965419bbfcfe2695dba3101c44a61680e38a9e58bbe634673f37f347213608099f7b13e8841e592135918899255c50bef4a0604
7
+ data.tar.gz: dd9f77fc45d35d87a3d514cc18ecef672f84fb94b8a7b218e5f52dddbf2132be2f87028338cf26446bc0a45a44d6e924484cb540483bafa83c1181e2c1983859
@@ -1,41 +1,45 @@
1
- PATH
2
- remote: .
3
- specs:
4
- mqtt-homie (0.1.0)
5
- mqtt (~> 0.5)
6
- sys-uname (~> 1.0)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- diff-lcs (1.3)
12
- ffi (1.11.1-x64-mingw32)
13
- mqtt (0.5.0)
14
- rake (10.5.0)
15
- rspec (3.8.0)
16
- rspec-core (~> 3.8.0)
17
- rspec-expectations (~> 3.8.0)
18
- rspec-mocks (~> 3.8.0)
19
- rspec-core (3.8.1)
20
- rspec-support (~> 3.8.0)
21
- rspec-expectations (3.8.4)
22
- diff-lcs (>= 1.2.0, < 2.0)
23
- rspec-support (~> 3.8.0)
24
- rspec-mocks (3.8.1)
25
- diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.8.0)
27
- rspec-support (3.8.2)
28
- sys-uname (1.0.4)
29
- ffi (>= 1.0.0)
30
-
31
- PLATFORMS
32
- x64-mingw32
33
-
34
- DEPENDENCIES
35
- bundler (~> 2.0)
36
- mqtt-homie!
37
- rake (~> 10.0)
38
- rspec (~> 3.0)
39
-
40
- BUNDLED WITH
41
- 2.0.2
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mqtt-homie (0.1.0)
5
+ macaddr (~> 1.1)
6
+ mqtt (~> 0.5)
7
+ sys-uname (~> 1.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ diff-lcs (1.3)
13
+ ffi (1.11.1-x64-mingw32)
14
+ macaddr (1.7.2)
15
+ systemu (~> 2.6.5)
16
+ mqtt (0.5.0)
17
+ rake (10.5.0)
18
+ rspec (3.8.0)
19
+ rspec-core (~> 3.8.0)
20
+ rspec-expectations (~> 3.8.0)
21
+ rspec-mocks (~> 3.8.0)
22
+ rspec-core (3.8.1)
23
+ rspec-support (~> 3.8.0)
24
+ rspec-expectations (3.8.4)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.8.0)
27
+ rspec-mocks (3.8.1)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.8.0)
30
+ rspec-support (3.8.2)
31
+ sys-uname (1.0.4)
32
+ ffi (>= 1.0.0)
33
+ systemu (2.6.5)
34
+
35
+ PLATFORMS
36
+ x64-mingw32
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 2.0)
40
+ mqtt-homie!
41
+ rake (~> 10.0)
42
+ rspec (~> 3.0)
43
+
44
+ BUNDLED WITH
45
+ 2.0.2
data/README.md CHANGED
@@ -28,13 +28,11 @@ require 'rubygems'
28
28
  require 'mqtt/homie'
29
29
 
30
30
  # Set up a device, with a node and properties
31
- device = MQTT::Homie.device_builder(id: 'device', name: 'Device'
32
- localip: '192.168.1.1',
33
- mac: '80:1f:02:cc:15:dd'
34
- ).node(id: "gate", name: "Front gate", type: "Gate")
35
- .property(id: "state", name: "Gate state", enum: [:open, :closed, :opening, :closing], value: :closed)
36
- .property(id: "position", name: "Gate position", datatype: :integer, unit: "%", value: 0)
37
- .property(id: "command", name: "Send gate command", settable: true, enum: [:open, :close]).build
31
+ device = MQTT::Homie.device_builder(id: 'device', name: 'Device')
32
+ .node(id: "gate", name: "Front gate", type: "Gate")
33
+ .property(id: "state", name: "Gate state", enum: [:open, :closed, :opening, :closing], value: :closed)
34
+ .property(id: "position", name: "Gate position", datatype: :integer, unit: "%", value: 0)
35
+ .property(id: "command", name: "Send gate command", settable: true, enum: [:open, :close]).build
38
36
 
39
37
  # Create a client and connect to a MQTT broker
40
38
  client = MQTT::Homie::Client.new(device: device, host: 'localhost')
@@ -1,27 +1,29 @@
1
- require "mqtt"
2
- require "mqtt/homie/version"
3
-
4
- module MQTT
5
- module Homie
6
- class Error < StandardError; end
7
-
8
- class << self
9
- attr_accessor :logger
10
-
11
- def debug(message)
12
- logger.debug(message) if logger
13
- end
14
-
15
- def device_builder(options = {})
16
- MQTT::Homie::DeviceBuilder.new(options)
17
- end
18
- end
19
- end
20
- end
21
-
22
- require "mqtt/homie/homie_object"
23
- require "mqtt/homie/property"
24
- require "mqtt/homie/node"
25
- require "mqtt/homie/device"
26
- require "mqtt/homie/client"
27
- require "mqtt/homie/device_builder"
1
+ require "mqtt"
2
+ require "mqtt/homie/version"
3
+
4
+ module MQTT
5
+ module Homie
6
+ class Error < StandardError; end
7
+
8
+ class << self
9
+ attr_accessor :logger
10
+
11
+ def debug(message)
12
+ logger.debug(message) if logger
13
+ end
14
+
15
+ def device_builder(options = {})
16
+ MQTT::Homie::DeviceBuilder.new(options)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ require "mqtt/homie/homie_attribute"
23
+ require "mqtt/homie/homie_object"
24
+ require "mqtt/homie/network"
25
+ require "mqtt/homie/property"
26
+ require "mqtt/homie/node"
27
+ require "mqtt/homie/device"
28
+ require "mqtt/homie/client"
29
+ require "mqtt/homie/device_builder"
@@ -12,8 +12,17 @@ module MQTT
12
12
  @device = options[:device]
13
13
  @host = options[:host]
14
14
  @root_topic = options[:root_topic] || DEFAULT_ROOT_TOPIC
15
+
15
16
  raise "device required" unless @device
16
17
 
18
+ # next version of homie doesn't use stats or firmware details
19
+ @use_stats = true
20
+ if options[:develop]
21
+ @device.use_stats = false
22
+ @device.use_fw = false
23
+ @use_stats = false
24
+ end
25
+
17
26
  # observe all node properties so we can publish values when they change
18
27
  @device.nodes.each do |node|
19
28
  node.properties.each do |property|
@@ -30,12 +39,12 @@ module MQTT
30
39
  @client.connect
31
40
 
32
41
  publish(@device, topic)
33
- publish_statistics
42
+ publish_statistics if @use_stats
34
43
 
35
44
  @threads = []
36
45
 
37
46
  # run a thread to publish statistics
38
- @threads << Thread.new { run_statistics }
47
+ @threads << Thread.new { run_statistics } if @use_stats
39
48
 
40
49
  # run a thread to listen for settings
41
50
  @threads << Thread.new { run_set_listener }
@@ -106,7 +115,9 @@ module MQTT
106
115
  def run_statistics
107
116
  while !Thread.current[:done]
108
117
  publish_statistics
109
- sleep @device.interval
118
+
119
+ # halve interval, if we miss a notification then we will be marked as offline
120
+ sleep @device.stats.interval / 2
110
121
  end
111
122
  debug("statistics thread exiting")
112
123
  end
@@ -121,7 +132,7 @@ module MQTT
121
132
  end
122
133
 
123
134
  def publish_statistics
124
- publish(@device.statistics, topic + "/$stats")
135
+ publish(@device.stats, topic + "/$stats")
125
136
  end
126
137
 
127
138
  def publish_property_value(property)
@@ -1,31 +1,71 @@
1
1
  require "sys/uname"
2
+ require "socket"
2
3
 
3
4
  module MQTT
4
5
  module Homie
5
6
  class Device < HomieObject
7
+ class << self
8
+ include Network
9
+ end
10
+
6
11
  HOMIE_VERSION = "3.0.1"
7
12
  DEFAULT_STAT_REFRESH = 60 # seconds
8
- DEFAULT_IMPLEMENTATION = "mqtt-homie"
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
9
53
 
10
- attr_reader :nodes, :id, :mac, :fw_name, :fw_version, :name, :implementation, :interval
11
- attr_accessor :state
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
12
61
 
13
62
  def initialize(options = {})
14
63
  super(options)
15
- @name = options[:name]
16
- @start_time = Time.now
17
- @interval = set(options, :interval, default: DEFAULT_STAT_REFRESH)
18
- @nodes = set(options, :nodes, data_type: Array, default: [])
19
- @state = :init
20
- @localip = set(options, :localip, default: default_localip)
21
- @mac = set(options, :mac, default: default_mac)
22
- @implementation = set(options, :implementation, default: DEFAULT_IMPLEMENTATION)
23
- @fw_name = set(options, :fw_name, default: default_fw_name)
24
- @fw_version = set(options, :fw_version, default: default_fw_version)
25
- end
64
+ @stats = Statistics.new(options)
65
+ @fw = Firmware.new(subhash(options, "fw_"))
26
66
 
27
- def topic
28
- @id
67
+ @use_stats = options.include?(:use_stats) ? options[:use_stats] : true
68
+ @use_fw = options.include?(:use_fw) ? options[:use_fw] : true
29
69
  end
30
70
 
31
71
  def node(id)
@@ -35,17 +75,15 @@ module MQTT
35
75
  # device attributes must be sent when connection to broker is established or re-established
36
76
  # homie/device_id/
37
77
  def homie_attributes
38
- data = {
78
+ data = super.merge({
39
79
  "$homie" => HOMIE_VERSION,
40
- "$name" => @name,
41
- "$localip" => @localip,
42
- "$mac" => @mac,
43
- "$fw/name" => @fw_name || "mqtt-homie",
44
- "$fw/version" => @fw_version || MQTT::Homie::VERSION,
45
- "$nodes" => @nodes.collect { |i| i.id }.join(","),
46
- "$implementation" => @implementation,
47
- "$state" => @state.to_s,
48
- }
80
+ })
81
+
82
+ data.merge!({
83
+ "$fw/name" => @fw.name,
84
+ "$fw/version" => @fw.version,
85
+ }) if @use_fw
86
+
49
87
  @nodes.each do |node|
50
88
  node.homie_attributes.each do |k, v|
51
89
  data[node.topic + "/" + k] = v
@@ -54,43 +92,16 @@ module MQTT
54
92
  data
55
93
  end
56
94
 
57
- # statistics should be sent every INTERVAL seconds
58
- # homie/device_id/$stats
59
- def statistics
60
- {
61
- "uptime" => (Time.now - @start_time).to_i,
62
- #"signal" => 100, # TODO wifi signal strength
63
- #"cputemp" => 0,
64
- #"cpuload" => stats.load_average.one_minute,
65
- #"battery" => 100,
66
- #"freeheap" => stats.memory.free,
67
- #"supply" => 5,
68
- "interval" => @interval * 2,
69
- }
70
- end
71
-
72
- def update(time, node)
73
- # node value updated
74
- end
75
-
76
- def default_localip
77
- nil # TODO
78
- end
79
-
80
- def default_mac
81
- nil # TODO
82
- end
83
-
84
- def default_fw_name
85
- uname.sysname rescue uname.caption rescue "Unknown"
86
- end
87
-
88
- def default_fw_version
89
- uname.release rescue uname.build_number rescue "Unknown"
90
- end
95
+ private
91
96
 
92
- def uname
93
- @uname ||= Sys::Uname.uname
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
94
105
  end
95
106
  end
96
107
  end
@@ -0,0 +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
@@ -3,37 +3,15 @@ require "observer"
3
3
  module MQTT
4
4
  module Homie
5
5
  class HomieObject
6
- attr_reader :id
6
+ include HomieAttribute
7
7
 
8
8
  def initialize(options = {})
9
- @id = set(options, :id, required: true)
10
- raise "invalid id" unless valid_id?
9
+ homie_attr_init(options)
11
10
  end
12
11
 
13
12
  def topic
14
13
  @id
15
14
  end
16
-
17
- def homie_attributes
18
- data = {}
19
- end
20
-
21
- private
22
-
23
- def valid_id?
24
- @id && @id.kind_of?(String) && @id.match(/^[-a-z0-9]+$/) && !@id.start_with?("-")
25
- end
26
-
27
- def set(options = {}, name, default: nil, required: false, enum: nil, data_type: nil)
28
- value = options.include?(name) ? options[name] : default
29
- raise "#{name} is required for #{object_type} #{@id}" if required && value.nil?
30
- raise "expected #{name} to be a #{data_type} for #{object_type} #{@id}" if data_type && !value.kind_of?(data_type)
31
- value
32
- end
33
-
34
- def object_type
35
- self.class.name.split("::").last
36
- end
37
15
  end
38
16
  end
39
17
  end
@@ -0,0 +1,42 @@
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.find { |i| i[:default] }
17
+ end
18
+
19
+ def interfaces
20
+ @interfaces ||= begin
21
+ interfaces = {}
22
+ found = false
23
+ Socket.getifaddrs.each do |ifaddr|
24
+ ifname = ifaddr.name
25
+ data = interfaces[ifname] ||= { addresses: [] }
26
+ next unless addr = ifaddr.addr
27
+ data[:addresses].push addr if (addr.ipv4? || addr.ipv6?) && usable_address?(addr)
28
+ data[:hwaddr] = $1 if addr.inspect.match(/hwaddr=([0-9a-fA-F:]+)/) # doesn't work on windows
29
+ data[:default] = true unless found
30
+ data[:name] = ifname
31
+ found = true
32
+ end
33
+ interfaces
34
+ end
35
+ end
36
+
37
+ def usable_address?(addr)
38
+ !(addr.ipv4_loopback? || addr.ipv6_loopback? || addr.ipv4_multicast? || addr.ipv6_linklocal?)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,25 +1,17 @@
1
1
  module MQTT
2
2
  module Homie
3
3
  class Node < HomieObject
4
- attr_reader :name, :properties
5
-
6
- def initialize(options = {})
7
- super(options)
8
- @name = set(options, :name, required: true)
9
- @type = set(options, :type, required: true)
10
- @properties = set(options, :properties, required: true, data_type: Array)
11
- end
4
+ homie_id
5
+ homie_attr :name, required: true
6
+ homie_attr :type, required: true
7
+ homie_attr :properties, datatype: Array, required: true, immutable: true
12
8
 
13
9
  def property(id)
14
10
  @properties.find { |i| i.id == id }
15
11
  end
16
12
 
17
13
  def homie_attributes
18
- data = {
19
- "$name" => @name,
20
- "$type" => @type,
21
- "$properties" => @properties.collect { |i| i.id }.join(","),
22
- }
14
+ data = super
23
15
 
24
16
  @properties.each do |p|
25
17
  p.homie_attributes.each do |k, v|
@@ -7,31 +7,32 @@ module MQTT
7
7
 
8
8
  DATA_TYPES = [:integer, :float, :boolean, :string, :enum, :color]
9
9
 
10
- attr_reader :id, :name, :settable, :datatype, :unit, :retained, :format
10
+ homie_id
11
+ homie_attr :name, default: ""
12
+ homie_attr :settable, default: false, datatype: :boolean
13
+ homie_attr :retained, default: true, datatype: :boolean
14
+ homie_attr :datatype, default: :string, enum: DATA_TYPES, datatype: Symbol
15
+ homie_attr :unit, default: ""
16
+ homie_attr :format, required: lambda { |i| [:enum, :color].include?(i.datatype) }
17
+
11
18
  attr_reader :value
12
19
 
13
20
  def initialize(options = {})
14
- super(options)
15
-
16
21
  options = options.dup
17
22
 
18
23
  # enum shortcut
19
24
  if enum = options.delete(:enum)
20
25
  options[:datatype] = :enum
21
- options[:format] = enum.collect { |i| i.to_s }.join(',')
26
+ options[:format] = enum.collect { |i| i.to_s }.join(",")
22
27
  end
23
28
 
24
- @name = set(options, :name, default: "")
25
- @settable = !!set(options, :settable, default: false)
26
- @retained = !!set(options, :retained, default: true)
27
- @datatype = set(options, :datatype, default: :string, enum: DATA_TYPES).to_sym
28
- @unit = set(options, :unit, default: "")
29
- @format = set(options, :format, required: [:enum, :color].include?(@datatype))
29
+ super(options)
30
+
30
31
  @value = options[:value]
31
32
  end
32
33
 
33
34
  def value=(value)
34
- # TODO: check value conforms to expected datatype and format
35
+ # TODO: check value conforms to expected datatype and format?
35
36
  if value != @value
36
37
  @value = value
37
38
  changed
@@ -42,18 +43,6 @@ module MQTT
42
43
  def settable?
43
44
  @settable
44
45
  end
45
-
46
- def homie_attributes
47
- data = {
48
- "$name" => @name,
49
- "$settable" => @settable,
50
- "$datatype" => @datatype,
51
- "$unit" => @unit,
52
- "$format" => @format,
53
- "$retained" => @retained,
54
- }
55
- data
56
- end
57
46
  end
58
47
  end
59
48
  end
@@ -1,5 +1,5 @@
1
- module MQTT
2
- module Homie
3
- VERSION = "0.1.0"
4
- end
5
- end
1
+ module MQTT
2
+ module Homie
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -1,36 +1,37 @@
1
- lib = File.expand_path("lib", __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "mqtt/homie/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "mqtt-homie"
7
- spec.version = MQTT::Homie::VERSION
8
- spec.authors = ["Andrew Williams"]
9
- spec.email = ["sobakasu@gmail.com"]
10
-
11
- spec.summary = %q{A ruby interface for creating a device conforming to the MQTT Homie convention.}
12
- spec.homepage = "https://github.com/sobakasu/mqtt-homie"
13
- spec.license = "MIT"
14
-
15
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
-
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/sobakasu/mqtt-homie"
19
- spec.metadata["changelog_uri"] = "https://github.com/sobakasu/mqtt-homie/CHANGELOG"
20
-
21
- # Specify which files should be added to the gem when it is released.
22
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
- spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
- end
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 2.0"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency "rspec", "~> 3.0"
33
-
34
- spec.add_dependency "mqtt", "~> 0.5"
35
- spec.add_dependency "sys-uname", "~> 1.0"
36
- end
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "mqtt/homie/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "mqtt-homie"
7
+ spec.version = MQTT::Homie::VERSION
8
+ spec.authors = ["Andrew Williams"]
9
+ spec.email = ["sobakasu@gmail.com"]
10
+
11
+ spec.summary = %q{A ruby interface for creating a device conforming to the MQTT Homie convention.}
12
+ spec.homepage = "https://github.com/sobakasu/mqtt-homie"
13
+ spec.license = "MIT"
14
+
15
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/sobakasu/mqtt-homie"
19
+ spec.metadata["changelog_uri"] = "https://github.com/sobakasu/mqtt-homie/CHANGELOG"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 2.0"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec", "~> 3.0"
33
+
34
+ spec.add_dependency "mqtt", "~> 0.5"
35
+ spec.add_dependency "sys-uname", "~> 1.0"
36
+ spec.add_dependency "macaddr", "~> 1.1"
37
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mqtt-homie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Williams
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-27 00:00:00.000000000 Z
11
+ date: 2019-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: macaddr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.1'
83
97
  description:
84
98
  email:
85
99
  - sobakasu@gmail.com
@@ -102,7 +116,9 @@ files:
102
116
  - lib/mqtt/homie/client.rb
103
117
  - lib/mqtt/homie/device.rb
104
118
  - lib/mqtt/homie/device_builder.rb
119
+ - lib/mqtt/homie/homie_attribute.rb
105
120
  - lib/mqtt/homie/homie_object.rb
121
+ - lib/mqtt/homie/network.rb
106
122
  - lib/mqtt/homie/node.rb
107
123
  - lib/mqtt/homie/property.rb
108
124
  - lib/mqtt/homie/version.rb