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부에 다루어 본다.

 

 

관련글

 

저작자 표시 비영리 변경 금지
신고

  • 2016.03.18 17:56

    비밀댓글입니다

    1. BlogIcon Acidpop acidpop 2016.03.18 17:59 신고

      안녕하세요

      전반적인 소스나 로그가 없어서 바로 판단하기는 어렵습니다만...

      혹시 A 라는 계정에서 A계정으로 메시지를 보내시나요?

      아니면 봇의 계정은 다른 계정을 사용하시나요?

      만약 같은 계정으로 메시지를 보냈다면

      basicbot.lua 파일에서

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


      90~93 라인을 삭제 하던지 주석 처리 하셔서 사용해 보세요

    2. 여우너 2016.03.21 11:02 신고

      감사합니다

      알려주신 부분 주석처리 하니 답변이 오네요

      해결되었습니당 ^^

      정말 많은 도움이 되고 있습니다

      감사합니다

  • 정범진 2016.03.24 20:52 신고

    안녕하세요. 올려주신 자료를 따라하던 중

    (table)
    [from] = (table)
    [peer_id] = (number) 202089138
    [last_name] = (string) Pi
    [print_name] = (string) Strawberry_Pi
    [id] = (string) $01000000b2a20b0c70f34b10e8f80dbb
    [phone] = (string) 12816034555
    [peer_type] = (string) user
    [access_hash] = (number) 1
    [first_name] = (string) Strawberry
    [flags] = (number) 196609
    [unread] = (boolean) true
    [text] = (string) 날씨
    [id] = (string) 01000000b2a20b0ccd0000000000000070f34b10e8f80dbb
    [to] = (table)
    [peer_id] = (number) 84273437
    [last_name] = (string) Jung
    [print_name] = (string) Bumjin_Jung
    [id] = (string) $010000001de90505347275aac14ecdc7
    [phone] = (string) 61452405414
    [peer_type] = (string) user
    [access_hash] = (number) 1
    [first_name] = (string) Bumjin
    [flags] = (number) 589825
    [date] = (number) 1458820102
    [service] = (boolean) false
    [out] = (boolean) false
    [flags] = (number) 257
    auth : OK
    receive : [ 날씨 ]

    argument : [ ]

    Name : Strawberry_Pi
    Phone : 12816034555
    Msg Num : 01000000b2a20b0ccd0000000000000070f34b10e8f80dbb
    to.Name : Bumjin_Jung
    [11:48] Strawberry Pi >>> 날씨
    (table)
    [from] = (table)
    [peer_id] = (number) 84273437
    [last_name] = (string) Jung
    [print_name] = (string) Bumjin_Jung
    [id] = (string) $010000001de90505347275aac14ecdc7
    [phone] = (string) 61452405414
    [peer_type] = (string) user
    [access_hash] = (number) 1
    [first_name] = (string) Bumjin
    [flags] = (number) 589825
    [unread] = (boolean) true
    [text] = (string) 날씨 명령어를 입력하셨습니다
    [id] = (string) 010000001de90505ce00000000000000347275aac14ecdc7
    [to] = (table)
    [peer_id] = (number) 84273437
    [last_name] = (string) Jung
    [print_name] = (string) Bumjin_Jung
    [id] = (string) $010000001de90505347275aac14ecdc7
    [phone] = (string) 61452405414
    [peer_type] = (string) user
    [access_hash] = (number) 1
    [first_name] = (string) Bumjin
    [flags] = (number) 589825
    [date] = (number) 1458820103
    [service] = (boolean) false
    [out] = (boolean) true
    [flags] = (number) 16643
    auth : invalid user
    [11:48] Bumjin Jung <<< 날씨 명령어를 입력하셨습니다

    이런식으로 계속 자기 자신에게만 메세지를 보내는 오류때문에 한참을 고민하다
    댓글 남겨봅니다.
    다른 기기를 통해 봇에게 메세지를 보내었는데 그 기기가 아닌 봇 자신에게 답장을 하는 모양새입니다.

    혹시 한번 봐주실 수 있으신가요?

    1. BlogIcon Acidpop acidpop 2016.03.25 10:41 신고

      안녕하세요.

      혹시 소스를 어딘가 수정 하신건가요?

      아니면 basicbot.lua 파일에

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


      이 코드를 수정을 안하고 그냥 쓰시는건 아니신지요?

    2. BlogIcon JSA 2016.05.22 16:08 신고

      범진님 제가 겪었던 현상하고 같네요.
      131번하고 133번에
      user_id=msg.from.print_name 로 둘다 바꿔주시면 정상적으로
      작동합니다.

  • OJR 2016.08.01 17:57 신고

    안녕 이라고 쳤는데 MAG넘버가 계속 바뀌면서 응답을 여러번하는데 어떻게 해야하나요?

    1. BlogIcon Acidpop acidpop 2016.08.01 18:11 신고

      무슨 말씀이신지 잘 이해를 못하겠습니다.
      로그 내용을 올려주시는게 더 빠를거 같아요

  • 블리어 2016.09.10 22:06 신고

    포스팅 잘보고있습니다.
    일단 저는 현재 한게의 계정으로 사용을 하다보니 위 에 댓글과 갔이
    90 if msg.out then
    91 print("-- : ", msg.out, "\n";)
    92 return
    93 end
    부분을 주석 처리 하였습니다..
    일단 메시지는 받아 지는대... 위의 OJR 님의 내용과 동일하개 됩니다. (즉 : 안녕 명령어를 입력하셨습니다 가 계속 반복하여 텔레그람에 찍히고 로고역씨 MAG 넘버가 변경 괴면서 계속 약 20~30 번 반복 됩니다...
    --로고내용--
    (table)
    [id] = (string) 0100000028db0b00b1000000000000004b4114ed57df059f
    [unread] = (boolean) true
    [out] = (boolean) true
    [to] = (table)
    [id] = (string) $0100000028db0b004b4114ed57df059f
    [phone] = (string) 42777
    [peer_id] = (number) 777000
    [access_hash] = (number) 1
    [first_name] = (string) Telegram
    [flags] = (number) 9
    [print_name] = (string) Telegram
    [peer_type] = (string) user
    [flags] = (number) 16643
    [from] = (table)
    [id] = (string) $01000000e2106f0d8b7f8273820ed4fa
    [phone] = (string) 821093308642
    [print_name] = (string) Lee_Chang_Hyun
    [peer_type] = (string) user
    [first_name] = (string) Lee
    [access_hash] = (number) 1
    [peer_id] = (number) 225382626
    [last_name] = (string) Chang Hyun
    [flags] = (number) 524289
    [date] = (number) 1473512369
    [text] = (string) 안녕 명령어를 입력하셨습니다
    [service] = (boolean) false
    auth : OK
    receive : [ 안녕 ]

    argument : [ 명령어를 입력하셨습니다 ]

    Name : *******
    Phone : 8210********
    Msg Num : 0100000028db0b00b1000000000000004b4114ed57df059f <--- 이부분 변함
    to.Name : Telegram
    [21:59] Telegram <<< 안녕 명령어를 입력하셨습니다

    혹시 어디를 수정하거나 손봐야하는지 조언을 구할수있을까요?

    1. BlogIcon Acidpop acidpop 2016.09.12 09:51 신고

      안녕하세요.
      정확한 내용 파악이 필요한데 지금 사용하고 계신 봇 시스템의 ssh 로 제가 접속해서 볼 수 있을까요?

    2. BlogIcon Acidpop acidpop 2016.09.12 10:04 신고

      소스를 가지고 직접 테스트 해보았습니다.

      원인은 자신에게 메시지를 보낼때 안녕
      이라고 입력하면 안녕 메시지를 입력하셨습니다. 라고 다시 메시지를 보내는데
      "안녕 메시지를 입력하셨습니다." 라는 메시지를 명령어로 판단을 해서 무한 루프가 발생하는 경우가 있네요.

      소스 내용중에 '안녕 명령어를 입력하셨습니다'

      위 내용을
      '"안녕" 명령어를 입력하셨습니다'
      이렇게 안녕 이라는 글자 앞 뒤로 큰 따옴표를 붙여 주세요.
      바로 아래줄의 '날씨 명령어를 입력하셨습니다' 부분도
      '"날씨" 명령어를 입력하셨습니다'

      이렇게 바꿔주시고 테스트 해보시면 됩니다.

  • 패닉 2016.11.05 17:50 신고

    제가 저한테 문자보내지는데 ... 봇이 저한테 보내게 할 수 있을까요?

    1. BlogIcon Acidpop acidpop 2016.11.07 09:02 신고

      Telegram CLI 에서 봇과 계정을 분리 하려면
      봇 전용 계정, 즉 폰 번호가 하나 더 있어야 합니다.

      그럴 환경이 안된다면 Telegram CLI 가 아닌 Telegram BOT 을 사용하시는게 더 좋을것 같습니다.

      http://blog.acidpop.kr/215

      봇 계정을 만드는 방법이고

      python 을 이용해서 telepot 을 사용하시면 됩니다.

  • 피그 2016.12.06 18:43 신고

    lua 스크립트랑 파이썬 스크립트랑 차이가있나요 제가 파이썬으로 이미 짜던 소스가 있는데 atmega128에서 데이터를 받아서 처리를 하는데 그거를 메세지로 폰으로 다시전송하려고하는데 파이썬과 lua 병합을 못하겠네요... 혹시 방법이있을까요?
    아니면 파이썬 스크립트 내용도 있을가요?

    1. BlogIcon Acidpop acidpop 2016.12.07 09:11 신고

      Telegram CLI 는 Python 도 지원합니다.
      https://github.com/vysheng/tg/blob/master/README-PY.md

      해당 링크 참고하시면 되요

  • 피그 2016.12.06 21:01 신고

    텔레그램을 깔고 나니까 깔고난후에는 재부팅하니까 깔기전으로 돌아가던데 혹시원인을 알 수 있을까요..;;

    1. BlogIcon Acidpop acidpop 2016.12.07 09:12 신고

      텔레그램 CLI 를 다운로드 하고 컴파일 하였는데
      다운로드 받은 텔레그램 CLI 가 없어졌다 라는 말씀이신가요?

  • 피그 2016.12.07 13:39 신고

    텔레그램 CLI이인지 lua 스크립트인지 잘 모르겠습니다. 제가 sd카드가 2개있었는데 둘다 텔레그램 하면서 안돼서
    어떤상황이냐면 이 작업을 한 이후에 프로그램들은 다 날라갑니다 안에 프로그램을 다 삭제하고 초기라즈베리를 깔아도 이작업하기 바로전으로 돌아가고 예를들어 텔레그램 하기전이 0이고 하고난후가 1이면 무슨행동을 하든 0으로 돌아가버립니다... 포맷을 하려고해도 포맷이 안대고 초기화를 해도 0으로 다시돌아가버립니다.. 해결책이 있을까요..ㅜㅜ
    그리고 위에 python참고링크를 눌렀는데 엑박뜨는데 라즈베리 명령어창에서 치라는 말씀이신가요?

    1. BlogIcon Acidpop acidpop 2016.12.07 13:52 신고

      "프로그램이 날아 간다" 라는 의미를 도무지 이해를 못하겠습니다.

      부팅이 안된다는 말씀이신가요?
      아니면 텔레그램 CLI 가 설치된 디렉터리가 없어진다는 뜻인가요?

      좀 더 정확한 증상을 말씀해주세요.

      그리고 python 링크는 Telegram CLI 의 기초가 되는 tg 의 github 링크 입니다만.. 왜 안열리는지는 잘 모르겠네요?

      https://github.com/vysheng/tg

      여기에서 README-PY.md 파일을 참고 하시면 되요

      이게 어렵다면 python 용 텔레그램 봇인 telepot 을 이용하세요

      https://github.com/nickoala/telepot

  • 피그 2016.12.07 17:45 신고

    어그러니까 부팅은 되는데 날라간다는말이 그후에 하는 작업내용들이 다날라간다는뜻입니다. 예를들어 바탕화면에 새문서 하나 만들어놓으면 재부팅을 하면 그게 삭제되어있습니다... 그냥 그후에 하는작업들이 하나도 저장이안됩니다.

    1. BlogIcon Acidpop acidpop 2016.12.07 17:47 신고

      telegram cli 만 설치 하면 그런 증상이 나타나나요? 아니면 다른 파일을 생성하여도 그렇게 되나요?
      그리고 작업하시는 디렉토리 경로는 어디인가요?

  • 왕초보 2017.06.10 12:30 신고

    안녕 등의 명령어를 보내면 인코딩이 이상하게 되나봅니다.
    짬짬짬 이렇게 나오네요
    인코딩 설정도 해야하나요?

다른 카테고리의 글 목록

강좌/RaspberryPI 활용 카테고리의 포스트 목록