강좌/RaspberryPI 활용

라즈베리파이 Telegram BOT 만들기 3부 - Telegram cli BOT 의 뼈대 만들기

acidpop 2015. 7. 16. 17:54
반응형

1부 - 라즈베리파이에 Telegram CLI 설치 (http://blog.acidpop.kr/183


2부 - Telegram cli 기초 사용법 (http://blog.acidpop.kr/184)



이번 3부에서는 Telegram CLI 를 BOT 으로 활용하기 위한 기초적은 뼈대를 만들어 보자.


Telegram BOT 이란?

사용자가 텔레그램 BOT 계정에게 어떤 특정한 단어를 전달하면 BOT 이 명령을 처리하여 사진을 찍어서 보낸다던지

라즈베리파이에 연결된 센서값을 읽어서 사용자에게 전송을 한다던지 하는 것을 의미한다.




Telegram CLI 는 스크립트 언어로 lua 와 python 을 지원한다.


바로 이 lua script 와 python script 를 이용해서 BOT 을 제작할 수 있다.



여기서는 lua script 를 이용해서 BOT을 제작한다.



첫번째로 가장 간단한 BOT을 만들어 보자.


먼저 lua script 를 저장하기 위한 디렉토리를 생성한다.


cd /home/pi/tg

mkdir bot

cd bot

mkdir shell

mkdir tmp




bot 디렉토리를 만드는 이유는 점차 커질 lua script 파일들을 관리 하기 위해서이다.

bot 디렉토리 안에서 shell 디렉토리와 tmp 디렉토리도 생성해두었다.


lua script 에서 처리 할 수 없는 명령의 경우에는 Shell script 를 실행하여 결과값을 가져오기 위함이며 실행되는 Shell script 를 모아놓을 경로이다.

tmp 디렉토리는 send_text 또는 카메라를 이용하여 사진을 찍을때 만들어지는 임시 파일들을 저장하기 위한 디렉토리이다.


여기까지 진행이 되었다면 lua 스크립트를 만들어 보자.

--[[
Smart Telegram bot Project (Basic Version)

    2015.07.16
-- by http://blog.acidpop.kr 
]]--


-- 인증된 사용자만 BOT을 이용하게 하기 위해 폰 번호를 배열로 등록해둔다.
auth_phone  = { ["821012341234"] = true, 
                ["821011112222"] = true,
                ["801098765432"] = true }

-- 만약 1개의 폰 번호만 등록하고 싶다면 다음과 같이 작성한다.
--[[
auth_phone  = { ["821012341234"] = true }
]]--


-- 로그인 한 ID를 저장하는 변수
our_id = 0


    -- msg 라는 변수에 어떤 값이 있는지 확인 하기 위해 변수 내부를 출력하는 함수이다.
function vardump(value, depth, key)
    local linePrefix = ""
    local spaces = ""

    if key ~= nil then
    linePrefix = "["..key.."] = "
    end

    if depth == nil then
    depth = 0
    else
    depth = depth + 1
    for i=1, depth do spaces = spaces .. "  " end
    end

    if type(value) == 'table' then
        mTable = getmetatable(value)
    if mTable == nil then
        print(spaces ..linePrefix.."(table) ")
    else
        print(spaces .."(metatable) ")
        value = mTable
    end
    for tableKey, tableValue in pairs(value) do
        vardump(tableValue, depth, tableKey)
    end
    elseif type(value) == 'function' or 
        type(value) == 'thread' or 
        type(value) == 'userdata' or
        value == nil
    then
        print(spaces..tostring(value))
    else
        print(spaces..linePrefix.."("..type(value)..") "..tostring(value))
    end
end


    -- 수신 받은 메시지 중 특정 단어에 대해 처리 하는 함수들
function Hello(user_id)
    send_msg(user_id, '"안녕" 명령어를 입력하셨습니다', ok_cb, false)
end

function GetWether(user_id, arg)
    send_msg(user_id, '"날씨" 명령어를 입력하셨습니다', ok_cb, false)
end


function SendHelp(user_id)
    -- /home/pi/tg/bot 경로에 help.txt 파일이 있어야 한다.
    send_text(user_id, '/home/pi/tg/bot/help.txt', ok_cb, false)
end


    -- cmd 의 문자열을 비교 하여 각각 함수를 호출 하는 기능을 한다.
    -- 앞으로 BOT 명령어는 이곳에 추가한다.
function msg_processing(user_id, cmd, arg)
    -- Camera still
    if     ( cmd == '안녕' )        then    Hello(user_id)
    elseif ( cmd == '날씨' )        then    GetWether(user_id, arg)
    elseif ( cmd == 'help' )    then    SendHelp(user_id)
    -- else 해당 되지 않는 명령은 무시한다
    end
end

    -- 메시지 수신 처리 하는 함수
    -- 메시지가 수신 되면 이 함수가 호출되어진다
function on_msg_receive (msg)
    -- msg 변수에 있는 모든 항목을 출력
    vardump(msg)

    -- 자신이 보낸 메시지라면 return
    -- 자신의 계정으로만 사용중이라면 if <--> end 부분을 주석 처리
    if msg.out then
        print("-- : ", msg.out, "\n")
        return
    end

    -- auth (지정한 폰번호만 인증)
    if auth_phone[msg.from.phone] then
        print "auth    : OK "
    else
        print "auth    : invalid user"
        return
    end

    -- 수신 받은 메시지를 띄어쓰기를 기준으로 Command 와 Argument로 나눈다.
    -- ex : search arg1 text 123 => cmd = "search", arg = "arg1 text 123"
    local cmd, arg  = split(msg.text)

    -- command 가 영문일 경우 모두 소문자로 변환
    cmd = string.lower(cmd)
    print("receive  : [", cmd, "]\n")
    print("argument : [", arg, "]\n")

    -- 사용자 정보를 print 한다.
    print("Name     : ", msg.from.print_name)   -- 메시지 보낸사람 real name (Jinho)
    print("Phone    : ", msg.from.phone)            -- 메시지 보낸사람 전화번호  (8210AAAABBBB)
    print("Msg Num  : ", msg.id)                    -- 메시지 번호
    print("to.Name  : ", msg.to.print_name)

    -- 메시지를 전송할 대상을 구분하기 위한 기능.
    -- msg 를 보낸 ID와 로그인한 ID가 동일하다면 BOT에서 사용자에게 보낸 메시지이므로 from을 user_id로 설정
    -- msg 를 보낸 ID와 로그인 ID가 다르다면 BOT이 메시지를 수신 받은 경우이므로 to를 user_id로 설정
    if (msg.to.id == our_id) then
        user_id = msg.from.print_name
    else
        user_id = msg.to.print_name
    end

    -- 읽은 메시지로 표시
    mark_read(user_id, ok_cb, false)

    -- 메시지를 구분하는 함수, 이곳에서 command 를 인식하여 각각 처리한다
    msg_processing(user_id, cmd, arg)

end

    -- 비밀 대화방 생성시 호출 (확인 안됨)
function on_secret_chat_created (peer)
    print "secret chat create event"
end

    -- 비밀 대화방 생성이 아래 함수 호출 됨.
function on_secret_chat_update (schat, what)
    print "secret chat update event"
end

    -- 사용자 정보 업데이트시 호출됨
function on_user_update (user)
    print "user update event"
end

    -- 채팅방 업데이트시 호출됨
function on_chat_update (user)
    print "chat update event"
end

    -- 현재 로그인 한 ID를 통지 받는 함수 (숫자 형태의 ID) 
function on_our_id(id)
    our_id = id
    print("My user# : ", id)
end

    -- 어떤 기능인지 확인 안됨
function on_get_difference_end ()
end

    -- 기존 이벤트가 종료 될때 호출, 정확한 의미 파악이 안됨.
function on_binlog_replay_end ()
end

    -- telegram cli 에서 제공하는 lua 함수를 수행하였을때 결과를 받기 위한 함수.
    -- ex: send_msg(user_id, '메시지', ok_cb, false)
function ok_cb(extra, success, result)
end


-- 문자열의 앞뒤 공백을 없애는 함수
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end


    -- 문자열을 space 기준으로 잘라 command와 argument를 나누는 함수
function split(str)
    local cmd=""
    local arg=""
    local arg_cnt=1

    for s in string.gmatch(str, "[^%s]+") do
        if ( arg_cnt == 1 ) then
            cmd = s
        else
            arg = arg .." ".. s
        end
        arg_cnt = arg_cnt + 1
    end

    cmd = trim(cmd)
    arg = trim(arg)

    return cmd, arg
end




위 소스를 /home/pi/tg/bot/basicbot.lua 이름으로 저장한다.


복붙이 안되는 상황이라면 아래 파일을 받는다.


 

basicbot.lua




물론 당연히 소스의 auth_phone 부분에는 수신 받을 대상의 전화번호가 있어야 한다.


파일을 저장하였다면 다음 명령어로 Telegram CLI를 실행한다.



cd /home/pi/tg/

bin/telegram-cli -s bot/basicbot.lua


 

-s 옵션이 lua script 파일을 로딩하여 작동하게 만드는 옵션이다.


텔레그램이 실행 되어 있고 메시지를 수신 받으면 특정 단어에 한해서 lua 스크립트가 수행된다.


Telegram BOT 계정에 "안녕" 이라고 보내면


'안녕 명령어를 입력하셨습니다' 라고 메시지를 보내주고


'날씨' 라고 메시지를 보내면 BOT은 '날씨 명령어를 입력하셨습니다' 라고 메시지를 보내준다.


/home/pi/tg/bot/ 경로에 help.txt 파일이 있다면


help 라는 메시지를 보내게 되면 help.txt 파일의 내용을 사용자에게 전달하게 된다.






이상으로 Telegram BOT 의 가장 기초적인 작업이 완료 되었다.


하지만 위와 같이 실행 하였을때  SSH 접속툴을 종료하면 Telegram CLI 도 같이 종료가 되어 버린다.


리눅스의 Daemon 으로 Telegram CLI 를 실행 해야만 지속적으로 반응 하는 Telegram BOT이 완성이 되는데


Daemon 으로 띄우는 과정과 service 에 등록하는 과정등은 다음 4부에 다루어 본다.

 

 

관련글