Dropbox webcam uploader not running more than once

I have developed a plugin to upload webcam images to dropbox. I want it to run repeatedly at a user defined interval, which I am trying to do with running it, then when it has run, calling it again with luup.call_delay. It successfully goes through the first time, but the second time it bombs out part way through, and the log indicates a potential leak.

Here’s the code. The lug_startup function is the startup function for the device. Does anyone know why it won’t run more than the first time?

[code] local http=require(“socket.http”)
local https = require (“ssl.https”)
local lfs = require(“lfs”)
local consumer_key = “…”
local consumer_secret = “…”
local access_token=“”
local access_token_secret=“”

function send_all_images_to_dropbox(lul_data)
luup.log("sending images to Dropbox "…lul_data)

for k,v in pairs(luup.devices) do
                           
    if( v.category_num==6) then -- Camera
      send_image_to_dropbox(lul_data,k)
    end
end

end

function send_image_to_dropbox(dropbox,webcam)

luup.log("sending device "..webcam.." images to Dropbox "..dropbox)

access_token=luup.variable_get("S_DropboxSettings1.xml","AccessToken",dropbox)
access_token_secret=luup.variable_get("S_DropboxSettings1.xml","AccessTokenSecret",dropbox)

if(access_token and access_token_secret) then

local downloadUrl=“http://”…luup.devices[webcam].ip…luup.variable_get(“urn:micasaverde-com:serviceId:Camera1”,“URL”,webcam)
if(luup.devices[webcam].user and luup.devices[webcam].pass) then
if(luup.devices[webcam].user ~=“” and luup.devices[webcam].pass ~=“”) then
downloadUrl=“http://”…luup.devices[webcam].user…“:”…luup.devices[webcam].pass…“@”…luup.devices[webcam].ip…luup.variable_get(“urn:micasaverde-com:serviceId:Camera1”,“URL”,webcam)
end
end

local tempfile = ltn12.sink.file(io.open('/tmp/tempimage.jpg', 'wb'))
http.request {
  url = downloadUrl;
  sink = tempfile;
} 

local now=os.time() 
local filename=luup.devices[webcam].description..os.date("_%d_%m_%Y_%H_%M_%S",now)..".jpg"
local foldername=os.date("%d_%m_%Y",now)
local dropboxUrl = "https://api-content.dropbox.com/1/files_put/sandbox/"..foldername.."/"..filename
local nonce=now 
local post_headers =  "realm=\""..dropboxUrl.."\", oauth_timestamp=\""..now.."\", oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""..consumer_key.."\", oauth_token=\""..access_token.."\", oauth_signature=\""..consumer_secret.."%26"..access_token_secret.."\", oauth_nonce=\""..nonce.."\""
local filesize = lfs.attributes ('/tmp/tempimage.jpg', "size")

https.request
{
  url = dropboxUrl;
  method = "PUT";
  headers = 
  {
["Content-Length"] = filesize ;
["Content-Type"] = "text/plain";
["Authorization"] = "OAuth "..post_headers;
  };
  source = ltn12.source.file(io.open("/tmp/tempimage.jpg"));
 }
 luup.log("Dropbox file for webcam "..webcam.." sent")

 os.remove('/tmp/tempimage.jpg')
 
 end

end

 function sendImagesLoop(lul_data)
 
   send_all_images_to_dropbox(lul_data)
   local update_frequency=luup.variable_get("S_DropboxSettings1.xml","SendFrequency",lul_data) or 10
   update_frequency=update_frequency*60
   luup.log("Dropbox update frequency= "..update_frequency)
   luup.call_delay('sendImagesLoop',update_frequency,lul_data,true)
 end   

function lug_startup(lul_device)
sendImagesLoop(lul_device)
end[/code]

Thanks

Martin

Without seeing the log it’s hard to debug a hundred lines of someone else’s code. But here goes…

The first time through your code, the device variable is a Lua number. The second time through it will be a Lua string. Go and read the docs for luup.call_delay() and make a careful note of what type the parameters are. You will need to call tonumber() in one or two places.

While I’m here, some unsolicited advice: Using a timestamp for an OAuth nonce is a terrible idea. OAuth security relies on the nonce being unguessable. Build a string with a properly-seeded random number generator.

Thanks futzle. That was indeed the issue - it was converting the number to a string. It all works great now I have made that change.

You are right about the nonce too - it was originally a random number, but I changed it to a date as part of the debugging. I’ll put it back as a random number before release.

Martin

