Logic Machine Forum
Send image form ip camera to telegram - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: Send image form ip camera to telegram (/showthread.php?tid=2792)



Send image form ip camera to telegram - peyoe - 13.08.2020

I have an IP camera working and I can view it trough my logic machine.
The next step I like to reach is to send the snapshot to my telegram.
I have already configured my telegram, I can send messages. But it's impossible to send a snapshot.
I have a DAHUA camera, and the url to view the snapshot is this:
Http: // user: password@cameraip/cgi-bin/snapshot.cgi
I can view it in chrome without problems.
I try to send it with "sendphoto" command and with the example from here, in this case send through email.
https://forum.logicmachine.net/showthread.php?tid=1061

I do not know what else to do. Can someone help me?
Thanks.


RE: Send image form ip camera to telegram - admin - 13.08.2020

First you need to retrieve the image using http request.
Then you can send the image using this example. filedata variable must contain image data as a string, change PUT_CHAT_ID_HERE and PUT_BOT_TOKEN_HERE placeholders
Code:
require('ssl.https')

boundary = os.date('%d%m%Y%H%M%S')
filedata = '...' -- snapshot image data as a string

params = {
  {
    name = 'chat_id',
    value = 'PUT_CHAT_ID_HERE',
  },
  {
    name = 'photo',
    filename = 'snapshot.jpg',
    ctype = 'image/jpeg',
    value = filedata,
  }
}

body = { '--' .. boundary }

