mqtt-homie 0.1.0 → 0.1.1

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: 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