Martin12345
can you share the code ?
maybe this is a solution for that one without cash to pay for a NVR system.

thanks !

Piwtorak, don’t worry, I’ll be releasing it as a free plugin once dropbox approve the app for production use, so that everyone can make use of it.

Martin

Ok. Thanks.

Dropbox approved it, so now it’s just waiting for MCV to review the plugin, and then everyone will be able to make use of it.

Martin

Simply great!
I want to use it ! Waiting for the plug in…

Do you thing that is possible to trigger the storage of image based on motion sensor?

Thank you
Matteo

Yes, that’ll be possible - you can add a scene which triggers when a motion sensor triggers, and have the scene send a picture of one or all webcams to dropbox. Here are the instructions;

http://www.milliesoft.co.uk/index.php/other-articles/104-dropbox-webcam-uploader

Martin

I hope MCV be fast with this… great plugin…

in example of another plugins like sonos we can install by ourselves if you send instructions and files.

thanks !

The plugin is approved now, so I started a new thread here for comments and questions;

http://forum.micasaverde.com/index.php/topic,16518.0.html

Martin

For anyone who’s interested, here’s the final code;

[code]<?xml version="1.0"?>

local http=require("socket.http")
local https = require ("ssl.https")
local lfs = require("lfs")
local consumer_key = "....."
local consumer_secret = "....."
local access_token=""
local access_token_secret=""

function send_all_images_to_dropbox(lul_data)
local dropbox = tonumber(lul_data)
luup.log("sending all cameras to Dropbox "…dropbox)

for k,v in pairs(luup.devices) do
                           
    if( v.category_num==6) then -- Camera
      send_image_to_dropbox(dropbox,k)
    end
end

end

function send_image_to_dropbox(dropboxIn,webcamIn)

local dropbox = tonumber(dropboxIn)
local webcam = tonumber (webcamIn)

access_token=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","AccessToken",dropbox)
access_token_secret=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","AccessTokenSecret",dropbox)

if(access_token and access_token_secret) then
  if(access_token~="" and access_token_secret~="") then
luup.log("sending device "..webcam.." images to Dropbox "..dropbox)

local downloadUrl=“http://”…luup.devices[webcam].ip…luup.variable_get(“urn:micasaverde-com:serviceId:Camera1”,“URL”,webcam)
if(luup.devices[webcam].user and luup.devices[webcam].pass) then
if(luup.devices[webcam].user ~=“” and luup.devices[webcam].pass ~=“”) then
downloadUrl=“http://”…luup.devices[webcam].user…“:”…luup.devices[webcam].pass…“@”…luup.devices[webcam].ip…luup.variable_get(“urn:micasaverde-com:serviceId:Camera1”,“URL”,webcam)
end
end

local tempfile = ltn12.sink.file(io.open('/tmp/tempimage.jpg', 'wb'))
http.request {
  url = downloadUrl;
  sink = tempfile;
} 

local now=os.time() 
local filename=luup.devices[webcam].description..os.date("_%Y_%m_%d_%H_%M_%S",now)..".jpg"
local foldername=os.date("%Y_%m_%d",now)
local dropboxUrl = "https://api-content.dropbox.com/1/files_put/sandbox/"..foldername.."/"..filename
math.randomseed( os.time() )
local nonce=math.random(99999999) 
local post_headers =  "realm=\""..dropboxUrl.."\", oauth_timestamp=\""..now.."\", oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""..consumer_key.."\", oauth_token=\""..access_token.."\", oauth_signature=\""..consumer_secret.."%26"..access_token_secret.."\", oauth_nonce=\""..nonce.."\""
local filesize = lfs.attributes ('/tmp/tempimage.jpg', "size")

local response_body = { }
local res, code, response_headers =https.request
{
  url = dropboxUrl;
  method = "PUT";
  headers = 
  {
["Content-Length"] = filesize ;
["Content-Type"] = "text/plain";
["Authorization"] = "OAuth "..post_headers;
  };
  source = ltn12.source.file(io.open("/tmp/tempimage.jpg"));
  sink = ltn12.sink.table(response_body);
 }
 --luup.log("Status:".. res and "OK" or "FAILED")
 --luup.log("HTTP code:".. code)
 --luup.log("Response headers:")
 --if type(response_headers) == "table" then
 --  for k, v in pairs(response_headers) do
 --    luup.log(k.. ":".. v)
 --  end
 --end
 --luup.log("Response body:")
 --if type(response_body) == "table" then
 --  luup.log(table.concat(response_body))
 --end

 if(code==200) then
   luup.log("Dropbox file for webcam "..webcam.." sent successfully")
 else
   luup.log("Dropbox file for webcam "..webcam.." failed")
   if type(response_body) == "table" then
     luup.log(table.concat(response_body))
   end
 end
 

 os.remove('/tmp/tempimage.jpg')
 
 end

