rzwaveway 0.0.4 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +5 -0
- data/README.md +27 -4
- data/lib/rzwaveway/command_class.rb +29 -0
- data/lib/rzwaveway/command_classes/battery.rb +33 -0
- data/lib/rzwaveway/command_classes/sensor_binary.rb +33 -0
- data/lib/rzwaveway/command_classes/switch_binary.rb +37 -0
- data/lib/rzwaveway/command_classes/switch_multi_level.rb +37 -0
- data/lib/rzwaveway/command_classes/wake_up.rb +41 -0
- data/lib/rzwaveway/command_classes.rb +32 -69
- data/lib/rzwaveway/events.rb +28 -3
- data/lib/rzwaveway/extensions/fibaro_smoke_sensor.rb +11 -0
- data/lib/rzwaveway/extensions/ssa_siren_strobe_alarm.rb +53 -0
- data/lib/rzwaveway/extensions.rb +2 -0
- data/lib/rzwaveway/version.rb +3 -0
- data/lib/rzwaveway/zwave_device.rb +118 -22
- data/lib/rzwaveway/zway.rb +159 -47
- data/lib/rzwaveway.rb +2 -1
- data/rzwaveway.gemspec +12 -6
- data/spec/command_classes/battery_spec.rb +44 -0
- data/spec/command_classes/sensor_binary_spec.rb +42 -0
- data/spec/command_classes/switch_binary_spec.rb +42 -0
- data/spec/command_classes/switch_multi_level_spec.rb +42 -0
- data/spec/command_classes/wake_up_spec.rb +45 -0
- data/spec/data/battery_get.txt +73 -0
- data/spec/data/sensor_level.txt +24 -0
- data/spec/data/switch_multi_level_get.txt +24 -0
- data/spec/data/wake_up.txt +45 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/zwave_device_spec.rb +217 -0
- data/spec/zway_spec.rb +31 -0
- metadata +77 -7
@@ -2,59 +2,142 @@ require 'json'
|
|
2
2
|
|
3
3
|
module RZWaveWay
|
4
4
|
class ZWaveDevice
|
5
|
+
include CommandClass
|
5
6
|
include CommandClasses
|
6
7
|
|
8
|
+
attr_reader :name
|
7
9
|
attr_reader :id
|
10
|
+
attr_reader :last_contact_time
|
11
|
+
attr_accessor :contact_frequency
|
8
12
|
|
9
13
|
def initialize(id, data)
|
10
14
|
@id = id
|
11
|
-
|
12
|
-
$log.info "Created ZWaveDevice with id='#{id}'"
|
15
|
+
initialize_from data
|
16
|
+
$log.info "Created ZWaveDevice with name='#{name}' (id='#{id}')"
|
13
17
|
end
|
14
18
|
|
15
|
-
def
|
16
|
-
|
17
|
-
data['instances']['0']['commandClasses'].each do |cc_id, sub_tree|
|
18
|
-
cc_classes[cc_id.to_i] = CommandClass.new(cc_id.to_i, sub_tree)
|
19
|
-
end
|
20
|
-
cc_classes
|
19
|
+
def contacts_controller_periodically?
|
20
|
+
support_commandclass? CommandClass::WAKEUP
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
def next_contact_time
|
24
|
+
@last_contact_time + (@contact_frequency * (1 + @missed_contact_count) * 1.1)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_json
|
28
|
+
attributes = {
|
29
|
+
'name' => @name,
|
30
|
+
'deviceId' => @id,
|
31
|
+
# TODO remove these obsolete attributes (kept for backward compatibility)
|
32
|
+
'lastSleepTime' => @last_contact_time,
|
33
|
+
'lastWakeUpTime' => @last_contact_time,
|
34
|
+
'wakeUpInterval' => @contact_frequency
|
35
|
+
# ---
|
36
|
+
# 'lastContactTime' => @last_contact_time,
|
37
|
+
# 'contactFrequency' => @contact_frequency,
|
38
|
+
# 'properties' => @properties.to_json
|
39
|
+
}
|
40
|
+
attributes.to_json
|
29
41
|
end
|
30
42
|
|
31
|
-
def support_commandclass?
|
32
|
-
@command_classes.has_key?
|
43
|
+
def support_commandclass?(command_class_id)
|
44
|
+
@command_classes.has_key? command_class_id
|
33
45
|
end
|
34
46
|
|
35
47
|
def process updates
|
36
48
|
events = []
|
37
|
-
updates_per_commandclass =
|
49
|
+
updates_per_commandclass = group_per_commandclass updates
|
38
50
|
updates_per_commandclass.each do |cc, values|
|
39
51
|
if @command_classes.has_key? cc
|
40
|
-
event = @command_classes[cc].process(values
|
52
|
+
event = @command_classes[cc].process(values)
|
41
53
|
events << event if event
|
42
54
|
else
|
43
55
|
$log.warn "Could not find command class: '#{cc}'"
|
44
56
|
end
|
45
57
|
end
|
58
|
+
process_device_data(updates, events)
|
46
59
|
events
|
47
60
|
end
|
48
61
|
|
49
62
|
def process_alive_check
|
50
|
-
if
|
51
|
-
|
63
|
+
return if @dead
|
64
|
+
if @contact_frequency > 0
|
65
|
+
current_time = Time.now.to_i
|
66
|
+
delta = current_time - next_contact_time
|
67
|
+
if delta > 0
|
68
|
+
count = ((current_time - @last_contact_time) / @contact_frequency).to_i
|
69
|
+
if count > MAXIMUM_MISSED_CONTACT
|
70
|
+
@dead = true
|
71
|
+
DeadEvent.new(@id)
|
72
|
+
elsif count > @missed_contact_count
|
73
|
+
@missed_contact_count = count
|
74
|
+
NotAliveEvent.new(@id, delta, count)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def notify_contacted(time)
|
81
|
+
if time.to_i > @last_contact_time
|
82
|
+
@dead = false
|
83
|
+
@last_contact_time = time.to_i
|
84
|
+
@missed_contact_count = 0
|
85
|
+
true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_property(name, value, updateTime)
|
90
|
+
@properties[name] = [value, updateTime]
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_property(name)
|
94
|
+
@properties[name].dup
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_property(name, value, updateTime)
|
98
|
+
if @properties.has_key?(name)
|
99
|
+
property = @properties[name]
|
100
|
+
if property[0] != value || property[1] < updateTime
|
101
|
+
property[0] = value
|
102
|
+
property[1] = updateTime
|
103
|
+
true
|
104
|
+
end
|
52
105
|
end
|
53
106
|
end
|
54
107
|
|
55
108
|
private
|
56
109
|
|
110
|
+
MAXIMUM_MISSED_CONTACT = 10
|
111
|
+
|
112
|
+
def create_commandclasses_from data
|
113
|
+
cc_classes = {}
|
114
|
+
data['instances']['0']['commandClasses'].each do |id, sub_tree|
|
115
|
+
cc_id = id.to_i
|
116
|
+
cc_class = CommandClasses::Factory.instance.instantiate(cc_id, sub_tree, self)
|
117
|
+
cc_classes[cc_id] = cc_class
|
118
|
+
cc_class_name = cc_class.class.name.split('::').last
|
119
|
+
(class << self; self end).send(:define_method, cc_class_name) { cc_class } unless cc_class_name == 'Dummy'
|
120
|
+
end
|
121
|
+
cc_classes
|
122
|
+
end
|
123
|
+
|
124
|
+
def initialize_from data
|
125
|
+
@name = find('data.givenName.value', data)
|
126
|
+
last_contact_times = [
|
127
|
+
find('data.lastReceived.updateTime', data),
|
128
|
+
find('data.lastSend.updateTime', data)
|
129
|
+
]
|
130
|
+
@last_contact_time = last_contact_times.max
|
131
|
+
|
132
|
+
@dead = false
|
133
|
+
@missed_contact_count = 0
|
134
|
+
@contact_frequency = 0
|
135
|
+
@properties = {}
|
136
|
+
@command_classes = create_commandclasses_from data
|
137
|
+
end
|
138
|
+
|
57
139
|
def group_per_commandclass updates
|
140
|
+
other_updates = {}
|
58
141
|
updates_per_commandclass = {}
|
59
142
|
updates.each do | key, value |
|
60
143
|
match_data = key.match(/\Ainstances.0.commandClasses.(\d+)./)
|
@@ -63,10 +146,23 @@ module RZWaveWay
|
|
63
146
|
updates_per_commandclass[command_class] = {} unless updates_per_commandclass.has_key?(command_class)
|
64
147
|
updates_per_commandclass[command_class][match_data.post_match] = value
|
65
148
|
else
|
66
|
-
|
149
|
+
other_updates[key] = value
|
67
150
|
end
|
68
151
|
end
|
152
|
+
updates.clear
|
153
|
+
updates.merge!(other_updates)
|
69
154
|
updates_per_commandclass
|
70
155
|
end
|
156
|
+
|
157
|
+
def process_device_data(updates, events)
|
158
|
+
times = []
|
159
|
+
updates.each do | key, value |
|
160
|
+
if key == 'data.lastReceived' || key == 'data.lastSend'
|
161
|
+
times << value['updateTime']
|
162
|
+
end
|
163
|
+
end
|
164
|
+
time = times.max
|
165
|
+
events << AliveEvent.new(@id, time) if notify_contacted(time)
|
166
|
+
end
|
71
167
|
end
|
72
|
-
end
|
168
|
+
end
|
data/lib/rzwaveway/zway.rb
CHANGED
@@ -1,38 +1,121 @@
|
|
1
|
-
require '
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'faraday'
|
2
4
|
require 'log4r'
|
3
5
|
require 'json'
|
4
6
|
|
5
7
|
module RZWaveWay
|
6
|
-
|
7
|
-
|
8
|
+
class ZWay
|
9
|
+
include Singleton
|
8
10
|
include Log4r
|
9
11
|
|
10
|
-
|
12
|
+
attr_reader :devices
|
11
13
|
|
12
|
-
def
|
14
|
+
def initialize
|
13
15
|
$log = Logger.new 'RZWaveWay'
|
16
|
+
formatter = PatternFormatter.new(:pattern => "[%l] %d - %m")
|
14
17
|
outputter = Outputter.stdout
|
15
|
-
outputter.formatter =
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
outputter.formatter = formatter
|
19
|
+
outputter.level = Log4r::INFO
|
20
|
+
file_outputter = RollingFileOutputter.new('file', filename: 'rzwaveway.log', maxsize: 1048576, trunc: 86400)
|
21
|
+
file_outputter.formatter = formatter
|
22
|
+
file_outputter.level = Log4r::DEBUG
|
23
|
+
$log.outputters = [Outputter.stdout, file_outputter]
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(device_id, command_class, command_class_function, argument = nil)
|
27
|
+
raise "No device with id '#{device_id}'" unless @devices.has_key?(device_id)
|
28
|
+
raise "Device with id '#{device_id}' does not support command class '#{command_class}'" unless @devices[device_id].support_commandclass?(command_class)
|
29
|
+
function_name = command_class_function.to_s
|
30
|
+
run_zway_function(device_id, command_class, function_name, argument)
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_extension(name, device_id)
|
34
|
+
device = @devices[device_id.to_i]
|
35
|
+
raise ArgumentError, "No device with id '#{device_id}'" unless device
|
36
|
+
clazz = qualified_const_get "RZWaveWay::Extensions::#{name}"
|
37
|
+
clazz.new(device)
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup(hostname, *adapter_params)
|
41
|
+
adapter_params = :httpclient if adapter_params.compact.empty?
|
21
42
|
@base_uri="http://#{hostname}:8083"
|
43
|
+
@connection = Faraday.new {|faraday| faraday.adapter *adapter_params}
|
22
44
|
end
|
23
45
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
def start
|
47
|
+
@devices = {}
|
48
|
+
@event_handlers = {}
|
49
|
+
@update_time = '0'
|
50
|
+
loop do
|
51
|
+
results = get_zway_data_tree_updates
|
52
|
+
if results.has_key?('devices')
|
53
|
+
results['devices'].each {|device_id,device_data_tree| create_device(device_id.to_i, device_data_tree)}
|
54
|
+
break
|
55
|
+
else
|
56
|
+
sleep 1.0
|
57
|
+
$log.warn 'No devices found at start-up, retrying'
|
58
|
+
end
|
29
59
|
end
|
30
|
-
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_event(event, &listener)
|
63
|
+
@event_handlers[event] = listener
|
31
64
|
end
|
32
65
|
|
33
66
|
def process_events
|
67
|
+
check_devices
|
68
|
+
updates = get_zway_data_tree_updates
|
69
|
+
events = devices_process updates
|
70
|
+
check_not_alive_devices(events)
|
71
|
+
deliver_to_handlers(events)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
DATA_TREE_BASE_PATH='/ZWaveAPI/Data/'
|
77
|
+
RUN_BASE_PATH='/ZWaveAPI/Run/'
|
78
|
+
|
79
|
+
def check_devices
|
80
|
+
@devices.values.each do |device|
|
81
|
+
unless device.contacts_controller_periodically?
|
82
|
+
current_time = Time.now.to_i
|
83
|
+
# TODO ensure last_contact_time is set in the device initializer
|
84
|
+
if (current_time % 10 == 0) && (current_time > device.next_contact_time - 60)
|
85
|
+
run_zway_no_operation device.id
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_not_alive_devices(events)
|
92
|
+
@devices.values.each do |device|
|
93
|
+
event = device.process_alive_check
|
94
|
+
events << event if event
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_device(device_id, device_data_tree)
|
99
|
+
if device_id > 1
|
100
|
+
device = ZWaveDevice.new(device_id, device_data_tree)
|
101
|
+
device.contact_frequency = 300 unless device.contacts_controller_periodically?
|
102
|
+
@devices[device_id] = device
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def deliver_to_handlers events
|
107
|
+
events.each do |event|
|
108
|
+
handler = @event_handlers[event.class]
|
109
|
+
if handler
|
110
|
+
handler.call(event)
|
111
|
+
else
|
112
|
+
$log.warn "No event handler for #{event.class}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def devices_process updates
|
34
118
|
events = []
|
35
|
-
updates = http_post_request
|
36
119
|
updates_per_device = group_per_device updates
|
37
120
|
updates_per_device.each do | id, updates |
|
38
121
|
if @devices[id]
|
@@ -42,16 +125,6 @@ module RZWaveWay
|
|
42
125
|
$log.warn "Could not find device with id '#{id}'"
|
43
126
|
end
|
44
127
|
end
|
45
|
-
alive_events = check_not_alive_devices
|
46
|
-
events += alive_events unless alive_events.empty?
|
47
|
-
events.each do |event|
|
48
|
-
handler = @event_handlers[event.class]
|
49
|
-
if handler
|
50
|
-
handler.call(event)
|
51
|
-
else
|
52
|
-
$log.warn "no handler for #{event.class}"
|
53
|
-
end
|
54
|
-
end
|
55
128
|
events
|
56
129
|
end
|
57
130
|
|
@@ -64,36 +137,75 @@ module RZWaveWay
|
|
64
137
|
updates_per_device[device_id] = {} unless(updates_per_device.has_key?(device_id))
|
65
138
|
updates_per_device[device_id][match_data.post_match] = value
|
66
139
|
else
|
67
|
-
$log.
|
140
|
+
$log.debug "No device group match for key='#{key}'"
|
68
141
|
end
|
69
142
|
end
|
70
143
|
updates_per_device
|
71
144
|
end
|
72
145
|
|
73
|
-
def
|
74
|
-
|
75
|
-
@
|
76
|
-
|
77
|
-
|
146
|
+
def get_zway_data_tree_updates
|
147
|
+
results = {}
|
148
|
+
url = @base_uri + DATA_TREE_BASE_PATH + "#{@update_time}"
|
149
|
+
begin
|
150
|
+
response = @connection.get(url)
|
151
|
+
if response.success?
|
152
|
+
results = JSON.parse response.body
|
153
|
+
@update_time = results.delete('updateTime')
|
154
|
+
else
|
155
|
+
$log.error(response.reason)
|
156
|
+
end
|
157
|
+
rescue StandardError => e
|
158
|
+
$log.error("Failed to communicate with ZWay HTTP server: #{e}")
|
78
159
|
end
|
79
|
-
|
160
|
+
results
|
80
161
|
end
|
81
162
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
@update_time = results.delete("updateTime")
|
163
|
+
def qualified_const_get(str)
|
164
|
+
path = str.to_s.split('::')
|
165
|
+
from_root = path[0].empty?
|
166
|
+
if from_root
|
167
|
+
from_root = []
|
168
|
+
path = path[1..-1]
|
89
169
|
else
|
90
|
-
|
170
|
+
start_ns = ((Class === self)||(Module === self)) ? self : self.class
|
171
|
+
from_root = start_ns.to_s.split('::')
|
91
172
|
end
|
92
|
-
|
173
|
+
until from_root.empty?
|
174
|
+
begin
|
175
|
+
return (from_root+path).inject(Object) { |ns,name| ns.const_get(name) }
|
176
|
+
rescue NameError
|
177
|
+
from_root.delete_at(-1)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
path.inject(Object) { |ns,name| ns.const_get(name) }
|
93
181
|
end
|
94
182
|
|
95
|
-
def
|
96
|
-
|
183
|
+
def run_zway_function(device_id, command_class, function_name, argument)
|
184
|
+
command_path = "devices[#{device_id}].instances[0].commandClasses[#{command_class}]."
|
185
|
+
if argument
|
186
|
+
command_path += "#{function_name}(#{argument})"
|
187
|
+
else
|
188
|
+
command_path += "#{function_name}()"
|
189
|
+
end
|
190
|
+
run_zway command_path
|
191
|
+
end
|
192
|
+
|
193
|
+
def run_zway_no_operation device_id
|
194
|
+
run_zway "devices[#{device_id}].SendNoOperation()"
|
195
|
+
end
|
196
|
+
|
197
|
+
def run_zway command_path
|
198
|
+
begin
|
199
|
+
uri = URI.encode(@base_uri + RUN_BASE_PATH + command_path, '[]')
|
200
|
+
response = @connection.get(uri)
|
201
|
+
unless response.success?
|
202
|
+
$log.error(response.status)
|
203
|
+
$log.error(response.body)
|
204
|
+
end
|
205
|
+
rescue StandardError => e
|
206
|
+
$log.error("Failed to communicate with ZWay HTTP server: #{e}")
|
207
|
+
$log.error(e.backtrace)
|
208
|
+
end
|
97
209
|
end
|
98
210
|
end
|
99
|
-
end
|
211
|
+
end
|
data/lib/rzwaveway.rb
CHANGED
data/rzwaveway.gemspec
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
require 'rzwaveway/version'
|
3
|
+
|
1
4
|
Gem::Specification.new do |s|
|
2
|
-
s.name =
|
3
|
-
s.version =
|
4
|
-
s.authors = [
|
5
|
+
s.name = 'rzwaveway'
|
6
|
+
s.version = RZWaveWay::VERSION
|
7
|
+
s.authors = ['Vincent Touchard']
|
5
8
|
s.date = %q{2014-02-18}
|
6
9
|
s.summary = 'ZWave API for ZWay'
|
7
10
|
s.description = 'A Ruby API to use the Razberry ZWave ZWay interface'
|
8
|
-
s.email = '
|
11
|
+
s.email = 'touchardv@yahoo.com'
|
9
12
|
s.homepage = 'https://github.com/touchardv/rzwaveway'
|
10
13
|
s.files = `git ls-files`.split("\n")
|
11
14
|
s.has_rdoc = false
|
12
15
|
|
13
16
|
dependencies = [
|
14
|
-
[:runtime,
|
15
|
-
[:runtime,
|
17
|
+
[:runtime, 'log4r', '~> 1.1.10'],
|
18
|
+
[:runtime, 'faraday'],
|
19
|
+
[:runtime, 'httpclient'],
|
20
|
+
[:development, 'bundler', '~> 1.0'],
|
21
|
+
[:development, 'rspec', '~> 3.0.0']
|
16
22
|
]
|
17
23
|
|
18
24
|
dependencies.each do |type, name, version|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RZWaveWay
|
4
|
+
module CommandClasses
|
5
|
+
describe Battery do
|
6
|
+
let(:device) { ZWaveDevice.new(create_id, create_device_data) }
|
7
|
+
let(:command_class) do
|
8
|
+
Battery.new(
|
9
|
+
{'data' => { 'last' => {
|
10
|
+
'value' => 60,
|
11
|
+
'type' => 'int',
|
12
|
+
'updateTime' => 1409681662
|
13
|
+
}}}, device)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#new' do
|
17
|
+
it 'stores interesting properties' do
|
18
|
+
command_class
|
19
|
+
expect(device.get_property(:battery_level)).to eq [60, 1409681662]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#process' do
|
24
|
+
it 'does nothing when it processes no updates' do
|
25
|
+
expect(command_class.process({})).to be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns a battery event' do
|
29
|
+
updates = {
|
30
|
+
'data.last' => {
|
31
|
+
'value' => 50,
|
32
|
+
'type' => 'int',
|
33
|
+
'updateTime' => 1409681762
|
34
|
+
}}
|
35
|
+
event = command_class.process(updates)
|
36
|
+
expect(event.class).to be RZWaveWay::BatteryValueEvent
|
37
|
+
expect(event.value).to eq 50
|
38
|
+
expect(event.device_id).to eq device.id
|
39
|
+
expect(event.time).to eq 1409681762
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RZWaveWay
|
4
|
+
module CommandClasses
|
5
|
+
describe SensorBinary do
|
6
|
+
let(:device) { ZWaveDevice.new(create_id, create_device_data) }
|
7
|
+
let(:command_class) do
|
8
|
+
SensorBinary.new(
|
9
|
+
{'data' => { '1' => { 'level' => {
|
10
|
+
'value' => false,
|
11
|
+
'updateTime' => 1405102560
|
12
|
+
}}}}, device)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#new' do
|
16
|
+
it 'stores interesting properties' do
|
17
|
+
command_class
|
18
|
+
expect(device.get_property(:level)).to eq [false, 1405102560]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#process' do
|
23
|
+
it 'does nothing when it processes no updates' do
|
24
|
+
expect(command_class.process({})).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns a level event' do
|
28
|
+
updates = {
|
29
|
+
'data.1' => { 'level' => {
|
30
|
+
'value' => true,
|
31
|
+
'updateTime' => 1405102860
|
32
|
+
}}}
|
33
|
+
event = command_class.process(updates)
|
34
|
+
expect(event.class).to be RZWaveWay::LevelEvent
|
35
|
+
expect(event.level).to eq true
|
36
|
+
expect(event.device_id).to eq device.id
|
37
|
+
expect(event.time).to eq 1405102860
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RZWaveWay
|
4
|
+
module CommandClasses
|
5
|
+
describe SwitchBinary do
|
6
|
+
let(:device) { ZWaveDevice.new(create_id, create_device_data) }
|
7
|
+
let(:command_class) do
|
8
|
+
SwitchBinary.new(
|
9
|
+
{'data' => { 'level' => {
|
10
|
+
'value' => false,
|
11
|
+
'updateTime' => 1405102560
|
12
|
+
}}}, device)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#it caches the level' do
|
16
|
+
it 'stores interesting properties' do
|
17
|
+
command_class
|
18
|
+
expect(device.get_property(:level)).to eq [false, 1405102560]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#process' do
|
23
|
+
it 'does nothing when it processes no updates' do
|
24
|
+
expect(command_class.process({})).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns a multi level event' do
|
28
|
+
updates = {
|
29
|
+
'data.level' => {
|
30
|
+
'value' => true,
|
31
|
+
'updateTime' => 1405102860
|
32
|
+
}}
|
33
|
+
event = command_class.process(updates)
|
34
|
+
expect(event.class).to be RZWaveWay::LevelEvent
|
35
|
+
expect(event.level).to eq true
|
36
|
+
expect(event.device_id).to eq device.id
|
37
|
+
expect(event.time).to eq 1405102860
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RZWaveWay
|
4
|
+
module CommandClasses
|
5
|
+
describe SwitchMultiLevel do
|
6
|
+
let(:device) { ZWaveDevice.new(create_id, create_device_data) }
|
7
|
+
let(:command_class) do
|
8
|
+
SwitchMultiLevel.new(
|
9
|
+
{'data' => { 'level' => {
|
10
|
+
'value' => 33,
|
11
|
+
'updateTime' => 1405102560
|
12
|
+
}}}, device)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#new' do
|
16
|
+
it 'stores interesting properties' do
|
17
|
+
command_class
|
18
|
+
expect(device.get_property(:level)).to eq [33, 1405102560]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#process' do
|
23
|
+
it 'does nothing when it processes no updates' do
|
24
|
+
expect(command_class.process({})).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns a multi level event' do
|
28
|
+
updates = {
|
29
|
+
'data.level' => {
|
30
|
+
'value' => 66,
|
31
|
+
'updateTime' => 1405102860
|
32
|
+
}}
|
33
|
+
event = command_class.process(updates)
|
34
|
+
expect(event.class).to be RZWaveWay::MultiLevelEvent
|
35
|
+
expect(event.level).to eq 66
|
36
|
+
expect(event.device_id).to eq device.id
|
37
|
+
expect(event.time).to eq 1405102860
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|