for _, param in ipairs(params) do
  line = string.format('Content-Disposition: form-data; name=%q', param.name)
  if param.filename then
    line = string.format('%s; filename=%q', line, param.filename)
  end
  body[ #body + 1 ] = line

  if param.ctype then
    body[ #body + 1 ] = string.format('Content-Type: %s', param.ctype)
  end

  body[ #body + 1 ] = ''
  body[ #body + 1 ] = param.value
  body[ #body + 1 ] = '--' .. boundary
end

-- last boundary
body[ #body ] = body[ #body ] .. '--'
-- empty line at the end
body[ #body + 1 ] = ''

bodydata = table.concat(body, '\r\n')

resp = {}

log(
  ssl.https.request({
    url = 'https://api.telegram.org/PUT_BOT_TOKEN_HERE/sendPhoto',
    sink = ltn12.sink.table(resp),
    method = 'POST',
    source = ltn12.source.string(bodydata),
    headers = {
      ['content-length'] = #bodydata,
      ['content-type'] = 'multipart/form-data; boundary=' .. boundary
    }
  })
)

log(table.concat(resp))



RE: Send image form ip camera to telegram - peyoe - 13.08.2020

Thanks for the answer.
I put my url snapshot on "filedata" and my CHATID and BOT_TOKEN, but it doesn't work.
The log says:


* arg: 1
* number: 1
* arg: 2
* number: 400
* arg: 3
* table:
["server"]
* string: nginx/1.16.1
["access-control-expose-headers"]
* string: Content-Length,Content-Type,Date,Server,Connection
["content-type"]
* string: application/json
["connection"]
* string: close
["content-length"]
* string: 79
["date"]
* string: Thu, 13 Aug 2020 15:18:09 GMT
["strict-transport-security"]
* string: max-age=31536000; includeSubDomains; preload
["access-control-allow-origin"]
* string: *
* arg: 4
* string: HTTP/1.1 400 Bad Request


* string: {"ok":false,"error_code":400,"description":"Bad Request: IMAGE_PROCESS_FAILED"}


RE: Send image form ip camera to telegram - admin - 13.08.2020

As mentioned before first you need to retrieve the image from your camera via http request. You cannot pass a url to the snapshot here because telegram server cannot access your camera.


RE: Send image form ip camera to telegram - peyoe - 13.08.2020

Ok.
As you can see I'm a completely noob with LUA.
I will search info about that.

Thanks again.


RE: Send image form ip camera to telegram - peyoe - 14.08.2020

Hello.

I have tried to retrieve the image with no results.
I have used these examples:


https://forum.logicmachine.net/showthread.php?tid=1630&highlight=image+http+request

https://forum.logicmachine.net/showthread.php?tid=1061&pid=9364#pid9364

Can you explain me how I need to do this?
Thanks in advance.


RE: Send image form ip camera to telegram - admin - 14.08.2020

Log what you get when sending a request to the camera. Make sure that the URL is correct and it actually returns an image not a HTML page containing the image.
Code:
require('socket.http')
log(socket.http.request('http://user:password@cameraip/cgi-bin/snapshot.cgi'))



RE: Send image form ip camera to telegram - peyoe - 14.08.2020

(14.08.2020, 08:08)admin Wrote: Log what you get when sending a request to the camera. Make sure that the URL is correct and it actually returns an image not a HTML page containing the image.
Code:
require('socket.http')
log(socket.http.request('http://user:password@cameraip/cgi-bin/snapshot.cgi'))

Sure:

* arg: 1
  * string:
* arg: 2
  * number: 401
* arg: 3
  * table:
  ["content-length"]
    * string: 0
  ["www-authenticate"]
    * string: Digest realm="Login to 5L02EC8PAGC1BC0", qop="auth", nonce="762101674", opaque="e65481894c6ae41a2f1296db7e53d66882f66471"
  ["connection"]
    * string: close
* arg: 4
  * string: HTTP/1.1 401 Unauthorized



RE: Send image form ip camera to telegram - admin - 14.08.2020

This means that you need to use digest code example from here: https://forum.logicmachine.net/showthread.php?tid=1061&pid=9364#pid9364
log what you get from the request:
Code:
url = 'http://user:password@cameraip/cgi-bin/snapshot.cgi'
image, err, hdrs = request(url)
log(image, err, hdrs)



RE: Send image form ip camera to telegram - peyoe - 14.08.2020

(14.08.2020, 08:47)admin Wrote: This means that you need to use digest code example from here: https://forum.logicmachine.net/showthread.php?tid=1061&pid=9364#pid9364
log what you get from the request:
Code:
url = 'http://user:password@cameraip/cgi-bin/snapshot.cgi'
image, err, hdrs = request(url)
log(image, err, hdrs)

With the last code I have not had any records, instead that I had an error:

User script:21: attempt to call global 'request' (a nil value)
stack traceback:
User script:21: in main chunk



RE: Send image form ip camera to telegram - admin - 14.08.2020

You need to copy the whole code from here: https://forum.logicmachine.net/showthread.php?tid=1061&pid=9364#pid9364
And change the last lines as in my previous post.


RE: Send image form ip camera to telegram - peyoe - 14.08.2020

(14.08.2020, 08:53)admin Wrote: You need to copy the whole code from here: https://forum.logicmachine.net/showthread.php?tid=1061&pid=9364#pid9364
And change the last lines as in my previous post.

Ok, sorry. This is the log:

Code:
* arg: 1
  * string: ����



RE: Send image form ip camera to telegram - peyoe - 14.08.2020

EDIT
It's working, I have to put on filedata, the name without ' '.

Thanks admin.

This is my whole code:
Code:
local skthttp = require('socket.http')
local skturl = require('socket.url')
local ltn12 = require('ltn12')
local md5sum = require('encdec').md5

local hash = function(...)
  return md5sum(table.concat({...}, ':'))
end

local parse_header = function(header)
  local result = {}
  for key, value in (header .. ','):gmatch('(%w+)=(.-),') do
    if value:sub(1, 1) == '"' then -- strip quotes
      result[ key:lower() ] = value:sub(2, -2)
    else
      result[ key:lower() ] = value
    end
  end
  return result
end

local make_digest_header = function(headers)
  local digest = {}
  for _, header in ipairs(headers) do
    if not header.unquote then
      header[ 2 ] = '"' .. header[ 2 ] .. '"'
    end

    digest[ #digest + 1 ] = header[ 1 ] .. '=' .. header[ 2 ]
  end
  return 'Digest ' .. table.concat(digest, ', ')
end

local _request = function(req)
  if not req.url then
    return nil, 'missing url'
  end

  local url = skturl.parse(req.url)
  local user, password = url.user, url.password
  if not user or not password then
    return nil, 'missing credentials in url'
  end

  url.user, url.password, url.authority, url.userinfo = nil, nil, nil, nil
  req.url = skturl.build(url)
  local source
  if req.source then
    local chunks = {}
    local capture = function(chunk)
      if chunk then
        chunks[ #chunks + 1 ] = chunk
      end
      return chunk
    end
    local chunk_id = 0
    source = function()
      chunk_id = chunk_id + 1
      return chunks[ chunk_id ]
    end
    req.source = ltn12.source.chain(req.source, capture)
  end
  local body, code, hdrs = skthttp.request(req)
  if code == 401 and hdrs['www-authenticate'] then
    local ht = parse_header(hdrs['www-authenticate'])
    if not ht.realm or not ht.nonce then
      return nil, 'missing realm/nonce from response'
    end
    if ht.qop ~= 'auth' then
      return nil, 'unsupported qop ' .. tostring(ht.qop)
    end
    if ht.algorithm and ht.algorithm:lower() ~= 'md5' then
      return nil, 'unsupported algo ' .. tostring(ht.algorithm)
    end
    local nc = '00000001'
    local cnonce = string.format('%08x', os.time())
    local uri = skturl.build({ path = url.path, query = url.query })
    local method = req.method or 'GET'
    local response = hash(
      hash(user, ht.realm, password),
      ht.nonce,
      nc,
      cnonce,
      'auth',
      hash(method, uri)
    )
    req.headers = req.headers or {}
    local auth = {
      { 'username', user },
      { 'realm', ht.realm },
      { 'nonce', ht.nonce },
      { 'uri', uri },
      { 'cnonce', cnonce },
      { 'nc', nc, unquote = true },
      { 'qop', 'auth' },
      { 'algorithm', 'MD5' },
      { 'response', response },
    }
    if ht.opaque then
      table.insert(auth, { 'opaque', ht.opaque })
    end
    req.headers.authorization = make_digest_header(auth)
    if not req.headers.cookie and hdrs['set-cookie'] then
      -- not really correct but enough for httpbin
      local cookie = (hdrs['set-cookie'] .. ';'):match('(.-=.-)[;,]')
      if cookie then
        req.headers.cookie = '$Version: 0; ' .. cookie .. ';'
      end
    end
    if req.source then
      req.source = source
    end
    body, code, hdrs = skthttp.request(req)
  end

  return body, code, hdrs
end

local request = function(url)
  local t = type(url)
  if t == 'table' then
    return _request(table.clone(url))
  elseif t == 'string' then
    local req = {}
    local _, code, headers = _request({ url = url, sink = ltn12.sink.table(req) })
    return table.concat(req), code, headers
  end
end

url = 'http://USER:PASS@CAM IP/cgi-bin/snapshot.cgi?1&ts=123/snapshot.jpeg'
image, err, hdrs = request(url)
log(image, err, hdrs)


require('ssl.https')

boundary = os.date('%d%m%Y%H%M%S')
filedata = image -- snapshot image data as a string

params = {
  {
    name = 'chat_id',
    value = 'MY CHAT ID',
  },
  {
    name = 'photo',
    filename = 'snapshot.jpg',
    ctype = 'image/jpeg',
    value = filedata,
  }
}

body = { '--' .. boundary }

for _, param in ipairs(params) do
  line = string.format('Content-Disposition: form-data; name=%q', param.name)
  if param.filename then
    line = string.format('%s; filename=%q', line, param.filename)
  end
  body[ #body + 1 ] = line

  if param.ctype then
    body[ #body + 1 ] = string.format('Content-Type: %s', param.ctype)
  end

  body[ #body + 1 ] = ''
  body[ #body + 1 ] = param.value
  body[ #body + 1 ] = '--' .. boundary
end

-- last boundary
body[ #body ] = body[ #body ] .. '--'
-- empty line at the end
body[ #body + 1 ] = ''

bodydata = table.concat(body, '\r\n')

resp = {}

log(
  ssl.https.request({
    url = 'https://api.telegram.org/MY BOT/sendPhoto',
    sink = ltn12.sink.table(resp),
    method = 'POST',
    source = ltn12.source.string(bodydata),
    headers = {
      ['content-length'] = #bodydata,
      ['content-type'] = 'multipart/form-data; boundary=' .. boundary
    }
  })
)

log(table.concat(resp))



RE: Send image form ip camera to telegram - admin - 14.08.2020

This line is incorrect:
Code:
filedata = 'image'

It should be
Code:
filedata = image



RE: Send image form ip camera to telegram - peyoe - 14.08.2020

(14.08.2020, 11:08)admin Wrote: This line is incorrect:
Code:
filedata = 'image'

It should be
Code:
filedata = image

Yes, I just put it in my previous post. Thank you very much again.