Fibaro HTTPClient Class

To query a remote server you can use the HTTPClient class to build a connection to the remote server, send your request and receive the response. In the case of web services this response is likely a json string that can be converted to a lua table using the json.decode() function.

To create an instance of the HTTPClient class use:

instance_variable = net.HTTPClient( { timeout = value_in_ms } )

To query a remote site use the request method on the created instance:

instance_variable:request( url, options, success, error )

Where success and error are typically functions for processing successful query of the remote URL or not. Example:

--[[
       Example send of UPnP Play action to a Sonos speaker at 10.0.1.8
       You can use UPnP Tools' Device Spy to create other actions. 
--]]
   
   local ipAddr = '10.0.1.8';
   local upnpAction = 'Play';
   local upnpService = 'AVTransport';
   local upnpRqData  = '<Speed>1</Speed>';

   local reqBody = '<?xml version="1.0" encoding="utf-8"?>'
         ..'<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'
               ..' xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">'
         ..'<s:Body>'
            ..'<u:'..upnpAction..' xmlns:u="urn:schemas-upnp-org:service:'
			   ..upnpService..':1">'
               ..'<InstanceID>0</InstanceID>'
               ..upnpRqData
            ..'</u:'..upnpAction..'>'
         ..'</s:Body>'
         ..'</s:Envelope>';

   local tgtURL = 'http://'..ipAddr..':1400/MediaRenderer/'..upnpService..'/Control'

function httpResp(response)
   if (response.status == 200) then
      fibaro:debug("success: "..response.data);
   else
      fibaro:debug("Request rejected: " .. response.status);
      fibaro:debug(" reported error: " .. response.data);
   end
end;

function httpError(error)
   fibaro:debug('ERROR: '..error)
end;

   local selfhttp = net.HTTPClient({timeout=2000})
   selfhttp:request( tgtURL, 
   {
      success = httpResp,
      error = httpError,
      options = 
      {  
         method = 'POST',
         data = reqBody,
         headers = 
         {
            ['SOAPACTION'] = '"urn:schemas-upnp-org:service:'
			   ..upnpService..':1#'..upnpAction..'"',
            ['Content-Type'] = 'text/xml; charset="utf-8"',
         },
         timeout = 5000
      }
   });

Notes:

  1. The success function is called if a response is returned by the server. The status property will indicate whether the server was able to process the request correctly. The error function is called if the HC cannot process the request or no response is returned within the timeout period.
  2. The Lua table returned to the success function includes:
  3. The headers parameter requires only http headers that cannot be implied e.g. HOST: and Content-Length will be calculated by the HTTPClient request method.
  4. The success and error functions are scheduled asynchronously when the request completes. Once the http client has scheduled your request control is returned to the next instruction. If the scene completes it is paused by the system until a response is received and the success or error functions are scheduled. This makes the http client difficult to manage especially for multiple requests, one way to circumvent this difficulty is to place the http client code in a scene of its own.

The scene below interfaces with the pushover service to broadcast alerts to registered users (see https://pushover.net for details of the pushover service).

if (fibaro:args()) then
      local msgTxt = fibaro:args()[1];
      if ( string.find(msgTxt, '&message=') == nil) then
         msgTxt = '&priority=0'
               .. '&sound=spacealarm'
               .. '&title=Message from Fibaro HC2'
               .. '&message='..msgTxt;
      else
         if ( string.find(msgTxt, '&title=') == nil) then
            msgTxt = '&title=Message from Fibaro HC2'..msgTxt;
         end;
         
         if ( string.find(msgTxt, '&priority=') == nil) then
            msgTxt = '&priority=0'..msgTxt;
         elseif ( string.find(msgTxt, '&priority=2') ~= nil) then
            if ( string.find(msgTxt, '&expire=') == nil) then
               msgTxt = '&expire=10800'..msgTxt;
            end;
            if ( string.find(msgTxt, '&retry=') == nil) then
               msgTxt = '&retry=60'..msgTxt;
            end;
            if ( string.find(msgTxt, '&sound=') == nil) then
               msgTxt = '&sound=persistent'..msgTxt;
            end;
         end;
         if ( string.find(msgTxt, '&sound=') == nil) then
            msgTxt = '&sound=spacealarm'..msgTxt;
         end;
      end;
      
      msgTxt = 'token=_pushover_token_goes_here_'
            .. '&user=_pushover_user_id_goes_here_'
            .. msgTxt;
      
      local selfhttp = net.HTTPClient({timeout=2000})
      selfhttp:request('https://api.pushover.net/1/messages.json', {
         options = { headers = selfhttp.controlHeaders,
            data = msgTxt,
            method = 'POST',
            timeout = 5000
           },

         success = function(response)
            if (response.status) == 200 then
               local result = json.decode(response.data);
               -- {"status":1, "request":"request_id", "receipt":"receipt_token(pri2 only)"}
               if result.status == 1 then
                  fibaro:debug("Successful, Request id: " ..result.request);
               else
                  fibaro:debug("Unexpected response:" ..response.data);
               end
            else
               fibaro:debug("Request rejected: " .. response.status);
               fibaro:debug(" reported error: " .. response.data);
            end
         end,

         error = function(error)
            fibaro:debug('ERROR: '..error)
         end
      })

The id of the above scene has been saved as Fibaro global variable scnPushover. Any other scene can now send an alert to pushover users as follows:

   local msg = '&title=TimeOfDay set to: Evening'
         .. '&message=Living room lights have been turned on as a result of Fibaro'
         .. ' HC2 recognising that it is evening'
   fibaro:startScene(fibaro:getGlobalValue("scnPushover"), {msg});

 

Domotica Home
Contents