end
end

function removeOldFiles(dropboxIn)

local json=require("dropbox_json_parser")
local dropbox = tonumber(dropboxIn)

access_token=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","AccessToken",dropbox)
access_token_secret=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","AccessTokenSecret",dropbox)
local daysToKeep=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","DaysToKeep",dropbox) or 14
local secondsToKeep=daysToKeep*86400

if(access_token and access_token_secret) then
  if(access_token~="" and access_token_secret~="") then
  local now=os.time() 
  local dropboxUrl = "https://api.dropbox.com/1/metadata/sandbox/"
  math.randomseed( os.time() )
  local nonce=math.random(99999999) 
  local post_headers =  "realm=\""..dropboxUrl.."\", oauth_timestamp=\""..now.."\", oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""..consumer_key.."\", oauth_token=\""..access_token.."\", oauth_signature=\""..consumer_secret.."%26"..access_token_secret.."\", oauth_nonce=\""..nonce.."\""

local response_body = { }
  local res, code, response_headers =https.request
  {
    url = dropboxUrl;
    method = "GET";
    headers = 
    {
["Content-Type"] = "text/plain";
["Authorization"] = "OAuth "..post_headers;
    };
    sink = ltn12.sink.table(response_body);       
  }
  if type(response_body) == "table" then
    local dir_list=json.decode(table.concat(response_body))
    
    local dir_contents=dir_list["contents"]
    local pattern = "(%d+)_(%d+)_(%d+)"

    for i,content in ipairs(dir_contents) do
      if(content["is_dir"]) then
        folderName=string.sub(content["path"],2)
        year,month,day=folderName:match(pattern)
        if(year) then
          folderDay=os.time({day=day,month=month,year=year,hour=0,min=0,sec=0})
          if(folderDay) then
            luup.log(folderDay)
            if((os.time()-folderDay)>secondsToKeep) then
            
            
                  now=os.time() 
	      dropboxUrl = "https://api.dropbox.com/1/fileops/delete?root=sandbox\038path="..folderName
	      math.randomseed( os.time() )
	      nonce=math.random(99999999) 
	      post_headers =  "realm=\""..dropboxUrl.."\", oauth_timestamp=\""..now.."\", oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""..consumer_key.."\", oauth_token=\""..access_token.."\", oauth_signature=\""..consumer_secret.."%26"..access_token_secret.."\", oauth_nonce=\""..nonce.."\""
	  
	      response_body = { }
	      res, code, response_headers =https.request
	      {
	        url = dropboxUrl;
	        method = "POST";
	        headers = 
	        {
	  	["Content-Type"] = "text/plain";
	  	["Authorization"] = "OAuth "..post_headers;
	        };
	        sink = ltn12.sink.table(response_body);       
	      }

            end
            
          end                     
        end
       end
      end
    end
  end
  luup.log("Done cleaning up")

   
 end

end

 function removeOldFilesLoop(lul_data)     
   removeOldFiles(lul_data)
   local dropboxNumber=tonumber(lul_data)
   luup.call_delay('removeOldFilesLoop',86400,dropboxNumber,true)
 end   

 function sendImagesLoop(lul_data)
 
   send_all_images_to_dropbox(lul_data)
   local update_frequency=luup.variable_get("S_WebcamDropboxUploaderSettings1.xml","SendFrequency",lul_data) or 10
   luup.log("Dropbox update frequency= "..update_frequency.." minutes")
   update_frequency=update_frequency*60
   local dropboxNumber=tonumber(lul_data)
   if(update_frequency>0) then
     luup.call_delay('sendImagesLoop',update_frequency,dropboxNumber,true)
   end
 end   

function lug_startup(lul_device)
sendImagesLoop(lul_device)
removeOldFilesLoop(lul_device)
end

lug_startup urn:milliesoft-com:serviceId:WebcamDropboxUploader1 SendAllSnapshots do send_all_images_to_dropbox(lul_device) return 4,30 end urn:milliesoft-com:serviceId:WebcamDropboxUploader1 SendSnapshot do local webcamNumber = tonumber(lul_settings.webcamNumber) send_image_to_dropbox(lul_device,webcamNumber) return 4,30 end [/code]