ansible4ozw 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ansible.rb +47 -0
- data/lib/ansible/ansible_callback.rb +142 -0
- data/lib/ansible/ansible_device.rb +68 -0
- data/lib/ansible/ansible_value.rb +179 -0
- data/lib/ansible/config.rb +92 -0
- data/lib/ansible/devices/ansible_dimmer.rb +80 -0
- data/lib/ansible/devices/ansible_switch.rb +66 -0
- data/lib/ansible/knx/EIBConnection.rb +2371 -0
- data/lib/ansible/knx/dpt/canonical_1bit.rb +54 -0
- data/lib/ansible/knx/dpt/dpt1.rb +224 -0
- data/lib/ansible/knx/dpt/dpt10.rb +85 -0
- data/lib/ansible/knx/dpt/dpt11.rb +72 -0
- data/lib/ansible/knx/dpt/dpt12.rb +61 -0
- data/lib/ansible/knx/dpt/dpt13.rb +100 -0
- data/lib/ansible/knx/dpt/dpt14.rb +87 -0
- data/lib/ansible/knx/dpt/dpt15.rb +72 -0
- data/lib/ansible/knx/dpt/dpt16.rb +67 -0
- data/lib/ansible/knx/dpt/dpt17.rb +65 -0
- data/lib/ansible/knx/dpt/dpt18.rb +66 -0
- data/lib/ansible/knx/dpt/dpt19.rb +100 -0
- data/lib/ansible/knx/dpt/dpt2.rb +156 -0
- data/lib/ansible/knx/dpt/dpt3.rb +104 -0
- data/lib/ansible/knx/dpt/dpt4.rb +75 -0
- data/lib/ansible/knx/dpt/dpt5.rb +124 -0
- data/lib/ansible/knx/dpt/dpt6.rb +73 -0
- data/lib/ansible/knx/dpt/dpt7.rb +146 -0
- data/lib/ansible/knx/dpt/dpt8.rb +118 -0
- data/lib/ansible/knx/dpt/dpt9.rb +204 -0
- data/lib/ansible/knx/dpt/tests/test_dpt10.rb +45 -0
- data/lib/ansible/knx/dpt/tests/test_dpt9.rb +60 -0
- data/lib/ansible/knx/hexdump.rb +113 -0
- data/lib/ansible/knx/knx_dpt.rb +58 -0
- data/lib/ansible/knx/knx_dpt_scalar.rb +62 -0
- data/lib/ansible/knx/knx_eistypes.rb +76 -0
- data/lib/ansible/knx/knx_protocol.rb +99 -0
- data/lib/ansible/knx/knx_scene.rb +48 -0
- data/lib/ansible/knx/knx_tools.rb +76 -0
- data/lib/ansible/knx/knx_transceiver.rb +237 -0
- data/lib/ansible/knx/knx_value.rb +327 -0
- data/lib/ansible/openzwave/ozw_constants.rb +11 -0
- data/lib/ansible/openzwave/ozw_headers.rb +80 -0
- data/lib/ansible/openzwave/ozw_remote_manager.rb +7615 -0
- data/lib/ansible/openzwave/ozw_types.rb +406 -0
- data/lib/ansible/orbiter_proxy.rb +12 -0
- data/lib/ansible/transceiver.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_bool.rb +74 -0
- data/lib/ansible/zwave/types/valuetype_button.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_byte.rb +78 -0
- data/lib/ansible/zwave/types/valuetype_decimal.rb +64 -0
- data/lib/ansible/zwave/types/valuetype_int.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_list.rb +64 -0
- data/lib/ansible/zwave/types/valuetype_short.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_string.rb +61 -0
- data/lib/ansible/zwave/zwave_command_classes.rb +113 -0
- data/lib/ansible/zwave/zwave_node.rb +5 -0
- data/lib/ansible/zwave/zwave_protocol.rb +52 -0
- data/lib/ansible/zwave/zwave_transceiver.rb +435 -0
- data/lib/ansible/zwave/zwave_value.rb +193 -0
- metadata +108 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
module Ansible
|
26
|
+
|
27
|
+
module ZWave
|
28
|
+
|
29
|
+
# string value type for OpenZWave
|
30
|
+
module ValueType_String
|
31
|
+
|
32
|
+
# define type-specific OZW::Manager API calls
|
33
|
+
def read_operation
|
34
|
+
return :GetValueAsString
|
35
|
+
end
|
36
|
+
|
37
|
+
def write_operation
|
38
|
+
return :SetValue_String
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
def as_canonical_value()
|
43
|
+
puts 'TODO:: zwave_string: as_canonical'
|
44
|
+
return (current_value)
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
def to_protocol_value(new_val)
|
49
|
+
puts 'TODO:: zwave_string: to_protocol'
|
50
|
+
result = nil
|
51
|
+
result = new_val.to_s if [TrueClass, FalseClass].include?(new_val.class)
|
52
|
+
end
|
53
|
+
|
54
|
+
# return a human-readable representation of a ZWave frame
|
55
|
+
def explain
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
module OpenZWave
|
26
|
+
|
27
|
+
# hashmap of ZWave's command class symbol id to byte value
|
28
|
+
CommandClassesByName = {
|
29
|
+
:COMMAND_CLASS_VERSION => 0x86,
|
30
|
+
:COMMAND_CLASS_BATTERY => 0x80,
|
31
|
+
:COMMAND_CLASS_WAKE_UP => 0x84,
|
32
|
+
:COMMAND_CLASS_CONTROLLER_REPLICATION => 0x21,
|
33
|
+
:COMMAND_CLASS_BASIC => 0x20,
|
34
|
+
:COMMAND_CLASS_SWITCH_MULTILEVEL => 0x26,
|
35
|
+
:COMMAND_CLASS_SWITCH_ALL => 0x27,
|
36
|
+
:COMMAND_CLASS_SENSOR_BINARY => 0x30,
|
37
|
+
:COMMAND_CLASS_SENSOR_MULTILEVEL => 0x31,
|
38
|
+
:COMMAND_CLASS_ALARM => 0x71,
|
39
|
+
:COMMAND_CLASS_MULTI_CMD => 0x8F,
|
40
|
+
:COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE => 0x46,
|
41
|
+
:COMMAND_CLASS_CLOCK => 0x81,
|
42
|
+
:COMMAND_CLASS_ASSOCIATION => 0x85,
|
43
|
+
:COMMAND_CLASS_CONFIGURATION => 0x70,
|
44
|
+
:COMMAND_CLASS_MANUFACTURER_SPECIFIC => 0x72,
|
45
|
+
:COMMAND_CLASS_APPLICATION_STATUS => 0x22,
|
46
|
+
:COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION => 0x9B,
|
47
|
+
:COMMAND_CLASS_AV_CONTENT_DIRECTORY_MD => 0x95,
|
48
|
+
:COMMAND_CLASS_AV_CONTENT_SEARCH_MD => 0x97,
|
49
|
+
:COMMAND_CLASS_AV_RENDERER_STATUS => 0x96,
|
50
|
+
:COMMAND_CLASS_AV_TAGGING_MD => 0x99,
|
51
|
+
:COMMAND_CLASS_BASIC_WINDOW_COVERING => 0x50,
|
52
|
+
:COMMAND_CLASS_CHIMNEY_FAN => 0x2A,
|
53
|
+
:COMMAND_CLASS_COMPOSITE => 0x8D,
|
54
|
+
:COMMAND_CLASS_DOOR_LOCK => 0x62,
|
55
|
+
:COMMAND_CLASS_ENERGY_PRODUCTION => 0x90,
|
56
|
+
:COMMAND_CLASS_FIRMWARE_UPDATE_MD => 0x7a,
|
57
|
+
:COMMAND_CLASS_GEOGRAPHIC_LOCATION => 0x8C,
|
58
|
+
:COMMAND_CLASS_GROUPING_NAME => 0x7B,
|
59
|
+
:COMMAND_CLASS_HAIL => 0x82,
|
60
|
+
:COMMAND_CLASS_INDICATOR => 0x87,
|
61
|
+
:COMMAND_CLASS_IP_CONFIGURATION => 0x9A,
|
62
|
+
:COMMAND_CLASS_LANGUAGE => 0x89,
|
63
|
+
:COMMAND_CLASS_LOCK => 0x76,
|
64
|
+
:COMMAND_CLASS_MANUFACTURER_PROPRIETARY => 0x91,
|
65
|
+
:COMMAND_CLASS_METER_PULSE => 0x35,
|
66
|
+
:COMMAND_CLASS_METER => 0x32,
|
67
|
+
:COMMAND_CLASS_MTP_WINDOW_COVERING => 0x51,
|
68
|
+
:COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION => 0x8E,
|
69
|
+
:COMMAND_CLASS_MULTI_INSTANCE => 0x60,
|
70
|
+
:COMMAND_CLASS_NO_OPERATION => 0x00,
|
71
|
+
:COMMAND_CLASS_NODE_NAMING => 0x77,
|
72
|
+
:COMMAND_CLASS_NON_INTEROPERABLE => 0xf0,
|
73
|
+
:COMMAND_CLASS_POWERLEVEL => 0x73,
|
74
|
+
:COMMAND_CLASS_PROPRIETARY => 0x88,
|
75
|
+
:COMMAND_CLASS_PROTECTION => 0x75,
|
76
|
+
:COMMAND_CLASS_REMOTE_ASSOCIATION_ACTIVATE => 0x7c,
|
77
|
+
:COMMAND_CLASS_REMOTE_ASSOCIATION => 0x7d,
|
78
|
+
:COMMAND_CLASS_SCENE_ACTIVATION => 0x2b,
|
79
|
+
:COMMAND_CLASS_SCENE_ACTUATOR_CONF => 0x2C,
|
80
|
+
:COMMAND_CLASS_SCENE_CONTROLLER_CONF => 0x2D,
|
81
|
+
:COMMAND_CLASS_SCREEN_ATTRIBUTES => 0x93,
|
82
|
+
:COMMAND_CLASS_SCREEN_MD => 0x92,
|
83
|
+
:COMMAND_CLASS_SECURITY => 0x98,
|
84
|
+
:COMMAND_CLASS_SENSOR_ALARM => 0x9C,
|
85
|
+
:COMMAND_CLASS_SENSOR_CONFIGURATION => 0x9E,
|
86
|
+
:COMMAND_CLASS_SILENCE_ALARM => 0x9d,
|
87
|
+
:COMMAND_CLASS_SIMPLE_AV_CONTROL => 0x94,
|
88
|
+
:COMMAND_CLASS_SWITCH_BINARY => 0x25,
|
89
|
+
:COMMAND_CLASS_SWITCH_TOGGLE_BINARY => 0x28,
|
90
|
+
:COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL => 0x29,
|
91
|
+
:COMMAND_CLASS_THERMOSTAT_FAN_MODE => 0x44,
|
92
|
+
:COMMAND_CLASS_THERMOSTAT_FAN_STATE => 0x45,
|
93
|
+
:COMMAND_CLASS_THERMOSTAT_HEATING => 0x38,
|
94
|
+
:COMMAND_CLASS_THERMOSTAT_MODE => 0x40,
|
95
|
+
:COMMAND_CLASS_THERMOSTAT_OPERATING_STATE => 0x42,
|
96
|
+
:COMMAND_CLASS_THERMOSTAT_SETBACK => 0x47,
|
97
|
+
:COMMAND_CLASS_THERMOSTAT_SETPOINT => 0x43,
|
98
|
+
:COMMAND_CLASS_TIME_PARAMETERS => 0x8B,
|
99
|
+
:COMMAND_CLASS_TIME => 0x8a,
|
100
|
+
:COMMAND_CLASS_USER_CODE => 0x63,
|
101
|
+
:COMMAND_CLASS_ZIP_ADV_CLIENT => 0x34,
|
102
|
+
:COMMAND_CLASS_ZIP_ADV_SERVER => 0x33,
|
103
|
+
:COMMAND_CLASS_ZIP_ADV_SERVICES => 0x2F,
|
104
|
+
:COMMAND_CLASS_ZIP_CLIENT => 0x2e,
|
105
|
+
:COMMAND_CLASS_ZIP_SERVER => 0x24,
|
106
|
+
:COMMAND_CLASS_ZIP_SERVICES => 0x23
|
107
|
+
}
|
108
|
+
|
109
|
+
# hashmap of ZWave's command class byte to symbol
|
110
|
+
CommandClassesByID = {}
|
111
|
+
CommandClassesByName.each {|key, value| CommandClassesByID[value] = key }
|
112
|
+
|
113
|
+
end #module
|
@@ -0,0 +1,52 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
require 'bindata'
|
26
|
+
|
27
|
+
#~ // ID Packing:
|
28
|
+
#~ // Bits
|
29
|
+
#~ // 24-31: 8 bits. Node ID of device
|
30
|
+
#~ // 22-23: 2 bits. genre of value (see ValueGenre enum).
|
31
|
+
#~ // 14-21: 8 bits. ID of command class that created and manages this value.
|
32
|
+
#~ // 12-13: 2 bits. Unused.
|
33
|
+
#~ // 04-11: 8 bits. Index of value within all the value created by the command class
|
34
|
+
#~ // instance (in configuration parameters, this is also the parameter ID).
|
35
|
+
#~ // 00-03: 4 bits. Type of value (bool, byte, string etc).
|
36
|
+
class OZW_ValueID_id < BinData::Record
|
37
|
+
bit8 :node_id, { :display_name => "Node ID of device" }
|
38
|
+
bit2 :value_genre, { :display_name => "Value Genre"}
|
39
|
+
bit8 :cmd_class, { :display_name => "command class"}
|
40
|
+
bit2 :pad1
|
41
|
+
bit8 :value_idx, { :display_name => "value index"}
|
42
|
+
bit4 :value_type, { :display_name => "value type( bool, byte, string etc)"}
|
43
|
+
end
|
44
|
+
|
45
|
+
#~ // ID1 Packing:
|
46
|
+
#~ // Bits
|
47
|
+
#~ // 24-31 8 bits. Instance Index of the command class.
|
48
|
+
class OZW_ValueID_id1 < BinData::Record
|
49
|
+
bit8 :cmd_class_instance, { :display_name => "cmd class instance" }
|
50
|
+
bit24 :unused2, { :display_name => "(unused)" }
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,435 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'onstomp'
|
27
|
+
require 'thrift'
|
28
|
+
|
29
|
+
require 'config'
|
30
|
+
require 'zwave_protocol'
|
31
|
+
require 'zwave_value'
|
32
|
+
require 'transceiver'
|
33
|
+
|
34
|
+
module Ansible
|
35
|
+
|
36
|
+
module ZWave
|
37
|
+
|
38
|
+
# the ZWave transceiver is responsible for communication with the ZWave network
|
39
|
+
# uses ozwd, a Thrift wrapper around the OpenZWave library
|
40
|
+
class ZWave_Transceiver < Transceiver
|
41
|
+
|
42
|
+
# we also use callbacks
|
43
|
+
include AnsibleCallback
|
44
|
+
|
45
|
+
attr_reader :stompURL, :thriftURL
|
46
|
+
|
47
|
+
def initialize(stompURL, thriftURL)
|
48
|
+
raise "Already initialized!" unless Ansible::ZWave::ValueID::transceiver.nil?
|
49
|
+
puts "#{self}: initializing" if $DEBUG
|
50
|
+
@stompURL, @thriftURL = stompURL, thriftURL
|
51
|
+
#@stompMutex = Mutex.new
|
52
|
+
@thriftMutex = Mutex.new
|
53
|
+
@stomp_ok, @thrift_ok = false, false
|
54
|
+
@alive = true
|
55
|
+
super()
|
56
|
+
# store reference to ourselves to the classes that use us
|
57
|
+
Ansible::ZWave::ValueID.transceiver = self
|
58
|
+
|
59
|
+
@ValueMonitors = {}
|
60
|
+
@ValueMonitorMutex = Mutex.new
|
61
|
+
end
|
62
|
+
|
63
|
+
# initialize connection to STOMP server
|
64
|
+
def init_stomp
|
65
|
+
unless @stomp_ok
|
66
|
+
begin
|
67
|
+
#puts "init_stomp\n-------------\n\t" + caller.join("\n\t") + "\n"
|
68
|
+
@stompserver = OnStomp::Client.new(@stompURL)
|
69
|
+
@stompserver.on_connection_died { |client, con|
|
70
|
+
@stomp_ok = false
|
71
|
+
puts "STOMP connection died!! sleeping for 3 seconds and then retrying..."
|
72
|
+
puts "stack trace: \n\t"<< caller.join("\t\n")
|
73
|
+
sleep(3)
|
74
|
+
@stompserver.connect
|
75
|
+
}
|
76
|
+
#
|
77
|
+
@stompserver.on_connection_closed { |client, con|
|
78
|
+
@stomp_ok = false
|
79
|
+
puts "STOMP connection closed!! sleeping for 10 seconds and then retrying..."
|
80
|
+
puts "stack trace: \n\t"<< caller.join("\t\n")
|
81
|
+
sleep(10)
|
82
|
+
@stompserver.connect
|
83
|
+
}
|
84
|
+
#
|
85
|
+
@stompserver.on_connection_established { |client, con|
|
86
|
+
puts "STOMP: Connected to broker using protocol version #{con.version}"
|
87
|
+
@stomp_ok = true
|
88
|
+
}
|
89
|
+
@stompserver.connect
|
90
|
+
rescue Errno::ECONNREFUSED => e
|
91
|
+
@stomp_ok = false
|
92
|
+
puts "#{e}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
return @stompserver
|
96
|
+
end
|
97
|
+
|
98
|
+
# get handle to stomp server, connect unless already connected
|
99
|
+
# caller must unlock @stompMutex when done with stomp
|
100
|
+
def stomp
|
101
|
+
@stomp_ok ? @stompserver : init_stomp()
|
102
|
+
end
|
103
|
+
|
104
|
+
# Thrift URL Regexp
|
105
|
+
ThriftURL_RE = /thrift:\/\/([^:]*)(?::(.*))*/
|
106
|
+
|
107
|
+
# initialize connection to THRIFT server
|
108
|
+
def init_thrift()
|
109
|
+
unless @thrift_ok
|
110
|
+
# connect to Thrift server for OpenZWave
|
111
|
+
begin
|
112
|
+
if md = ThriftURL_RE.match(@thriftURL) then
|
113
|
+
host = md[1]
|
114
|
+
port = md[2].nil?? 9090: md[2].to_i
|
115
|
+
#puts "THRIFT host, port = #{host}:#{port}"
|
116
|
+
@thrift_transport = Thrift::BufferedTransport.new(Thrift::Socket.new(host, port))
|
117
|
+
@thrift_protocol = Thrift::BinaryProtocol.new(@thrift_transport)
|
118
|
+
@thrift_transport.open()
|
119
|
+
@manager = ::OpenZWave::RemoteManager::Client.new(@thrift_protocol)
|
120
|
+
# fetch all known ValueID's from the server
|
121
|
+
@manager.SendAllValues
|
122
|
+
@thrift_ok = true
|
123
|
+
@thrift_heartbeat = Thread.new{
|
124
|
+
puts "Thrift: New heartbeat thread, #{Thread.current}"
|
125
|
+
# aargh, ugly heartbeat
|
126
|
+
while (@thrift_ok) do
|
127
|
+
sleep(1)
|
128
|
+
#puts 'ping...'
|
129
|
+
manager_send(:GetControllerNodeId, HomeID)
|
130
|
+
end
|
131
|
+
puts "Thrift: heartbeat thread exiting, #{Thread.current}"
|
132
|
+
}
|
133
|
+
else
|
134
|
+
raise "Thrift URL invalid"
|
135
|
+
end
|
136
|
+
#rescue Thrift::TransportException => e
|
137
|
+
rescue Exception => e
|
138
|
+
@thrift_ok = false
|
139
|
+
puts "#{e}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
return @manager
|
143
|
+
end
|
144
|
+
|
145
|
+
# get handle to OpenZWave::RemoteManager
|
146
|
+
def manager
|
147
|
+
# TODO: add caller watch here, (check for unsynchronized access)
|
148
|
+
@thrift_ok ? @manager : init_thrift()
|
149
|
+
end
|
150
|
+
|
151
|
+
# the preferred method to access OpenZWave::Manager methods
|
152
|
+
# is via this generic call function, which takes care of all the nitty-gritty
|
153
|
+
# details such as connection monitoring and thread synchronization
|
154
|
+
def manager_send(meth, *args)
|
155
|
+
result = nil
|
156
|
+
@thriftMutex.synchronize {
|
157
|
+
begin
|
158
|
+
result = manager.method(meth).call(*args)
|
159
|
+
rescue Thrift::TransportException => e
|
160
|
+
@thrift_ok = false
|
161
|
+
puts "Thrift transport exception, in method #{meth.inspect}"
|
162
|
+
puts "--------------------------, callers=\n\t\t" + caller[0..2].join("\n\t\t")
|
163
|
+
sleep(1)
|
164
|
+
retry
|
165
|
+
rescue Exception => e
|
166
|
+
@thrift_ok = false
|
167
|
+
puts "OpenZWave exception: #{e}, in method #{meth.inspect}"
|
168
|
+
puts "--------------------, callers=\n\t\t" + caller[0..2].join("\n\t\t")
|
169
|
+
end
|
170
|
+
}
|
171
|
+
return(result)
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# transceiver main loop, runs in its own Ruby thread
|
176
|
+
#
|
177
|
+
def run
|
178
|
+
# 1) subscribe to zwave's notification channel
|
179
|
+
stomp.subscribe '/queue/zwave/monitor' do |msg|
|
180
|
+
# Invoked every time the broker delivers a MESSAGE frame for the
|
181
|
+
# SUBSCRIBE frame generated by this method call.
|
182
|
+
puts "\n------ ZWAVE MESSAGE (#{Time.now}) ------" if $DEBUG
|
183
|
+
begin
|
184
|
+
value = nil
|
185
|
+
# lookup or create ValueID related to Notification
|
186
|
+
if msg.headers["HomeID"] and msg.headers["ValueID"] then
|
187
|
+
homeID = msg.headers["HomeID"]
|
188
|
+
valueID = msg.headers["ValueID"]
|
189
|
+
# sync current HomeID
|
190
|
+
h = homeID.to_i(16)
|
191
|
+
unless Ansible::ZWave.const_defined?(:HomeID) then
|
192
|
+
if h > 0 then
|
193
|
+
puts "------ SETTING HOME ID: #{homeID}"
|
194
|
+
Ansible::ZWave.const_set("HomeID", h)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
# get or create ValueID object
|
198
|
+
value = Ansible::ZWave::ValueID.get_or_create(homeID, valueID)
|
199
|
+
end
|
200
|
+
# bind other notification parameters
|
201
|
+
if msg.headers["NotificationType"] then
|
202
|
+
node = msg.headers["NotificationNodeId"].to_i(16)
|
203
|
+
byte = msg.headers["NotificationByte"].to_i(16)
|
204
|
+
notif_type = msg.headers["NotificationType"].to_i(16)
|
205
|
+
name, desc = OpenZWave::NotificationTypes[notif_type]
|
206
|
+
# dynamic notification handler dispatch mechanism
|
207
|
+
if md = /Type_(.*)/.match(name) then
|
208
|
+
handler = "notification_" + md[1]
|
209
|
+
puts "#{handler} (n:#{node}) (b:#{byte}) (#{value})"
|
210
|
+
__send__(handler, node, byte, value) if respond_to?(handler)
|
211
|
+
# fire all notification-related callbacks for the value, if any
|
212
|
+
# e.g. onValueChanged, onValueRefreshed etc.
|
213
|
+
if value.is_a?AnsibleValue then
|
214
|
+
value.fire_callback("on#{md[1]}".to_sym)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
# controller state change notification mechanism
|
219
|
+
if ctrl_state = msg.headers["ControllerState"] then
|
220
|
+
controller_state(ctrl_state.to_i(16))
|
221
|
+
end
|
222
|
+
rescue Exception => e
|
223
|
+
puts "ZWaveTransceiver::decode_monitor() exception: #{e}"
|
224
|
+
puts "\t"+e.backtrace[0..3].join("\n\t")
|
225
|
+
end
|
226
|
+
end # do subscribe
|
227
|
+
# 2) Sleep forever (how pretty)
|
228
|
+
while true #@alive #FIXME
|
229
|
+
sleep(1)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
#
|
235
|
+
#
|
236
|
+
# NOTIFICATIONS
|
237
|
+
#
|
238
|
+
|
239
|
+
# a value has been added to the Z-Wave network
|
240
|
+
def notification_ValueAdded(nodeId, byte, value)
|
241
|
+
#@@Values[homeID].push(value)
|
242
|
+
end
|
243
|
+
|
244
|
+
# a value has been removed from the Z-Wave network
|
245
|
+
def notification_ValueRemoved(nodeId, byte, value)
|
246
|
+
# A node value has been removed from OpenZWave's list. This only occurs when a node is removed.
|
247
|
+
#@@Values[homeID].delete(value)
|
248
|
+
end
|
249
|
+
|
250
|
+
# A node value has been updated from the Z-Wave network.
|
251
|
+
def notification_ValueChanged(nodeId, byte, value)
|
252
|
+
# OpenZWave peculiarity: we got a ValueChanged event, but the value
|
253
|
+
# reported by OpenZWave is unchanged. Thus we need to poll the
|
254
|
+
# device using :RequestNodeDynamic, wait for NodeQueriesComplete
|
255
|
+
# then re-get the value
|
256
|
+
#trigger_value_monitor(value)
|
257
|
+
#
|
258
|
+
# as of r471 ValueChanged behaves correctly
|
259
|
+
AnsibleValue[:_nodeId => nodeId, :_gerne => 1].each { |v|
|
260
|
+
v.get
|
261
|
+
}
|
262
|
+
end
|
263
|
+
|
264
|
+
# A node value has been refreshed from the Z-Wave network.
|
265
|
+
def notification_ValueRefreshed(nodeId, byte, value)
|
266
|
+
#value.get unless value.nil?
|
267
|
+
end
|
268
|
+
|
269
|
+
# The associations for the node have changed. The application
|
270
|
+
# should rebuild any group information it holds about the node.
|
271
|
+
def notification_Group(nodeId, byte, value)
|
272
|
+
puts 'TODO'
|
273
|
+
end
|
274
|
+
|
275
|
+
# A new node has been found (not already stored in zwcfg*.xml file)
|
276
|
+
def notification_NodeNew(nodeId, byte, value)
|
277
|
+
puts 'TODO'
|
278
|
+
end
|
279
|
+
|
280
|
+
# A new node has been added to OpenZWave's list. This may be due
|
281
|
+
# to a device being added to the Z-Wave network, or because the
|
282
|
+
# application is initializing itself.
|
283
|
+
def notification_NodeAdded(nodeId, byte, value)
|
284
|
+
puts 'TODO'
|
285
|
+
end
|
286
|
+
|
287
|
+
# A node has been removed from OpenZWave's list. This may be due
|
288
|
+
# to a device being removed from the Z-Wave network, or because
|
289
|
+
# the application is closing.
|
290
|
+
def notification_NodeRemoved(nodeId, byte, value)
|
291
|
+
puts 'TODO'
|
292
|
+
end
|
293
|
+
|
294
|
+
# Basic node information has been receievd, such as whether
|
295
|
+
# the node is a listening device, a routing device and its
|
296
|
+
# baud rate and basic, generic and specific types. It is
|
297
|
+
# after this notification that you can call Manager::GetNodeType
|
298
|
+
# to obtain a label containing the device description. */
|
299
|
+
def notification_NodeProtocolInfo(nodeId, byte, value)
|
300
|
+
puts 'TODO'
|
301
|
+
end
|
302
|
+
|
303
|
+
# One of the node names has changed (name, manufacturer, product).
|
304
|
+
def notification_NodeNaming(nodeId, byte, value)
|
305
|
+
puts 'TODO'
|
306
|
+
end
|
307
|
+
|
308
|
+
# A node has triggered an event. This is commonly caused when a node
|
309
|
+
# sends a Basic_Set command to the controller. The event value is
|
310
|
+
# stored in the notification.
|
311
|
+
def notification_NodeEvent(nodeId, byte, value)
|
312
|
+
puts 'TODO'
|
313
|
+
end
|
314
|
+
|
315
|
+
# Polling of a node has been successfully turned off by a call
|
316
|
+
# to Manager::DisablePoll
|
317
|
+
def notification_PollingDisabled(nodeId, byte, value)
|
318
|
+
puts 'TODO'
|
319
|
+
end
|
320
|
+
|
321
|
+
# Polling of a node has been successfully turned on by a call
|
322
|
+
# to Manager::EnablePoll
|
323
|
+
def notification_PollingEnabled(nodeId, byte, value)
|
324
|
+
puts 'TODO'
|
325
|
+
end
|
326
|
+
|
327
|
+
# A driver for a PC Z-Wave controller has been added and is ready
|
328
|
+
# to use. The notification will contain the controller's Home ID,
|
329
|
+
# which is needed to call most of the Manager methods.
|
330
|
+
def notification_DriverReady(nodeId, byte, value)
|
331
|
+
puts 'TODO'
|
332
|
+
end
|
333
|
+
|
334
|
+
# Driver failed to load */
|
335
|
+
def notification_DriverFailed(nodeId, byte, value)
|
336
|
+
puts 'TODO'
|
337
|
+
end
|
338
|
+
|
339
|
+
# All nodes and values for this driver have been removed.
|
340
|
+
# This is sent instead of potentially hundreds of individual node
|
341
|
+
# and value notifications.
|
342
|
+
def notification_DriverReset(nodeId, byte, value)
|
343
|
+
puts 'TODO'
|
344
|
+
end
|
345
|
+
|
346
|
+
# The last message that was sent is now complete.
|
347
|
+
def notification_MsgComplete(nodeId, byte, value)
|
348
|
+
puts 'TODO'
|
349
|
+
end
|
350
|
+
|
351
|
+
# The queries on a node that are essential to its operation have
|
352
|
+
# been completed. The node can now handle incoming messages.
|
353
|
+
def notification_EssentialNodeQueriesComplete(nodeId, byte, value)
|
354
|
+
#OpenZWave::RefreshedNodes[nodeId] = true
|
355
|
+
end
|
356
|
+
|
357
|
+
# All the initialisation queries on a node have been completed.
|
358
|
+
def notification_NodeQueriesComplete(nodeId, byte, value)
|
359
|
+
# node monitor phase 2:
|
360
|
+
=begin
|
361
|
+
@ValueMonitorMutex.synchronize do
|
362
|
+
sleep(2)
|
363
|
+
AnsibleValue[:_nodeId => nodeId].each { |val|
|
364
|
+
val.get()
|
365
|
+
}
|
366
|
+
# all values now should be fresh
|
367
|
+
@ValueMonitors[nodeId] = false
|
368
|
+
fire_callback(:onMonitorStop)
|
369
|
+
puts "==> trigger change monitor ENDED<=="
|
370
|
+
end
|
371
|
+
=end
|
372
|
+
end
|
373
|
+
|
374
|
+
# All awake nodes have been queried, so client application can
|
375
|
+
# expected complete data for these nodes.
|
376
|
+
def notification_AwakeNodesQueried(nodeId, byte, value)
|
377
|
+
puts 'TODO'
|
378
|
+
end
|
379
|
+
|
380
|
+
# All nodes have been queried, so client application can
|
381
|
+
# expect complete data.
|
382
|
+
def notification_AllNodesQueried(nodeId, byte, value) #
|
383
|
+
puts 'TODO'
|
384
|
+
end
|
385
|
+
|
386
|
+
# ------------------------------
|
387
|
+
# CONTROLLER STATE NOTIFICATIONS
|
388
|
+
# ------------------------------
|
389
|
+
|
390
|
+
# handle controller state notifications
|
391
|
+
def controller_state(idx)
|
392
|
+
puts OpenZWave::ControllerStates[idx].join(': ')
|
393
|
+
end
|
394
|
+
=begin
|
395
|
+
ControllerCommand_RemoveFailedNode (id=7)
|
396
|
+
irb(main):024:0> ZWT.manager.BeginControllerCommand(HomeID, 7, false, 3, 0)
|
397
|
+
=> true
|
398
|
+
irb(main):025:0>
|
399
|
+
------ ZWAVE MESSAGE (2012-02-05 22:43:28 +0200) ------
|
400
|
+
ControllerState_InProgress: The controller is communicating with the other device to carry out the command.
|
401
|
+
|
402
|
+
------ ZWAVE MESSAGE (2012-02-05 22:43:28 +0200) ------
|
403
|
+
ControllerState_Completed: The command has completed successfully.
|
404
|
+
=end
|
405
|
+
# TODO: remove all AnsibleValues upon completion of
|
406
|
+
|
407
|
+
|
408
|
+
=begin
|
409
|
+
DEPRECATED since OZW rev.477
|
410
|
+
# Zwave value notification system only informs us about a _manual_
|
411
|
+
# operation of a ZWave node using a ValueChanged notification.
|
412
|
+
# We need to monitor that node in order to get the actual device status.
|
413
|
+
def trigger_value_monitor(nodeId)
|
414
|
+
@ValueMonitorMutex.synchronize do
|
415
|
+
# define a node monitor proc then spawn a new thread to run it
|
416
|
+
unless @ValueMonitors[nodeId] then
|
417
|
+
puts "==> spawning trigger change monitor thread for #{nodeId}<=="
|
418
|
+
fire_callback(:onMonitorStart)
|
419
|
+
AnsibleValue[:_nodeId => nodeId].each { |val|
|
420
|
+
manager_send(:RefreshValue, val)
|
421
|
+
}
|
422
|
+
# node monitor phase 1: request all dynamic node values from OZW
|
423
|
+
#manager_send(:RequestNodeDynamic, Ansible::ZWave::HomeID, nodeId)
|
424
|
+
# then declare the handler to run upon NodeQueriesComplete notification
|
425
|
+
@ValueMonitors[nodeId] = true
|
426
|
+
# node monitor phase 2: see notification_NodeQueriesComplete
|
427
|
+
end # unless
|
428
|
+
end # do
|
429
|
+
end
|
430
|
+
=end
|
431
|
+
end #class
|
432
|
+
|
433
|
+
end
|
434
|
+
|
435
|
+
end # module Ansible
|