카카오톡과 LoRa 기술을 이용한 Pet Feeder

2017. 6. 19. 17:172018년 이전 관심사/개발관련

반응형

카카오톡과 LoRa 기술을 이용한 Pet Feeder

구현 아이디어 및 요약

최근 사물인터넷(Internet of Things, IoT)은 차세대 이동통신 서비스의 생태계 구축을 위해 가장 중요한 역할을 수행 할 것으로 예측되고 있으며, 사물인터넷을 위한 LPWAN(Low-Power Wide-Area Network)에 대한 관심이 증가하고 있다.
국내 통신사에서도 LPWAN 기술 및 IoT에 지속적으로 관심을 가지고 있으며, 국내 3사 통신사 중 SKT는 LoRa, LG와 KT는 NB-IoT를 주력 IoT 서비스로 내세우고 있다.

본 프로젝트에서는 SKT의 LoRa 서비스를 이용해 애완동물의 먹이를 원격에서 줄 수 있는 Pet Feeder를 구현 할 예정이며, Pet Feeder Service를 구성하는 컨트롤러 보드, LoRa 모니터링 서버, 스마트폰 구현 방법에 대해 설명한다.

프로젝트 목표

  • 카카오톡을 이용한 먹이 주기 명령 수행
  • 컨트롤러 보드에서 온/습도 정보를 측정해서 LoRa 모니터링 서버에서 모니터링 하기

프로젝트 구성도

프로젝트는 아래 그림과 같이 컨트롤러, SKT LoRa Network, LoRa 모니터링 서버, 카카오톡 서버로 구성된다.
컨트롤러에서 온/습도 데이터를 측정해서 LoRa로 데이터를 송신하면, SKT의 G/W(Gateway)와 N/W(Network)서버를 통해 ThingPlug에 데이터를 전달한다. ThingPlug는 전달 받은 데이터를 LoRa 모니터링 서버에게 다시 전달하고, LoRa 모니터링 서버는 수신한 데이터를 자신의 DB(Database)에 저장한다.

참고로, ThingPlug에 전달된 데이터는 ThingPlug에 DB에 임시적으로 저장되지만, 저장된 데이터는 2일 후에 삭제 된다. 때문에 본 프로젝트와 같이 사용자가 직접 구현한 서버에서 ThingPlug의 데이터를 가져 오는 작업을 해야 한다. ThingPlug에서 데이터를 가져오는 방법은 해당 링크를 참고 하기 바란다.http://docs.thingplug.apiary.io/#reference/data-management

추가로 카카오톡 서버에서는 발생하는 이벤트를 LoRa 모니터링 서버로 Redirection 해서, 사용자가 카카오톡을 이용하여 먹이 주기를 수행 할 수 있는 구조로 설계 하였다.

Contest1

컨트롤러

컨트롤러의 역할은 온/습도 정보를 측정하여 SKT LoRa Network로 전달하는 기능과 카카오톡으로 부터 먹이 주기 명령을 받으면 내부에 있는 스크류를 동작 시켜 애완동물의 먹이를 밖으로 배출한다.

컨트롤러의 구성요소는 아래와 같다.

  • T자형 PVC와 내부 스크류
  • Continuous Rotation Servo ( Parallax )
  • WizArduino Mega Wifi ( WIZnet )
  • LoRa Kit ( WIZnet )
  • LoRa 모듈 (TLT01CS1, 솔루엠)
  • 온습도 센서 ( DHT11 )

