Class: Ansible::ZWave::ZWave_Transceiver
- Inherits:
-
Transceiver
- Object
- Transceiver
- Ansible::ZWave::ZWave_Transceiver
- Includes:
- AnsibleCallback
- Defined in:
- lib/ansible/zwave/zwave_transceiver.rb
Overview
the ZWave transceiver is responsible for communication with the ZWave network uses ozwd, a Thrift wrapper around the OpenZWave library
Constant Summary collapse
- ThriftURL_RE =
Thrift URL Regexp
/thrift:\/\/([^:]*)(?::(.*))*/
Instance Attribute Summary collapse
-
#stompURL ⇒ Object
readonly
Returns the value of attribute stompURL.
-
#thriftURL ⇒ Object
readonly
Returns the value of attribute thriftURL.
Attributes inherited from Transceiver
Instance Method Summary collapse
-
#controller_state(idx) ⇒ Object
handle controller state notifications.
-
#init_stomp ⇒ Object
initialize connection to STOMP server.
-
#init_thrift ⇒ Object
initialize connection to THRIFT server.
-
#initialize(stompURL, thriftURL) ⇒ ZWave_Transceiver
constructor
A new instance of ZWave_Transceiver.
-
#manager ⇒ Object
get handle to OpenZWave::RemoteManager.
-
#manager_send(meth, *args) ⇒ Object
the preferred method to access OpenZWave::Manager methods is via this generic call function, which takes care of all the nitty-gritty details such as connection monitoring and thread synchronization.
-
#notification_AllNodesQueried(nodeId, byte, value) ⇒ Object
All nodes have been queried, so client application can expect complete data.
-
#notification_AwakeNodesQueried(nodeId, byte, value) ⇒ Object
All awake nodes have been queried, so client application can expected complete data for these nodes.
-
#notification_DriverFailed(nodeId, byte, value) ⇒ Object
Driver failed to load */.
-
#notification_DriverReady(nodeId, byte, value) ⇒ Object
A driver for a PC Z-Wave controller has been added and is ready to use.
-
#notification_DriverReset(nodeId, byte, value) ⇒ Object
All nodes and values for this driver have been removed.
-
#notification_EssentialNodeQueriesComplete(nodeId, byte, value) ⇒ Object
The queries on a node that are essential to its operation have been completed.
-
#notification_Group(nodeId, byte, value) ⇒ Object
The associations for the node have changed.
-
#notification_MsgComplete(nodeId, byte, value) ⇒ Object
The last message that was sent is now complete.
-
#notification_NodeAdded(nodeId, byte, value) ⇒ Object
A new node has been added to OpenZWave’s list.
-
#notification_NodeEvent(nodeId, byte, value) ⇒ Object
A node has triggered an event.
-
#notification_NodeNaming(nodeId, byte, value) ⇒ Object
One of the node names has changed (name, manufacturer, product).
-
#notification_NodeNew(nodeId, byte, value) ⇒ Object
A new node has been found (not already stored in zwcfg*.xml file).
-
#notification_NodeProtocolInfo(nodeId, byte, value) ⇒ Object
Basic node information has been receievd, such as whether the node is a listening device, a routing device and its baud rate and basic, generic and specific types.
-
#notification_NodeQueriesComplete(nodeId, byte, value) ⇒ Object
All the initialisation queries on a node have been completed.
-
#notification_NodeRemoved(nodeId, byte, value) ⇒ Object
A node has been removed from OpenZWave’s list.
-
#notification_PollingDisabled(nodeId, byte, value) ⇒ Object
Polling of a node has been successfully turned off by a call to Manager::DisablePoll.
-
#notification_PollingEnabled(nodeId, byte, value) ⇒ Object
Polling of a node has been successfully turned on by a call to Manager::EnablePoll.
-
#notification_ValueAdded(nodeId, byte, value) ⇒ Object
a value has been added to the Z-Wave network.
-
#notification_ValueChanged(nodeId, byte, value) ⇒ Object
A node value has been updated from the Z-Wave network.
-
#notification_ValueRefreshed(nodeId, byte, value) ⇒ Object
A node value has been refreshed from the Z-Wave network.
-
#notification_ValueRemoved(nodeId, byte, value) ⇒ Object
a value has been removed from the Z-Wave network.
-
#run ⇒ Object
transceiver main loop, runs in its own Ruby thread.
-
#stomp ⇒ Object
get handle to stomp server, connect unless already connected caller must unlock @stompMutex when done with stomp.
Methods included from AnsibleCallback
#add_callback, #fire_callback, #remove_callback
Methods inherited from Transceiver
Constructor Details
#initialize(stompURL, thriftURL) ⇒ ZWave_Transceiver
Returns a new instance of ZWave_Transceiver.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 41 def initialize(stompURL, thriftURL) raise "Already initialized!" unless Ansible::ZWave::ValueID::transceiver.nil? puts "#{self}: initializing" if $DEBUG @stompURL, @thriftURL = stompURL, thriftURL #@stompMutex = Mutex.new @thriftMutex = Mutex.new @stomp_ok, @thrift_ok = false, false @alive = true super() # store reference to ourselves to the classes that use us Ansible::ZWave::ValueID.transceiver = self @ValueMonitors = {} @ValueMonitorMutex = Mutex.new end |
Instance Attribute Details
#stompURL ⇒ Object (readonly)
Returns the value of attribute stompURL.
39 40 41 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 39 def stompURL @stompURL end |
#thriftURL ⇒ Object (readonly)
Returns the value of attribute thriftURL.
39 40 41 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 39 def thriftURL @thriftURL end |
Instance Method Details
#controller_state(idx) ⇒ Object
handle controller state notifications
385 386 387 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 385 def controller_state(idx) puts OpenZWave::ControllerStates[idx].join(': ') end |
#init_stomp ⇒ Object
initialize connection to STOMP server
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 58 def init_stomp unless @stomp_ok begin #puts "init_stomp\n-------------\n\t" + caller.join("\n\t") + "\n" @stompserver = OnStomp::Client.new(@stompURL) @stompserver.on_connection_died { |client, con| @stomp_ok = false puts "STOMP connection died!! sleeping for 3 seconds and then retrying..." puts "stack trace: \n\t"<< caller.join("\t\n") sleep(3) @stompserver.connect } # @stompserver.on_connection_closed { |client, con| @stomp_ok = false puts "STOMP connection closed!! sleeping for 10 seconds and then retrying..." puts "stack trace: \n\t"<< caller.join("\t\n") sleep(10) @stompserver.connect } # @stompserver.on_connection_established { |client, con| puts "STOMP: Connected to broker using protocol version #{con.version}" @stomp_ok = true } @stompserver.connect rescue Errno::ECONNREFUSED => e @stomp_ok = false puts "#{e}" end end return @stompserver end |
#init_thrift ⇒ Object
initialize connection to THRIFT server
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 102 def init_thrift() unless @thrift_ok # connect to Thrift server for OpenZWave begin if md = ThriftURL_RE.match(@thriftURL) then host = md[1] port = md[2].nil?? 9090: md[2].to_i #puts "THRIFT host, port = #{host}:#{port}" @thrift_transport = Thrift::BufferedTransport.new(Thrift::Socket.new(host, port)) @thrift_protocol = Thrift::BinaryProtocol.new(@thrift_transport) @thrift_transport.open() @manager = ::OpenZWave::RemoteManager::Client.new(@thrift_protocol) # fetch all known ValueID's from the server @manager.SendAllValues @thrift_ok = true @thrift_heartbeat = Thread.new{ puts "Thrift: New heartbeat thread, #{Thread.current}" # aargh, ugly heartbeat while (@thrift_ok) do sleep(1) #puts 'ping...' manager_send(:GetControllerNodeId, HomeID) end puts "Thrift: heartbeat thread exiting, #{Thread.current}" } else raise "Thrift URL invalid" end #rescue Thrift::TransportException => e rescue Exception => e @thrift_ok = false puts "#{e}" end end return @manager end |
#manager ⇒ Object
get handle to OpenZWave::RemoteManager
140 141 142 143 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 140 def manager # TODO: add caller watch here, (check for unsynchronized access) @thrift_ok ? @manager : init_thrift() end |
#manager_send(meth, *args) ⇒ Object
the preferred method to access OpenZWave::Manager methods is via this generic call function, which takes care of all the nitty-gritty details such as connection monitoring and thread synchronization
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 148 def manager_send(meth, *args) result = nil @thriftMutex.synchronize { begin result = manager.method(meth).call(*args) rescue Thrift::TransportException => e @thrift_ok = false puts "Thrift transport exception, in method #{meth.inspect}" puts "--------------------------, callers=\n\t\t" + caller[0..2].join("\n\t\t") sleep(1) retry rescue Exception => e @thrift_ok = false puts "OpenZWave exception: #{e}, in method #{meth.inspect}" puts "--------------------, callers=\n\t\t" + caller[0..2].join("\n\t\t") end } return(result) end |
#notification_AllNodesQueried(nodeId, byte, value) ⇒ Object
All nodes have been queried, so client application can expect complete data.
376 377 378 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 376 def notification_AllNodesQueried(nodeId, byte, value) # puts 'TODO' end |
#notification_AwakeNodesQueried(nodeId, byte, value) ⇒ Object
All awake nodes have been queried, so client application can expected complete data for these nodes.
370 371 372 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 370 def notification_AwakeNodesQueried(nodeId, byte, value) puts 'TODO' end |
#notification_DriverFailed(nodeId, byte, value) ⇒ Object
Driver failed to load */
329 330 331 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 329 def notification_DriverFailed(nodeId, byte, value) puts 'TODO' end |
#notification_DriverReady(nodeId, byte, value) ⇒ Object
A driver for a PC Z-Wave controller has been added and is ready to use. The notification will contain the controller’s Home ID, which is needed to call most of the Manager methods.
324 325 326 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 324 def notification_DriverReady(nodeId, byte, value) puts 'TODO' end |
#notification_DriverReset(nodeId, byte, value) ⇒ Object
All nodes and values for this driver have been removed.
This is sent instead of potentially hundreds of individual node and value notifications.
336 337 338 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 336 def notification_DriverReset(nodeId, byte, value) puts 'TODO' end |
#notification_EssentialNodeQueriesComplete(nodeId, byte, value) ⇒ Object
The queries on a node that are essential to its operation have been completed. The node can now handle incoming messages.
347 348 349 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 347 def notification_EssentialNodeQueriesComplete(nodeId, byte, value) #OpenZWave::RefreshedNodes[nodeId] = true end |
#notification_Group(nodeId, byte, value) ⇒ Object
The associations for the node have changed. The application should rebuild any group information it holds about the node.
265 266 267 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 265 def notification_Group(nodeId, byte, value) puts 'TODO' end |
#notification_MsgComplete(nodeId, byte, value) ⇒ Object
The last message that was sent is now complete.
341 342 343 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 341 def notification_MsgComplete(nodeId, byte, value) puts 'TODO' end |
#notification_NodeAdded(nodeId, byte, value) ⇒ Object
A new node has been added to OpenZWave’s list. This may be due to a device being added to the Z-Wave network, or because the application is initializing itself.
277 278 279 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 277 def notification_NodeAdded(nodeId, byte, value) puts 'TODO' end |
#notification_NodeEvent(nodeId, byte, value) ⇒ Object
A node has triggered an event. This is commonly caused when a node sends a Basic_Set command to the controller. The event value is stored in the notification.
305 306 307 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 305 def notification_NodeEvent(nodeId, byte, value) puts 'TODO' end |
#notification_NodeNaming(nodeId, byte, value) ⇒ Object
One of the node names has changed (name, manufacturer, product).
298 299 300 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 298 def notification_NodeNaming(nodeId, byte, value) puts 'TODO' end |
#notification_NodeNew(nodeId, byte, value) ⇒ Object
A new node has been found (not already stored in zwcfg*.xml file)
270 271 272 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 270 def notification_NodeNew(nodeId, byte, value) puts 'TODO' end |
#notification_NodeProtocolInfo(nodeId, byte, value) ⇒ Object
Basic node information has been receievd, such as whether the node is a listening device, a routing device and its baud rate and basic, generic and specific types. It is after this notification that you can call Manager::GetNodeType to obtain a label containing the device description. */
293 294 295 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 293 def notification_NodeProtocolInfo(nodeId, byte, value) puts 'TODO' end |
#notification_NodeQueriesComplete(nodeId, byte, value) ⇒ Object
All the initialisation queries on a node have been completed.
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 352 def notification_NodeQueriesComplete(nodeId, byte, value) # node monitor phase 2: =begin @ValueMonitorMutex.synchronize do sleep(2) AnsibleValue[:_nodeId => nodeId].each { |val| val.get() } # all values now should be fresh @ValueMonitors[nodeId] = false fire_callback(:onMonitorStop) puts "==> trigger change monitor ENDED<==" end =end end |
#notification_NodeRemoved(nodeId, byte, value) ⇒ Object
A node has been removed from OpenZWave’s list. This may be due to a device being removed from the Z-Wave network, or because the application is closing.
284 285 286 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 284 def notification_NodeRemoved(nodeId, byte, value) puts 'TODO' end |
#notification_PollingDisabled(nodeId, byte, value) ⇒ Object
Polling of a node has been successfully turned off by a call to Manager::DisablePoll
311 312 313 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 311 def notification_PollingDisabled(nodeId, byte, value) puts 'TODO' end |
#notification_PollingEnabled(nodeId, byte, value) ⇒ Object
Polling of a node has been successfully turned on by a call to Manager::EnablePoll
317 318 319 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 317 def notification_PollingEnabled(nodeId, byte, value) puts 'TODO' end |
#notification_ValueAdded(nodeId, byte, value) ⇒ Object
a value has been added to the Z-Wave network
234 235 236 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 234 def notification_ValueAdded(nodeId, byte, value) #@@Values[homeID].push(value) end |
#notification_ValueChanged(nodeId, byte, value) ⇒ Object
A node value has been updated from the Z-Wave network.
245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 245 def notification_ValueChanged(nodeId, byte, value) # OpenZWave peculiarity: we got a ValueChanged event, but the value # reported by OpenZWave is unchanged. Thus we need to poll the # device using :RequestNodeDynamic, wait for NodeQueriesComplete # then re-get the value #trigger_value_monitor(value) # # as of r471 ValueChanged behaves correctly AnsibleValue[:_nodeId => nodeId, :_gerne => 1].each { |v| v.get } end |
#notification_ValueRefreshed(nodeId, byte, value) ⇒ Object
A node value has been refreshed from the Z-Wave network.
259 260 261 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 259 def notification_ValueRefreshed(nodeId, byte, value) #value.get unless value.nil? end |
#notification_ValueRemoved(nodeId, byte, value) ⇒ Object
a value has been removed from the Z-Wave network
239 240 241 242 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 239 def notification_ValueRemoved(nodeId, byte, value) # A node value has been removed from OpenZWave's list. This only occurs when a node is removed. #@@Values[homeID].delete(value) end |
#run ⇒ Object
transceiver main loop, runs in its own Ruby thread
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 171 def run # 1) subscribe to zwave's notification channel stomp.subscribe '/queue/zwave/monitor' do |msg| # Invoked every time the broker delivers a MESSAGE frame for the # SUBSCRIBE frame generated by this method call. puts "\n------ ZWAVE MESSAGE (#{Time.now}) ------" if $DEBUG begin value = nil # lookup or create ValueID related to Notification if msg.headers["HomeID"] and msg.headers["ValueID"] then homeID = msg.headers["HomeID"] valueID = msg.headers["ValueID"] # sync current HomeID h = homeID.to_i(16) unless Ansible::ZWave.const_defined?(:HomeID) then if h > 0 then puts "------ SETTING HOME ID: #{homeID}" Ansible::ZWave.const_set("HomeID", h) end end # get or create ValueID object value = Ansible::ZWave::ValueID.get_or_create(homeID, valueID) end # bind other notification parameters if msg.headers["NotificationType"] then node = msg.headers["NotificationNodeId"].to_i(16) byte = msg.headers["NotificationByte"].to_i(16) notif_type = msg.headers["NotificationType"].to_i(16) name, desc = OpenZWave::NotificationTypes[notif_type] # dynamic notification handler dispatch mechanism if md = /Type_(.*)/.match(name) then handler = "notification_" + md[1] puts "#{handler} (n:#{node}) (b:#{byte}) (#{value})" __send__(handler, node, byte, value) if respond_to?(handler) # fire all notification-related callbacks for the value, if any # e.g. onValueChanged, onValueRefreshed etc. if value.is_a?AnsibleValue then value.fire_callback("on#{md[1]}".to_sym) end end end # controller state change notification mechanism if ctrl_state = msg.headers["ControllerState"] then controller_state(ctrl_state.to_i(16)) end rescue Exception => e puts "ZWaveTransceiver::decode_monitor() exception: #{e}" puts "\t"+e.backtrace[0..3].join("\n\t") end end # do subscribe # 2) Sleep forever (how pretty) while true #@alive #FIXME sleep(1) end end |
#stomp ⇒ Object
get handle to stomp server, connect unless already connected caller must unlock @stompMutex when done with stomp
94 95 96 |
# File 'lib/ansible/zwave/zwave_transceiver.rb', line 94 def stomp @stomp_ok ? @stompserver : init_stomp() end |