Changes between Version 1 and Version 2 of develop


Ignore:
Timestamp:
2013-04-13 11:53:48 (12 years ago)
Author:
futzle
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • develop

    v1 v2  
    1515The MiOS LuaUPnP process cannot receive '''NOTIFY''' messages, so the plugin instead nominates the UPnP Event Proxy daemon as the callback URL.  The plugin must also inform the UPnP Event Proxy daemon of the SID, and which Luup action on the plugin to invoke when the event occurs. 
    1616 
     17== Setup code == 
     18 
     19The example code below assumes these variables: 
     20 
     21{{{ 
     22http = require("socket.http") 
     23ltn12 = require("ltn12") 
     24function socketWithTimeout(timeout) 
     25  local s = socket.tcp() 
     26  s:settimeout(timeout) 
     27  return s 
     28end 
     29}}} 
     30 
    1731== Registering a subscription with the proxy == 
    1832 
    19 TODO 
     33In this example, the plugin at MiOS deviceId ''deviceId'' is interested in knowing about changes to the UPnP variable ''UPnPVariable''. 
     34 
     35Sending the UPnP SUBSCRIBE request is outside the scope of this document.  For example code, see the Belkin WeMo plugin function [http://code.mios.com/trac/mios_belkin-wemo/browser/L_WeMo1.lua#L327 subscribeToDevice()].  The callback URL must be <http://''vera-address'':2529/upnp/event>. 
     36 
     37After the '''SUBSCRIBE''' request succeeds, the plugin will have a subscription identifier (SID) ''sid'', and a duration in seconds ''timeout''.  For the next ''timeout'' seconds, the UPnP device will send '''NOTIFY''' messages to the callback URL. 
     38 
     39The plugin has an action ''VariableChanged'' in service ''pluginServiceId'' which accepts two parameters: ''valueParam'' (the new value of the varable), and ''sidParam'' (the subscription identifier).  The plugin wants this action to be invoked by the proxy every time that ''UPnPVariable'' changes. 
     40 
     41To register the subscription with the proxy, perform an HTTP '''PUT''' to /upnp/event/''sid'': 
     42 
     43{{{ 
     44local proxyRequestBody = "<subscription expiry='" .. os.time() + timeout .. "'>" 
     45proxyRequestBody = proxyRequestBody .. 
     46  "<variable name='UPnPVariable' host='localhost' deviceId='" .. 
     47  deviceId .. "' serviceId='pluginServiceId' " .. 
     48  "action='VariableChanged' parameter='valueParam' sidParameter='sidParam'/>" 
     49proxyRequestBody = proxyRequestBody .. "</subscription>" 
     50local request, code = http.request({ 
     51  url = "http://localhost:2529/upnp/event/" .. url.escape(sid), 
     52  create = socketWithTimeout(2), 
     53  method = "PUT", 
     54  headers = { 
     55    ["Content-Type"] = "text/html", 
     56    ["Content-Length"] = proxyRequestBody:len(), 
     57  }, 
     58  source = ltn12.source.string(proxyRequestBody), 
     59  sink = ltn12.sink.null(), 
     60}) 
     61if (request == nil and code ~= "closed") then 
     62  -- Failed (timeout?) 
     63elseif (code ~= 200) then 
     64  -- Failed (refused) 
     65else 
     66  -- Succeeded 
     67end 
     68}}} 
     69 
     70The proxy will soon receive (or may have already received) the initial UPnP '''NOTIFY''' (with sequence 0), and will invoke the ''VariableChanged'' action on the plugin. 
    2071 
    2172== Receiving an event notification from the proxy == 
    2273 
    23 TODO 
     74The plugin should have an action ''VariableChanged'', matching the ''serviceId'' and ''action'' parameters supplied in the previous section's sample code.  In the 
     75 
     76{{{ 
     77<action> 
     78  <serviceId>pluginServiceId</serviceId> 
     79  <name>VariableChanged</name> 
     80  <run> 
     81    doSomethingWith(lul_device, lul_settings.valueParam, lul_settings.sidParam) 
     82  </run> 
     83</action> 
     84}}} 
     85 
     86The ''doSomethingWith'' function will be called with the value of ''UPnPVariable'' from each notification from the UPnP device, and the SID mentioned in the event.  Normally this function will set a Luup variable to reflect the reported change in the variable. 
    2487 
    2588== Renewing the subscription == 
    2689 
    27 TODO 
     90Before ''timeout'' seconds have passed, the plugin must renew the subscription with the UPnP device.  The code to do this is outside the scope of this document. 
     91 
     92If the renewal succeeds, a new timeout will be supplied by the UPnP device.  The plugin must inform the proxy of the new expiry, using code exactly the same as the initial registration.  This '''PUT''' request completely replaces the previous registration, so it must mention all variables again. 
    2893 
    2994== Cancelling the subscription == 
    3095 
    31 TODO 
     96In most cases, the plugin will want to keep renewing the subscription indefinitely.  If the plugin knows that a subscription should be cancelled, it can ask the proxy to stop forwarding the event to the plugin with an HTTP '''DELETE''': 
     97 
     98{{{ 
     99local request, code = http.request({ 
     100  url = "http://localhost:2529/upnp/event/" .. url.escape(sid), 
     101  create = socketWithTimeout(2), 
     102  method = "DELETE", 
     103  headers = { 
     104    ["Content-Length"] = 0, 
     105  }, 
     106  source = ltn12.source.empty(), 
     107  sink = ltn12.sink.null(), 
     108}) 
     109if (request == nil and code ~= "closed") then 
     110  -- Failed (timeout?) 
     111elseif (code ~= 200) then 
     112  -- Failed (refused) 
     113else 
     114  -- Succeeded 
     115end 
     116}}} 
     117 
     118If the Luup engine is restarted, the plugin will not have an opportunity to cancel a subscription, and the proxy will send events that were registered before the Luup engine was restarted.  The plugin can use the ''sidParam'' value to see if this has happened.  Eventually the subscription will expire and the plugin will stop receive notifications. 
    32119 
    33120== Avoiding deadlocks ==