컨트롤러는 아래와 같은 단계로 제작 되었다.

  1. Thingiverse에서 해당 프로젝트에서 사용할 수 있는 3D 모델링 파일들을 검색하고, 이를 3D 프린터로 출력. (모델링 파일의 원본 주소: https://www.thingiverse.com/thing:34100 )
  2. 출력된 스크류와 서보 모터를 연결하고, 이를 50파이 짜리 T자형 PVC에 장착
  3. WizArduino MEGA WIFI와 Wiznet Lora Kit 연결 ( WizArduino와 LoRa Kit간에는 Software UART(RX:10,TX:11)를 사용 함 )
  4. WizArduino의 9번 핀을 이용하여 Servo Motor 제어

Contest4

본 프로젝트를 위해 SoluM 모듈을 Arduino 에서 사용 할 수 있도록 라이브러리 작업을 진행 하였으며, 해당 라이브러리는 아래 주소에서 다운 받을 수 있다.
https://github.com/kaizen8501/solum_lora_library

컨트롤러 역할을 하는 아두이노 보드의 코드는 아래와 같다.

#include "Arduino.h"
#include <SKT_LoRa.h>
#include <SoftwareSerial.h>
#include <Servo.h>

SoftwareSerial LoRaSerial(10, 11); // RX, TX
Servo servo;
int servoPin = 9;

void setup()
{
    servo.attach(servoPin);
    servo.write(90);

    Serial.begin(38400);
    LoRaSerial.begin(38400);
    LoRa.init(&LoRaSerial);
    LoRa.begin();
}

void loop()
{
    char str[100];
    if( LoRa.available() )
    {
        LoRa.read((uint8_t*)str,100);
        if( strcmp(str,"1000\r\n") == 0 )
        {
            Serial.println("Start Feed");
            servo.write(120);
            delay(5000);
            servo.write(90);
        }
    }
}

LoRa 모니터링 서버

로라 모니터링 서버는 Django 플랫폼을 이용하여 구현 하였으며, 컨트롤러와 같이 SKT LoRa Network에 연결되어 있는 디바이스들의 정보를 모니터링 하거나 제어 할 수 있는 기능을 가지고 있다. 또한 본 프로젝트를 위한 용도 이외에 SKT LoRa를 위한 범용 웹 서버로 사용 가능 하다.

Contest5

카카오톡 플러스 친구 설정 및 연동 방법

카카오톡 플러스 친구를 설정하기 위해서는 https://center-pf.kakao.com/에 접속하고 아래와 같은 절차를 수행 해야 한다.

새 플러스 친구 만들기 버튼 클릭 후 정보 기입

Contest6-0

Contest6-1

스마트 채팅 설정

아래 그림과 같이 스마트 채팅 탭을 클릭하고 API형에 대한 설정 버튼을 눌러 API에 대한 설정을 진행 한다.
자동응답형은 노출되는 버튼을 선택해서 제어 하는 방식으로 사용 할 수 있으며, 본 프로젝트는 대화형으로 제어 명령을 보내기 위해 API 형을 사용 하였다.

Contest6

API형 설정

API형 설정에서 가장 중요한 부분은 앱 URL 이다. 앱 URL에 기입 란에 LoRa 모니터링 서버의 URL 혹은 IP 주소를 입력하고 카카오톡을 위한 keyboard와 message가 구현되어 있는 URL 주소를 입력한다.
본 프로젝트는 아래와 같이 http://IP주소/thingplug/device/kakao 로 설정되어 있다.

urlpatterns = [
    url(r'^device/kakao/keyboard/', views.pet_feeder_kakao_keyboard),
    url(r'^device/kakao/message', views.pet_feeder_kakao_message),
    ]

Contest7

카카오톡 연동을 위한 설정이 정상적으로 완료 되었다면, API 테스트 버튼을 눌렀을 때 아래와 같이 keyboard OK 응답을 받아야 한다.

Contest8

카카오톡 연동을 위한 Python 코드는 아래와 같다.

def pet_feeder_kakao_keyboard(request):
    return JsonResponse({
            'type':'text',
            })


kakao_user = ''
kakao_device = ''

@csrf_exempt
def pet_feeder_kakao_message(request):
    global  kakao_user
    global  kakao_device

    json_str = ((request.body).decode('utf-8'))
    received_json_data = json.loads(json_str)
    command = received_json_data['content']

    user_obj = User.objects.all()
    user_info = ''

    if command.find('계정') != -1:
        for user in user_obj:
            user_info += '- ' + user.username + '\r\n'
        return JsonResponse({
            'message':{
                'text': '등록된 계정은 아래와 같습니다.\r\n' + user_info
            },
        })
    elif command.find('헬프') != -1 or command.find('help') != -1:
        return JsonResponse({
            'message': {
                'text': '명령어 리스트\r\n' +
                        '- 계정\r\n' +
                        '- 장치 리스트\r\n' +
                        '- 밥줘\r\n'
            },
        })
    elif command.find('재접속') != -1:
        pass

    elif command.find('장치리스트') != -1 or command.find('장치 리스트') != -1:
        command_list = command.split(' ')
        for command in command_list:
            for user in user_obj:
                if command.find(user.username) != -1:
                    kakao_user = user.username
                    #device_info = ''
                    device_list = []
                    tp_info_obj = ThingplugInfo.objects.get(user=user)
                    dev_obj = DeviceInfo.objects.filter(thingpluginfo=tp_info_obj)
                    for device in dev_obj:
                        #device_info += device.device_id + "\r\n"
                        device_list.append(device.device_id+' 장치 등록')

                    return JsonResponse({
                        'message':{
                            #'text': '등록된 장치는 아래와 같습니다.\r\n' + device_info
                            'text': '등록된 장치는 아래와 같습니다.'
                        },
                        'keyboard':{
                            'type': 'buttons',
                            'buttons':device_list
                        }
                    })
        return JsonResponse({
            'message':{
                'text': '계정 정보를 포함해서 질문 해 주세요.'
            }
        })

    elif command.find('장치 등록') != -1:
        try:
            user = User.objects.get(username=kakao_user)
        except User.DoesNotExist:
            return JsonResponse({
                'message': {
                    'text': '[장치 리스트]를 요청해 주세요.'
                }
            })
        try:
            tp_info_obj = ThingplugInfo.objects.get(user=user)
            dev_obj = DeviceInfo.objects.filter(thingpluginfo=tp_info_obj)
        except:
            return JsonResponse({
                'message': {
                    'text': 'ThingPlug 정보 확인 바람'
                }
            })

        command_list = command.split(' ')
        for command in command_list:
            for device in dev_obj:
                if command.find(device.device_id) != -1:
                    kakao_device = device.device_id
                    return JsonResponse({
                        'message': {
                            'text': kakao_device + ' 등록 완료'
                        }
                    })

        return JsonResponse({
            'message': {
                'text': '디바이스 정보가 없습니다.'
            }
        })

    elif command.find('밥') != -1:
        node_id = kakao_device
        mgmt_cmd = '1000'
        result, cmd_inst = g_thingplug.createMgmtInstance(node_id, "extDevMgmt", mgmt_cmd)
        time.sleep(3)
        result, exe_status, exe_result = g_thingplug.retrieveMgmtResult(node_id, "extDevMgmt", cmd_inst)
        if result == True:
            message = node_id + ' 동작 성공'
        else:
            message = node_id + ' 동작 실패'

        return JsonResponse({
            'message': {
                'text': message
            },
        })

    return JsonResponse({
        'message': {
            'text': '명령이 없습니다.'
        },
    })

카카오톡 데모

스마트폰에서 카카오톡 플러스 친구를 추가 하고, 아래 그림과 같이 명령을 수행하면 컨트롤러를 제어 할 수 있다.

Contest9

웹페이지 데모

LoRa 모니터링 서버에서는 웹 서버 기능도 지원하고 있으며, 아래와 같은 페이지를 이용하여 컨트롤러에게 제어를 내리거나 컨트롤러가 송신하는 데이터를 로그 및 차트 형태로 확인 할 수 있다.

Contest10

동작 데모


반응형