Telegram messenger

Send and receive messages using LM and Telegram #

Task #

You need to send text, image from LogicMachine to Telegram or receive text from Telegram to LogicMachine.

Send text #

  1. Install Telegram app

  2. Find BotFather or go here https://t.me/botfather

  3. Once in BotFather type /newbot and follow instructions. As a result you will get your token and your own bot link like t.me/yourname_bot . Click on the link and type any message there.

  4. Open browser (preferably Firefox as it converts JSON automatically) and go here https://api.telegram.org/bot<token>/getUpdates Replace <token> with your token. As a result you should have something like that. Save your chat ID.

telegram img_01

  1. Create a user library called telegram. Paste this code and replace your token and chat ID.
require('ssl.https')

local token = 'token' -- your token
local chat_id = '1234567' -- your chat id

function telegram(message)
  local url = 'https://api.telegram.org/bot' .. token .. '/sendMessage'
  local data = 'chat_id=' .. chat_id .. '&text=' .. socket.url.escape(message)
  return ssl.https.request(url, data)
end
  1. Create an event based script and use this code to send message to Telegram app:
require("user.telegram")
message = 'test message'
res, err = telegram(message)
log(res, err)

Send image #

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

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))

Receive text #

How to send messages from the Telegram app to LogicMachine.

  1. Follow instruction in first post how to create bot and your TOKEN

  2. Create a user library named tgupdates and paste this code:

return function(token, callback)
  local json = require('json')
  local socket = require('socket')
  local ssl = require('ssl')
  local host = 'api.telegram.org'
  local tgupdateid = storage.get('tg_update_id')

  local uri = '/bot' .. token .. '/getUpdates'

  local sock = socket.tcp()
  sock:settimeout(5)

  local res, err = sock:connect(host, 443)

  if not res then
    sock:close()
    log('connect failed', err)
    os.sleep(5)
    return
  end

  sock = ssl.wrap(sock, { mode = 'client' })
  sock:settimeout(60)
  sock:sni(host)
  res, err = sock:dohandshake()

  if not res then
    sock:close()
    log('dohandshake failed', err)
    os.sleep(5)
    return
  end

  local function sendreq()
    local args = 'timeout=50'
    local crlf = '\r\n'

    if tgupdateid then
      args = args .. '&offset=' .. tgupdateid
    end

    sock:send(
      'POST ' .. uri .. ' HTTP/1.1' .. crlf ..
      'Host: ' .. host .. crlf ..
      'Content-Type: application/x-www-form-urlencoded' .. crlf ..
      'Content-Length: ' .. #args .. crlf .. crlf ..
      args
    )
  end

  local function parse(resp)
    resp = json.pdecode(resp)

    if type(resp) ~= 'table' or not resp.ok then
      log('invalid response', resp)
    end

    local update_id = 0

    for _, item in ipairs(resp.result) do
      update_id = math.max(update_id, item.update_id)

      local message = item.message
      local text = message.text
      local userid = message.from.id
      local username = message.from.first_name

      callback(text, userid, username)
    end

    if update_id > 0 then
      tgupdateid = update_id + 1
      storage.set('tg_update_id', update_id + 1)
    end
  end

  sendreq()
  local pat, len = nil, nil

  while true do
    res, err = sock:receive(pat)

    if err then
      sock:close()
      log('receive error', err)
      break
    end

    if type(pat) == 'number' then
      pcall(parse, res)
      sendreq()

      pat, len = nil, nil
    elseif #res == 0 then
      pat = len
    elseif not len then
      len = res:match('Content%-Length: (%d+)')
      len = tonumber(len)
    end
  end
end
  1. Create a resident script with 0 interval and use this code. Change TOKEN. Write to your chat in telegram and your message will be in logs.
function callback(text, userid, username)
  log(text, userid, username)
end

token = 'YOUR TOKEN HERE'
require('user.tgupdates')(token, callback)

Modify the function to run your actions based on revived text. UserID is a unique number which can be used for authorization/restrictions. username is not unique as it is just a name in your Telegram account. It can be duplicated.