Class: Frisky::SSDP
- Inherits:
-
Object
- Object
- Frisky::SSDP
- Includes:
- NetworkConstants, LogSwitch
- Defined in:
- lib/frisky/ssdp.rb,
lib/frisky/ssdp/error.rb,
lib/frisky/ssdp/network_constants.rb,
lib/frisky/ssdp/broadcast_searcher.rb,
lib/frisky/ssdp/multicast_connection.rb
Overview
This is the main class for doing SSDP stuff. You can have a look at child classes, but you’ll probably want to just use these methods here.
SSDP is “Simple Service Discovery Protocol”, which lets you find and learn about UPnP devices on your network. Of the six “steps” of UPnP (given in the UPnP spec–that’s counting step 0), SSDP is what provides step 1, or the “discovery” step.
Before you can do anything with any of the UPnP devices on your network, you need to search
your network to see what devices are available. Once you’ve found what’s available, you can then decide device(s) you’d like to control. After searching, you should then listen
to the activity on your network. New devices on your network may come online (via ssdp:alive
) and devices that you care about may go offline (via ssdp:byebye
), in which case you probably shouldn’t try to talk to them anymore.
Defined Under Namespace
Modules: NetworkConstants Classes: BroadcastSearcher, Error, Listener, MulticastConnection, Notifier, Searcher
Constant Summary
Constants included from NetworkConstants
NetworkConstants::BROADCAST_IP, NetworkConstants::MULTICAST_IP, NetworkConstants::MULTICAST_PORT, NetworkConstants::TTL
Class Method Summary collapse
-
.listen(ttl = TTL) ⇒ Hash<Array>, Frisky::SSDP::Listener
Opens a multicast UDP socket on 239.255.255.250:1900 and listens for alive and byebye notifications from devices.
- .notify(notification_type, usn, ddf_url, valid_for_duration = 1800) ⇒ Object
-
.search(search_target = :all, options = {}) ⇒ Array<Hash>, Frisky::SSDP::Searcher
Opens a UDP socket on 0.0.0.0, on an ephemeral port, has Frisky::SSDP::Searcher build and send the search request, then receives the responses.
- .send_notification(notification_type, usn, ddf_url, valid_for_duration) ⇒ Object
Class Method Details
.listen(ttl = TTL) ⇒ Hash<Array>, Frisky::SSDP::Listener
Opens a multicast UDP socket on 239.255.255.250:1900 and listens for alive and byebye notifications from devices.
46 47 48 49 50 51 52 53 54 55 56 57 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 |
# File 'lib/frisky/ssdp.rb', line 46 def self.listen(ttl=TTL) alive_notifications = Set.new byebye_notifications = Set.new listener = proc do l = EM.open_datagram_socket(MULTICAST_IP, MULTICAST_PORT, Frisky::SSDP::Listener, ttl) i = 0 EM.add_periodic_timer(5) { i += 5; Frisky.log "Listening for #{i}\n" } l end if EM.reactor_running? return listener.call else EM.synchrony do l = listener.call alive_getter = Proc.new do |notification| alive_notifications << notification EM.next_tick { l.alive_notifications.pop(&live_getter) } end l.alive_notifications.pop(&alive_getter) byebye_getter = Proc.new do |notification| byebye_notifications << notification EM.next_tick { l.byebye_notifications.pop(&byebye_getter) } end l.byebye_notifications.pop(&byebye_getter) trap_signals end end { alive_notifications: alive_notifications.to_a.flatten, byebye_notifications: byebye_notifications.to_a.flatten } end |
.notify(notification_type, usn, ddf_url, valid_for_duration = 1800) ⇒ Object
This is for Frisky::Devices, which aren’t implemented yet, and thus this may not be working.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/frisky/ssdp.rb', line 155 def self.notify(notification_type, usn, ddf_url, valid_for_duration=1800) responses = [] notification_type = notification_type.to_upnp_s EM.synchrony do s = send_notification(notification_type, usn, ddf_url, valid_for_duration) EM.add_shutdown_hook { responses = s.discovery_responses } EM.add_periodic_timer(valid_for_duration) do s = send_notification(notification_type, usn, ddf_url, valid_for_duration) end trap_signals end responses end |
.search(search_target = :all, options = {}) ⇒ Array<Hash>, Frisky::SSDP::Searcher
Opens a UDP socket on 0.0.0.0, on an ephemeral port, has Frisky::SSDP::Searcher build and send the search request, then receives the responses. The search will stop after response_wait_time
.
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/frisky/ssdp.rb', line 106 def self.search(search_target=:all, = {}) response_wait_time = [:response_wait_time] || 5 ttl = [:ttl] || TTL do_broadcast_search = [:do_broadcast_search] = .delete :do_broadcast_search responses = [] search_target = search_target.to_upnp_s multicast_searcher = proc do EM.open_datagram_socket('0.0.0.0', 0, Frisky::SSDP::Searcher, search_target, ) end broadcast_searcher = proc do EM.open_datagram_socket('0.0.0.0', 0, Frisky::SSDP::BroadcastSearcher, search_target, response_wait_time, ttl) end if EM.reactor_running? return multicast_searcher.call else EM.synchrony do ms = multicast_searcher.call ms.discovery_responses.subscribe do |notification| responses << notification end if do_broadcast_search bs = broadcast_searcher.call bs.discovery_responses.subscribe do |notification| responses << notification end end EM.add_timer(response_wait_time) { EM.stop } trap_signals end end responses.flatten end |
.send_notification(notification_type, usn, ddf_url, valid_for_duration) ⇒ Object
This is for Frisky::Devices, which aren’t implemented yet, and thus this may not be working.
175 176 177 178 |
# File 'lib/frisky/ssdp.rb', line 175 def self.send_notification(notification_type, usn, ddf_url, valid_for_duration) EM.open_datagram_socket('0.0.0.0', 0, Frisky::SSDP::Notifier, notification_type, usn, ddf_url, valid_for_duration) end |