rzwaveway 0.0.4 → 0.0.6
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.
- 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
data/.gitignore
CHANGED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -3,20 +3,43 @@ rzwaveway
|
|
3
3
|
|
4
4
|
A Ruby library for communicating with the ZWave protocol stack from ZWay, running on the Raspberry Pi "razberry" add-on card (see http://razberry.z-wave.me/).
|
5
5
|
|
6
|
-
##
|
6
|
+
## Usage examples
|
7
|
+
|
8
|
+
### Initialize the framework
|
7
9
|
```
|
8
10
|
require 'rzwaveway'
|
9
11
|
|
10
|
-
z_way = RZWaveWay::ZWay.
|
11
|
-
|
12
|
-
|
12
|
+
z_way = RZWaveWay::ZWay.instance
|
13
|
+
z_way.setup('192.168.1.123')
|
14
|
+
z_way.start
|
15
|
+
```
|
16
|
+
|
17
|
+
### List the devices
|
18
|
+
```
|
19
|
+
z_way.devices.each do |device_id,device|
|
13
20
|
puts device.build_json
|
14
21
|
end
|
22
|
+
```
|
15
23
|
|
24
|
+
### Listen to events
|
25
|
+
```
|
16
26
|
z_way.on_event(RZWaveWay::AliveEvent) {|event| puts "A device woke up" }
|
17
27
|
z_way.on_event(RZWaveWay::LevelEvent) {|event| puts "A device got triggered" }
|
18
28
|
while true do
|
19
29
|
sleep 5
|
20
30
|
z_way.process_events
|
21
31
|
end
|
32
|
+
```
|
33
|
+
|
34
|
+
### Switch on/off a device
|
35
|
+
```
|
36
|
+
z_way.execute(4, RZWaveWay::CommandClass::SWITCH_BINARY, :Set, 1)
|
37
|
+
z_way.execute(4, RZWaveWay::CommandClass::SWITCH_BINARY, :Set, 0)
|
38
|
+
```
|
39
|
+
or
|
40
|
+
|
41
|
+
```
|
42
|
+
switch = z_way.devices[4]
|
43
|
+
switch.SwitchBinary.set(1)
|
44
|
+
switch.SwitchBinary.set(0)
|
22
45
|
```
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClass
|
3
|
+
BASIC = 32
|
4
|
+
SWITCH_BINARY = 37
|
5
|
+
SWITCH_MULTI_LEVEL = 38
|
6
|
+
SENSOR_BINARY = 48
|
7
|
+
SENSOR_MULTI_LEVEL = 49
|
8
|
+
CONFIGURATION = 112
|
9
|
+
ALARM = 113
|
10
|
+
MANUFACTURER_SPECIFIC = 114
|
11
|
+
BATTERY = 128
|
12
|
+
WAKEUP = 132
|
13
|
+
ASSOCIATION = 133
|
14
|
+
VERSION = 134
|
15
|
+
ALARM_SENSOR = 156
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def find(name, data)
|
20
|
+
parts = name.split '.'
|
21
|
+
result = data
|
22
|
+
parts.each do | part |
|
23
|
+
raise "Could not find part '#{part}' in '#{name}'" unless result.has_key? part
|
24
|
+
result = result[part]
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClasses
|
3
|
+
class Battery
|
4
|
+
include CommandClass
|
5
|
+
|
6
|
+
def initialize(data, device)
|
7
|
+
@device = device
|
8
|
+
@device.add_property(:battery_level,
|
9
|
+
find('data.last.value', data),
|
10
|
+
find('data.last.updateTime', data))
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(updates)
|
14
|
+
if updates.keys.include?('data.last')
|
15
|
+
data = updates['data.last']
|
16
|
+
value = data['value']
|
17
|
+
updateTime = data['updateTime']
|
18
|
+
if @device.update_property(:battery_level, value, updateTime)
|
19
|
+
return BatteryValueEvent.new(@device.id, updateTime, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def battery_value
|
25
|
+
@device.get_property(:battery_level)[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
RZWaveWay::ZWay.instance.execute(@device.id, BATTERY, :Get)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClasses
|
3
|
+
class SensorBinary
|
4
|
+
include CommandClass
|
5
|
+
|
6
|
+
def initialize(data, device)
|
7
|
+
@device = device
|
8
|
+
@device.add_property(:level,
|
9
|
+
find('data.1.level.value', data),
|
10
|
+
find('data.1.level.updateTime', data))
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(updates)
|
14
|
+
if updates.keys.include?('data.1')
|
15
|
+
data = updates['data.1']['level']
|
16
|
+
value = data['value']
|
17
|
+
updateTime = data['updateTime']
|
18
|
+
if @device.update_property(:level, value, updateTime)
|
19
|
+
return LevelEvent.new(@device.id, updateTime, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def level
|
25
|
+
@device.get_property(:level)[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
RZWaveWay::ZWay.instance.execute(@device.id, SENSOR_BINARY, :Get)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClasses
|
3
|
+
class SwitchBinary
|
4
|
+
include CommandClass
|
5
|
+
|
6
|
+
def initialize(data, device)
|
7
|
+
@device = device
|
8
|
+
@device.add_property(:level,
|
9
|
+
find('data.level.value', data),
|
10
|
+
find('data.level.updateTime', data))
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(updates)
|
14
|
+
if updates.keys.include?('data.level')
|
15
|
+
data = updates['data.level']
|
16
|
+
value = data['value']
|
17
|
+
updateTime = data['updateTime']
|
18
|
+
if @device.update_property(:level, value, updateTime)
|
19
|
+
return LevelEvent.new(@device.id, updateTime, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def level
|
25
|
+
@device.get_property(:level)[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
RZWaveWay::ZWay.instance.execute(@device.id, SWITCH_BINARY, :Get)
|
30
|
+
end
|
31
|
+
|
32
|
+
def set(value)
|
33
|
+
RZWaveWay::ZWay.instance.execute(@device.id, SWITCH_BINARY, :Set, value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClasses
|
3
|
+
class SwitchMultiLevel
|
4
|
+
include CommandClass
|
5
|
+
|
6
|
+
def initialize(data, device)
|
7
|
+
@device = device
|
8
|
+
@device.add_property(:level,
|
9
|
+
find('data.level.value', data),
|
10
|
+
find('data.level.updateTime', data))
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(updates)
|
14
|
+
if updates.keys.include?('data.level')
|
15
|
+
data = updates['data.level']
|
16
|
+
value = data['value']
|
17
|
+
updateTime = data['updateTime']
|
18
|
+
if @device.update_property(:level, value, updateTime)
|
19
|
+
return MultiLevelEvent.new(@device.id, updateTime, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def level
|
25
|
+
@device.get_property(:level)[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
RZWaveWay::ZWay.instance.execute(@device.id, SWITCH_MULTI_LEVEL, :Get)
|
30
|
+
end
|
31
|
+
|
32
|
+
def set(value)
|
33
|
+
RZWaveWay::ZWay.instance.execute(@device.id, SWITCH_MULTI_LEVEL, :Set, value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module CommandClasses
|
3
|
+
class WakeUp
|
4
|
+
include CommandClass
|
5
|
+
|
6
|
+
def initialize(data, device)
|
7
|
+
@device = device
|
8
|
+
wakeup_interval = find('data.interval.value', data)
|
9
|
+
last_wakeup_time = find('data.lastWakeup.value', data)
|
10
|
+
last_sleep_time = find('data.lastSleep.value', data)
|
11
|
+
|
12
|
+
@device.add_property(:wakeup_interval,
|
13
|
+
wakeup_interval,
|
14
|
+
find('data.interval.updateTime', data))
|
15
|
+
@device.add_property(:wakeup_last_sleep_time,
|
16
|
+
last_sleep_time,
|
17
|
+
find('data.lastSleep.updateTime', data))
|
18
|
+
@device.add_property(:wakeup_last_wakeup_time,
|
19
|
+
last_wakeup_time,
|
20
|
+
find('data.lastSleep.updateTime', data))
|
21
|
+
|
22
|
+
@device.contact_frequency = wakeup_interval
|
23
|
+
@device.notify_contacted(last_wakeup_time)
|
24
|
+
end
|
25
|
+
|
26
|
+
def process(updates)
|
27
|
+
if updates.keys.include?('data.lastWakeup')
|
28
|
+
data = updates['data.lastWakeup']
|
29
|
+
value = data['value']
|
30
|
+
updateTime = data['updateTime']
|
31
|
+
if @device.update_property(:wakeup_last_wakeup_time, value, updateTime)
|
32
|
+
@device.notify_contacted(value)
|
33
|
+
return AliveEvent.new(@device.id, value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO handle change of wake up interval value?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,82 +1,45 @@
|
|
1
|
-
|
2
|
-
module CommandClasses
|
3
|
-
BASIC = 32
|
4
|
-
SENSOR_BINARY = 48
|
5
|
-
MULTI_LEVEL_SENSOR = 49
|
6
|
-
CONFIGURATION = 112
|
7
|
-
BATTERY = 128
|
8
|
-
WAKEUP = 132
|
9
|
-
ALARM_SENSOR = 156
|
1
|
+
require 'singleton'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
'wakeUpInterval' => 'data.interval.value',
|
18
|
-
'lastSleepTime' => 'data.lastSleep.value',
|
19
|
-
'lastWakeUpTime' => 'data.lastWakeup.value'
|
20
|
-
},
|
21
|
-
BATTERY => {
|
22
|
-
'batteryLevel' => 'data.last.value'
|
23
|
-
}
|
24
|
-
}
|
25
|
-
end
|
3
|
+
require_relative 'command_class'
|
4
|
+
require_relative 'command_classes/battery'
|
5
|
+
require_relative 'command_classes/switch_binary'
|
6
|
+
require_relative 'command_classes/switch_multi_level'
|
7
|
+
require_relative 'command_classes/sensor_binary'
|
8
|
+
require_relative 'command_classes/wake_up'
|
26
9
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
10
|
+
module RZWaveWay
|
11
|
+
module CommandClasses
|
12
|
+
class Dummy
|
13
|
+
include Singleton
|
31
14
|
|
32
|
-
|
33
|
-
@id = id
|
34
|
-
@properties = {}
|
35
|
-
if DATA.has_key? id
|
36
|
-
DATA[id].each do |key, name|
|
37
|
-
@properties[key] = get_data(name, data)
|
38
|
-
end
|
15
|
+
def initialize
|
39
16
|
end
|
40
|
-
end
|
41
17
|
|
42
|
-
|
43
|
-
parts = name.split '.'
|
44
|
-
result = data
|
45
|
-
parts.each do | part |
|
46
|
-
raise "Could not find part '#{part}' in '#{name}'" unless result.has_key? part
|
47
|
-
result = result[part]
|
18
|
+
def process(updates)
|
48
19
|
end
|
49
|
-
result
|
50
20
|
end
|
51
21
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
if
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
when SENSOR_BINARY
|
63
|
-
if names.include?("data.1")
|
64
|
-
@properties['lastLevelChangeTime'] = updates['data.1']["level"]["updateTime"]
|
65
|
-
@properties['level'] = updates['data.1']["level"]["value"]
|
66
|
-
event = LevelEvent.new(device_id, @properties['lastLevelChangeTime'], @properties['level'])
|
22
|
+
class Factory
|
23
|
+
include Singleton
|
24
|
+
include CommandClass
|
25
|
+
|
26
|
+
def instantiate(id, data, device)
|
27
|
+
if CLASSES.has_key? id
|
28
|
+
return CLASSES[id].new(data, device)
|
29
|
+
else
|
30
|
+
return CommandClasses::Dummy.instance
|
67
31
|
end
|
68
32
|
end
|
69
|
-
event
|
70
|
-
end
|
71
33
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
CLASSES = {
|
37
|
+
SWITCH_BINARY => CommandClasses::SwitchBinary,
|
38
|
+
SWITCH_MULTI_LEVEL => CommandClasses::SwitchMultiLevel,
|
39
|
+
SENSOR_BINARY => CommandClasses::SensorBinary,
|
40
|
+
WAKEUP => CommandClasses::WakeUp,
|
41
|
+
BATTERY => CommandClasses::Battery
|
42
|
+
}
|
80
43
|
end
|
81
44
|
end
|
82
|
-
end
|
45
|
+
end
|
data/lib/rzwaveway/events.rb
CHANGED
@@ -12,10 +12,20 @@ module RZWaveWay
|
|
12
12
|
class NotAliveEvent
|
13
13
|
attr_reader :device_id
|
14
14
|
attr_reader :time_delay
|
15
|
+
attr_reader :missed_count
|
15
16
|
|
16
|
-
def initialize
|
17
|
+
def initialize(device_id, time_delay, missed_count)
|
17
18
|
@device_id = device_id
|
18
19
|
@time_delay = time_delay
|
20
|
+
@missed_count = missed_count
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class DeadEvent
|
25
|
+
attr_reader :device_id
|
26
|
+
|
27
|
+
def initialize(device_id)
|
28
|
+
@device_id = device_id
|
19
29
|
end
|
20
30
|
end
|
21
31
|
|
@@ -24,13 +34,28 @@ module RZWaveWay
|
|
24
34
|
attr_reader :time
|
25
35
|
attr_reader :level
|
26
36
|
|
27
|
-
def initialize
|
37
|
+
def initialize(device_id, time, level)
|
28
38
|
@device_id = device_id
|
29
39
|
@time = time
|
30
40
|
@level = level
|
31
41
|
end
|
32
42
|
end
|
33
43
|
|
44
|
+
class MultiLevelEvent < LevelEvent
|
45
|
+
end
|
46
|
+
|
47
|
+
class BatteryValueEvent
|
48
|
+
attr_reader :device_id
|
49
|
+
attr_reader :time
|
50
|
+
attr_reader :value
|
51
|
+
|
52
|
+
def initialize(device_id, time, value)
|
53
|
+
@device_id = device_id
|
54
|
+
@time = time
|
55
|
+
@value = value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
34
59
|
class SmokeEvent
|
35
60
|
attr_reader :device_id
|
36
61
|
attr_reader :time
|
@@ -45,4 +70,4 @@ module RZWaveWay
|
|
45
70
|
attr_reader :device_id
|
46
71
|
attr_reader :time
|
47
72
|
end
|
48
|
-
end
|
73
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RZWaveWay
|
2
|
+
module Extensions
|
3
|
+
class SSASirenStrobeAlarm
|
4
|
+
def initialize device
|
5
|
+
@device = device
|
6
|
+
end
|
7
|
+
|
8
|
+
def disable
|
9
|
+
set DISABLED
|
10
|
+
end
|
11
|
+
|
12
|
+
def enable
|
13
|
+
set(STROBE + SIREN)
|
14
|
+
end
|
15
|
+
|
16
|
+
def enable_siren
|
17
|
+
set SIREN
|
18
|
+
end
|
19
|
+
|
20
|
+
def enable_strobe
|
21
|
+
set STROBE
|
22
|
+
end
|
23
|
+
|
24
|
+
def level
|
25
|
+
case @device.SwitchMultiLevel.level
|
26
|
+
when DISABLED
|
27
|
+
:disabled
|
28
|
+
when STROBE
|
29
|
+
:strobe
|
30
|
+
when SIREN
|
31
|
+
:siren
|
32
|
+
else
|
33
|
+
:strobe_and_siren
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def level!
|
38
|
+
@device.SwitchMultiLevel.get
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
DISABLED = 0
|
45
|
+
STROBE = 33
|
46
|
+
SIREN = 66
|
47
|
+
|
48
|
+
def set level
|
49
|
+
@device.SwitchMultiLevel.set level
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|