1. 주제
2. 유사 제품 사례
2.1 스마트 알람 Bonjour
2.2 스마트 알람 Kello
2.3 Brookstone 스마트폰 앱 연동 알람시계
2.4 Philips의 Wake Up Light
2.5 카펫 알람
3. 진행
3.1 요구사항 설계
3.2 소프트웨어/하드웨어 스택 및 플랫폼 조사 및 확정
3.3 스터디
3.3.1 라즈베리파이 스터디
3.3.2 AVR / 아두이노 스터디
3.3.3 IoTivity 스터디
3.3.3.5 OCF표준과 IoTivity 개요
3.3.3.6 OCF 시소스 타입과 IoTivity 시뮬레이터
3.3.3.7 IoTivity 연결 추상계층
3.3.3.8 IoTivity P2P 연결
3.3.3.p3 IoTivity 빌드
3.3.3.p5 IoTivity 심플 서버와 심플 클라이언트
3.3.4 관련 툴 스터디
3.3.4.1 SCon
3.4 작업
3.4.1 라즈베리파이 작업
3.4.2 아두이노 작업
3.4.3 IoTivity 작업
주제: IoTivity를 활용한 스마트 알람 시스템 구축
가정에서 유용하게 사용할 수 있는 스마트 알람 시스템을 구축하는 것이 졸업작품의 주제이다. 사용할 주요 장비들로는 라즈베리파이, 아두이노, IoTivity 등이 있다.
킥 스타터 출처
크라우드 펀딩 사이트인 킥 스타터에 제안된 스마트 알람시계이다. 개인비서 역할을 수행한다. 학습기능도 갖추고 있다. 제공하는 기능들의 예시는 다음과 같다.
- 음성을 통한 알람 기능
- 교통상황 정보 제공
- 날씨 정보 제공
- 다른 스마트 홈 IoT 기기와의 연동
- 음악, 동영상 재생 기능
- 음성 인터페이스 제공
- 전용 스마트폰 앱을 통한 설정
- 사용자 생활 패턴에 따라 학습
기본적인 알람 기능 뿐만 아니라 날씨, 교통 정보 등을 종합하여 여유로운 시간 관리가 가능하도록 제안해준다.
또한 사용자의 생활 패턴을 분석하여 환경설정을 하여 맞춤형 정보를 제공한다.
스마트 홈 허브 역할도 수행한다. 음성 인터페이스를 제공한다.
Kello 공식 URL
Kello Labs에서 5만 불을 목표로 크라우드 펀딩을 시작한 알람시계이다. 일반적인 알람시계와는 다르게 수면 습관을 훈련시켜주는 기능을 가지고 있다. 수면 전문가의 수면 행태 분석 연구 결과를 녹여낸 프로그램이 설치되어 있다. 다음과 같은 기능들을 제공한다.
- Snooze Less: 일 주일 동안 알람 버튼을 눌러서 알람을 끄는 회수를 제한함
- Bedtime Alert: 잠자리에 들 시간이 되면 알려줌
- Wake Up Earlier: 조금씩이지만 꾸준한 변화를 통하여 일찍 일어날 수 있도록 함
- Power Naps: 낮잠을 효율적으로 잘 수 있도록 음악을 틀어줌
- Fall Asleep Fast: 빨리 잡들도록 숨쉬는 패턴에 맞추어 불빛을 내보내 줌
- Fight Jet Lag: 비행기를 통한 여행 일정을 알려주면, 신체 시계에 맞추어 최적화된 잠자리 시간을 알려줌
구매 URL
Brookstone에서 판매하는 스마트폰 연동 알람시계이다. 특별한 기능을 많이 넣기 보다는, 알람시계 본연의 기능을 넣되 필수 기능에 충실한 모습을 보여준다. UX에 좀 더 신경을 쓴 듯한 제품이다. 주요 특징은 다음과 같다.
- 케이블로 전원을 연결하되, 수은 전지를 통해 전원 케이블 연결 해제시에도 시간 정보를 저장한다. 따라서 케이블이 재연결되더라도 설정을 다시 할 필요가 없다.
- 스마트 폰을 통하여 심플한 UI로 모든 기능과 설정을 간편히 할 수 있다. 물론 스마트 폰이 없더라도 기능 사용에 제약은 없다.
- 알람 소리가 0db부터 100db 까지 점진적으로 커지는 크레센도식 알람을 지원한다.
아마존 구매 URL
기존에 소리로만 깨우는 알람과는 다르게, 아침 햇살을 모방하는 방식으로 깨워주는 알람시계이다. LED만으로 깨어나지 않는다면 소리도 같이 발생하는 기능도 갖추고 있다.
아마존 구매 URL
강력한 소리를 통해 수면자를 깨우고, 알람을 끄기 위해서는 최소 3초 동안 카펫 위에 서야 꺼진다. 이 값은 최대 30초까지 설정할 수 있다. 알람을 끄기 위해서는 강제적으로 침대에서 나올 수 밖에 없다.
스마트 알람은 혼자사는 개인을 위한 제품으로 대표적으로 다음과 같은 기능들을 제공한다.
- 빛을 이용한 알람과 소리를 이용한 알람을 동시에 사용
- 개인 스케쥴러와 연동하여 일어날 시간을 자동으로 계산하여 알람 등록
- 센서를 이용하여 개인이 수면에 드는 시간을 수집
- 웹을 통한 UI 제공
그리고 +alpha로 머신러닝을 활용한 기능도 추가할 예정이다.
추가적인 기능적 요구사항이 있을 시 이 문서에 추가한다.
지금 생각하는 SW/HW 스택 및 플랫폼은 다음과 같다.
- 라즈베리파이 - 라즈비안 OS
- 아두이노
- IoTivity
각각의 스택과 플랫폼에 대한 조사를 해보자 한다.
위키백과 링크
라즈베리파이는 영국 잉글랜드의 라즈베리 파이 재단이 만든 싱글 보드 컴퓨터이다. 교육용의 목적성을 띠고 제작되었으며, 저성능이지만 가격이 매우 싼 편이다. 그리고 높은 범용성을 가지고 있다. ARM CPU를 사용하며, 운영체제는 대부분 리눅스 계열을 사용한다. 그 중 데비안 계열 리눅스를 라즈베리파이용으로 만든, 라즈베리 파이의 개발사에서 기본적으로 제공하는 OS인 라즈비안이 있다. 그 외에도 다양한 리눅스와 저사양 디바이스용 Windows, 안드로이드 OS 등을 설치 가능하다.
라즈베리파이 3 모델 B의 스펙은 다음과 같다.
- Quad Cord 1.2GHz Broadcom BCM2837 64bit CPU
- 1GB RAM
- BCM43438 무선랜 과 BLE(Bluetooth Low Energy) 보드 내장
- 확장된 GPIO를 위한 40개 핀
- USB 2.0 포트 4개
- 4 Pole stereo output and composite video port
- 풀 사이즈 HDMI
- CSI 카메라 포트
- DSI 디스플레이 포트(터치스크린 디스플레이 연결용)
- 저장소를 위한 Micro SD 포트
- 2.5A까지 지원하는 Micro USB 전원 입력부
확인해보면, 보드 자체에서 Wi-Fi와 블루투스를 지원하므로 따로 Wi-Fi 동글 같은 것을 끼울 필요가 없다. 그리고 저장소로 Micro SD카드를 지원하므로, 라즈베리파이에 OS를 올리기 위해서는 이미지 업로드에 사용할 컴퓨터에 Micro SD 슬롯을 지원하거나 젠더를 가지고 있어야 한다.
AVR 마이크로 컨트롤러 프로젝트인 Wiring에서 파생한 프로젝트이다. 마이크로컨트롤러 유닛(MCU: Micro Controller Unit)은 간단하게 이야기 해서 작은 컴퓨터라고 볼 수 있다. 특수목적을 수행하는 소형화된 CPU로서, 주로 C언어를 이용하여 프로그래밍을 한다. CPU와 다른점은, 하나의 칩에 CPU, Flash Memory, SRAM, I/O의 기능이 내장되어 있다. 따라서 MCU 독립적으로 동작이 가능하다.
AVR은 하드웨어 엔지니어가 될 때 처음 공부하면 좋을만한 마이크로컨트롤러로, 1996년 아트멜 사에서 개발한 8비트 RISC MCU이다. 단일 칩 플래시 메모리를 사용한 최초의 MCU중 하나이다. AVR 프로그래밍을 통해 하드웨어를 개발할 시 하드웨어적으로 로우 레벨 부분을 신경써야 하므로, 해당 부분의 지식을 습득하기 좋다. AVR 프로그래밍을 할 시 Atmel Studio라는 IDE를 활용하면 편리하다. 개발도구가 무료이며, 하드웨어 가격도 저렴하다. 가격 대비 만족스러운 성능도 보여준다.
아두이노는 2005년 이탈리아의 IDII(Interaction Design Institutelvera)에서 하드웨어에 익숙치 않은 학생들이 자신의 작품들을 손쉽게 만들수 있게 하는 목적으로 만들어졌으며, AVR을 기반으로 제작되었다. 아두이이노는 임베디드 시스템 중의 하나로 장치 제어를 손쉽게 할 수 있는 환경을 제공한다. 아두이노 개발을 위한 아두이노 IDE도 무료로 제공되며 사용이 매우 쉽다. 펌웨어 업로드를 USB를 통하여 쉽게 할 수 있다. API는 C++로 제공된다.
IoTivity는 IoT 장비간의 연결과 관련된 다양한 기능을 제공하는 오픈소스 소프트웨어 프레임워크이다.
IoTivity가 어떤 서비스를 제공해주는지 알아보기 위해 학습을 진행한다.
관련된 교육 자료들은 다음 링크에서 얻을 수 있다.
SKKU 2017 Lecture Materials
IoT의 서비스 레벨 상호호환성을 지원하기 위한 OCF 표준이라는 것이 있다. IoTivity는 이 OCF 표준을 구현한 오픈소스 소프트웨어 프레임워크 중 하나이다.
OCF 표준
OCF표준은 원격 접근이나, 리소스 타입, 보안 등의 스펙들을 정해놓았다.
OCF는 Open Connectivity Foundation의 약자로, 기존에 있던 OIC(Open Interconnect Consortium)에 Microsoft Qualcomm, Electrolux가 새롭게 합류하면서 확장된 IoT 표준단체이다. 운영, 특허 정책 등 모든 내용이 OIC와 동일하지만, 신규 회원사의 참여로 인해서 이름만 바뀐 형태이다.
OIC Role은 클라이언트와 서버로 구성되어 있다. CRUDN 작업들은 CoAP/HTTP 프로토콜을 통해서 이루어진다. CoAP는 Constrained Application Protocol의 약자로, 요즘 떠오르는 IoT용 프로토콜이다. CoAP프로토콜은 UDP를 기반으로 이루어지며, 낮은 신뢰성은 반복적 메시징에 의해 의존한다. 또한 멀티캐스트를 지원하며, UDP 프로오콜 상 DTLS를 이용하여 보안을 강화환다. 리소스와 서비스는 URI를 이용하여 구분한다.
OIC 아키텍쳐는 클라이언트-서버 구조이다. OIC 클라이언트는 트랜젝션을 실행시키고, 서비스를 얻기 위해 OIC 서버에 접근한다. OIC 서버는 리소스를 제공하며, 응답을 주면서 서비스르 제공한다. RESTful 아키텍쳐에 기반한다.
RESTful 모델은 URI로 리소스를 표현하며 형태는 다음과 같다.
oic://<regular_name>/<path>?<query>
쿼리 파라매터는 ';' 문자를 통해 구분하며, 파라매터의 순서는 중요하다.
RESTful 모델에서 사용하는 동작은 CRUDN이며, 이는 각각 Create, Retrieve, Update, Delete, Notify의 머릿글자를 딴 것이다. 일반적인 자료구조의 Primitive Operation이 아닌 Notify는 상태 변화에 대하여 알림(notificiation)을 요청하는 동작이다.
이러한 RESTful 리소스 모델은, 네트워크 프로토콜에 관계없이 원격에 있는 OIC 디바이스에 접근할 수 있도록 추상화 계층을 제공한다.
JSON 스키마로 프로퍼티들을 나타내며, RAML(RESTful API Modeling Language)로 요청, 응답의 형태를 나타낸다.
IoTivity
크로스 플랫폼 프레임워크이며, 아두이노와 같은 저사양의 장비들을 지원한다. 그리고 다양한 언어에 API를 제공한다.
IoTivity가 서비스 레벨에서 제공하는 것들은 다음과 같다.
- 장비 관리
Thing Manager로 사물들을 관리한다.
Scene Manager로 여러개의 장비를 제어하는 시나리오를 만든다. - 저전력 관리
리소스 호스팅을 한다. 원격 클라이언트가 할 요청, 데이터 관리를 대신 해준다고 생각하면 된다.
리소스 디렉토리 기능을 제공한다. 소비 전력을 줄이기 위해서 Sleep 해야하고 Multicast에 응답할 수 없는 장비들을 찾아내는 쿼리를 보낸다. - 리소스 캡슐화
리소스 브로커 역할을 한다. 원격에 있는 리소스가 있는지 확인하고, 알려진 리소스에 대해 지속적으로 연결이 가능한지 확인하는 역할이다.
리소스 캐시역할을 한다. 원격 리소스의 가장 최신 정보를 가지고 있는다. - 리소스 컨테이너
프로토콜 브릿지 역할을 한다. OCF 리소스가 아닌 것들을 통합한다.
** RAML **
RAML(RESTful API Modeling Language)는 API 라이프사이클 설계와 공유를 쉽고 간편하게 해주는 모델링 언어이다. 공식 사이트 링크는 http://raml.org 이다.
RAML은 기계가 인식할 수 있는 API 설계도이며, 사람에게도 친숙하다. Nodejs, Java, .NET, 파이썬의 몇몇 언어들을 지원한다. RAML으로 CRUDN 연산 시 전송하는 패킷 내용을 정의할 수 있다. 시뮬레이션에 사용할 수도 있고, 응답의 타당성을 검증할 수 있다.
** CRUDN 연산 응답 코드 **
리소스 타입의 정의외 허용된 CRUDN 연산에 따라서 리소스는 생성되거나 변경될 수 있다. CRUDN 연산에 따라서 다른 의미를 갖는 다른 응답코드가 올 수 있다.
응답 코드 | 의미 |
---|---|
200 | 변경이 잘 이루어짐 |
201 | CREATE 연산에 의해 리소스가 성공적으로 생성되었고, 응답 내용은 생성된 리소스의 URL이다. |
204 | 모든 것이 잘 동작했고, 응답 내용은 없다. |
403 | RETRIEVE 연산의 경우, 서버는 해당 요청에 대하여 지원하지 않는다. 혹은 서버가 어떤 문제로 인하여 CREATE나 UPDATE 연산을 수행할 수 없다. |
OIC에서 정의하는 리소스 타입들
62개의 리소스 타입이 정의되어 있다.
OCF Resource Type Spec v1.3.0
OIC Resource Type Spec v.1.1.0
IoTivity Simulator
IoTivity 위키의 시뮬레이터 설명
IoTivity 시뮬레이터 유저 가이드
실제 장비들을 통해서 서비스 구성을 하지 않더라도, IoTivity Simulator를 통해서 설계한 RESTful API와 상황들을 테스트해볼 수 있다. 시뮬레이터는 크게 두가지 기능을 제공한다.
- 서비스 제공자
- 클라이언트 컨트롤러
시뮬레이터는 Eclipse 플러그인 형태를 띤다. 그리고 제공하는 피쳐가 리눅스 플랫폼에서 자바 API를 통한 SDK 지원이므로, 시뮬레이터 관련 작업은 리눅스에서 진행하도록 한다. 리눅스는 Vmware에 설치된 Ubuntu 16.04를 사용한다.
IoTivity 네트워크 연결 아키텍쳐는 크게 4단계로 나뉘어진다.
- 메시지 스위칭
게이트웨이 리소스 발견
라우팅 테이블 관리 메시지 포워딩 - CA 제어 컴포넌트
네트워크 선택과 인터페이스 제어
CoAP 메시지 직렬화와 파싱
블록단위 메시징의 흐름 제어 - 전송 어댑터 컴포넌트
UDP, TCP, BLE, BT와 NFC를 통한 데이터 전송
DTLS를 사용한 안전한 데이터 교환 - 플랫폼 어댑터 컴포넌트
Ubuntu, Android, Tizen, Arduiono와 같은 플랫폼별 해당되는 Wi-Fi, BLE, 이더넷, BT
- Routing Through Heterogeneous Connectivity
만약 중간 게이트웨이가 다양한 네트워크 연결을 지원한다면(IP와 Bluetooth), 게이트웨이는 서로 다른 전송계층에 있는 요청과 응답을 포워드 해줘서 연결가능하게 해줄 수 있다.
- Blockwise Transfer
OIC 클라이언트와 OIC 서버는 작은 블록단위의 메시지로 쪼개서 보냄으로써, 큰 크기의 메시지를 보내고 받을 수 있다.
- Start from Basic API Example
클라이언트 사이드에서는 서비스나 리소스를 찾기위해 다음 API를 사용할 수 있다.
OCPlatform::findResource Docs 링크
OCPlatform::findResource(const std::string& host, const std::string& resourceName, OCConectivityType connectivityType, FindCallback resourceHandler);
이 때 모든 알려진 OIC 디바이스를 찾기 위해선 다음과 같은 코드를 사용할 수 있다.
requestURI << OC_RSRVD_WELL_KNOWN_URI;
OCPlatform::findResource("", requetURI.str(), CT_DEFAULT, &foundResource);
OC_RSRVD_WELL_KNOWN_URI는 "/oic/res"를 뜻하며, 모든 discoverable한 OIC 장치를 뜻한다.
host 인자에 null값을 넣으면 리소스 탐색 쿼리를 멀티캐스트 하게 된다.
- Call Path(호출 과정)
API를 호출하면 OCPlatform -> OCPlatform_impl -> InProcClientWrapper -> OCStack -> CaAPI 순서로 호출된다.
다른 RESTful API의 호출 과정과 동일하다(POST, GET, PUT, OBSERVE)
- 소스 코드 계층구조(Source Code Hierarchy)
iotivity/resource/csdk/connectivity/src
에 연결 관련 소스코드가 있다.
라우팅 메니저 소스코드는 /iotivity/resource/csdk/routing
경로에 있다.
- 데이터 전송 시 호출 과정(Call Path: Sending Data)
-
전송 요청은 블록 단위(BWT:Block-wise tranfer)로 처리된다. 일반적으로 UDP나 블루투스를 통해 전송된다.
-
BWT는 단위 데이터를 기본 크기인 1KB의 블록 데이터로 만들어서 전송 큐 쓰레드로 보낸다.
-
전송 큐 쓰레드는 적절한 Transport 핸들러에 데이터를 보낸다.
-
UDP의 경우 UDP 전송 큐 스레드는 단말로 데이터를 보낸다.
전송 큐는 2가지 종류가 있으며, 각각이 공통 전송 큐과 어댑터 전송 큐이다.
- 데이터 수신 시 호출 과정(Call Path: Receiving Data)
- UDP의 경우, UDP 수신 쓰레드는 단말로부터 데이터를 받아온다.
- 적절한 Transport가 UDP나 블루투스인 경우, BWT는 블록 데이터의 다음 전송 데이터 준비를 한다.
- 전송큐 쓰레드로 다시 보내진다.
- 만약 받은 데이터가 BWT의 마지막 블록 데이터인 경우, 수신 큐 쓰레드로 데이터가 전송되고, 최종적으로는 상위 레이어로 보내지게 된다.
- CA(Connectivity Abstraction) APIs
연결 추상계층의 API들은 다음과 같이 존재한다.
CAResult_t CAInitialize();
void CATerminate();
CAResult_t CAStartListeningServer();
CAResult_t CAStopListeningServer();
CAResult_t CAStartDiscoveryServer();
void CARegisterHandler(CARequestCallback ReqHandler, CARequestCallback RespHandler, CAErrorCallback ErrorHandler);
CAResult_t CACreateEndpoint(CATransportFlags_t flags, CATransportAdapter_t adapter, const char *addr, uint16_t port, CAEndpoint_t **object);
void CADestroyEndpoint(CAEndpoint_t *object);
CAResult_t CAGenerateToken(CAToken_t &token, uint8_t tokenLength);
void CADestroyToken(CAToken_t token);
CAResult_t CASendRequest(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo);
CAResult_t CASendResponse(const CAEndpoint_t *object, const CAResponseInfo_t *responseInfo);
CAResult_t CASelectNetwork(CATransportAdapter_t interestedNetwork);
CAResult_t CAUnSelectNetwork(CATransportAdapter_t nonInterestedNetwork);
CAResult_t CAGetNetworkInformation(CAEndpoint_t **info, uint32_t *size);
CAResult_t CAHandleRequestResponse()
CAResult_t CASetRAInfo(const CARAInfo_t *caraInfo)
CAInitialize()
- 연결 추상화 모듈을 초기화한다. 어댑터와 공통 쓰레드 풀, 그외 모듈들을 초기화한다.
CASelectNetwork()
- 사용할 네트워크를 고른다.
CAStartDiscoveryServer()
- 멀티케스트 요청을 Listen하기 위한 서버를 실행한다. 어뎁터 설정에 따라 다른 종류의 서버가 구동된다.
CACreateEndpoint()
- 단말을 지정한다. CADestroyEndpoint()를 이용해서 단말을 해제할 수 있다.
CAGenerateToken()
- 요청과 응답을 매칭시키기 위한 토큰을 생성한다.
CASendRequest()
- 리소스에 제어 요청을 보낸다.
CAGetNetworkInformation()
- 네트워크 정보를 받아온다.
IoTivity는 다양한 언어들과 플랫폼을 위한 API들을 지원한다.
IoTivity는 멀티 플랫폼을 지원한다. x86, x86_64, arm-v7a, arm, arm64 CPU 아키텍쳐를 지원하고, 운영체제는 Linux, 안드로이드, 타이젠, 아두이노를 지원한다.
IoTivity의 기본 빌드 툴은 Scon으로 멀티 플랫폼의 크로스 빌드를 지원한다. 명령어는 다음과 같은 형식으로 사용한다.
$ scons TARGET_ARCH=arm TARGET_OS=android
IoTivity gerrit이라는 곳에서 소스코드를 받을 수 있다. 소스코드를 받기 이전에 IoTivity Linux foundation에 회원가입을 한다. 이후 다음 링크로 이동해서 username으로 로그인을 해야 한다.
https://gerrit.iotivity.org/gerrit/
그리고 소스코드를 내려받을 git 클라이언트 사이드에서 다음 명령어를 이용해서 공개키-비밀키를 생성한다.
$ ssh-keygen
일부 질문과 답변을 응답한다. 그러면 클라이언트의 공개키-비밀키가 생성되게 된다. 그리고 다음 명령어의 표준 출력값을 gerrit 웹 사이트의 SSH-public key form에 붙여넣는다.
$ cat ~/.ssh/id_rsa.pub
그리고 클라이언트에서 ssh configuration을 설정해준다.
$ gedit ~/.ssh/config
다음과 같은 양식으로 붙여넣는다. user 항목에는 gerrit ID값을 넣는다.
Host gerrit.iotivity.org
Hostname gerrit.iotivity.org
IdentityFile ~/.ssh/id_rsa
User hangil
Port 29418
그리고 다음 명령어로 git clone을 받는다.
$ git clone ssh://gerrit.iotivity.org/iotivity
그리고 의존 라이브러리도 같이 받는다.(tinycbor)
$ git clone https://github.com/01org/tinycbor.git extlibs/tinycbor/tinycbor
$ git clone https://github.com/ARMmbed/mbedtls.git extlibs/mbedtls/mbedtls -b mbedtls-2.4.2
scons를 이용해서 빌드할 수 있다. 다양한 플랫폼에 대해 빌드를 실시할 수 있다.
안드로이드 빌드
안드로이드는 OIC 클라이언트 예제 코드만 보여지고 있다. 안드로이드 빌드 시 다음 경로에서 서버 리소스의 IP주소를 설정해 주어야 한다.
iotivity/java/examples-android/simpleclient/src/main/java/org/iotivity/base/examples/SimpleClient.java
OcPlatform.findResource("196.168.0.1", ...
와 같은 형식으로 String으로 입력한다.
안드로이드를 타겟으로 하여 빌드할때는 다음과 같은 명령어를 사용한다.
$ scons TARGET_OS=android TARGET_ARCH=armeabi-v7a -j8
빌드가 다 된 이후에는 다음 경로에 apk파일들이 생성된다.
iotivity/java/examples-android/simpleclient/build/outputs/apk
adb를 이용해서 안드로이드 폰에 설치할 수 있다.
$ adb install simpleclient-armeabi-v7a-debug.apk
만약 [INSTALLED_FAILED_ALREADY_EXISTS]에러가 나타난다면 -r
옵션을 주어서 재설치 하면 된다.
$ adb install -r simpleclient-armeabi-v7a-debug.apk
라즈베리파이 빌드
라즈베리파이용을 위한 빌드를 하는 도중 다음과 같은 에러 메시지를 확인했다.
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Warning \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* You are trying cross build, please make sure cross (arm) libraries are
\* installed!
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
Checking for C++ library boost_thread... no
Did not find boost_thread, exiting!
iotivity/extlibs/boost
에 boost arm 라이브러리가 설치되지 않은 것으로 보인다. SConscript를 보니, sourceforce에서 라이브러리를 받아오는 것으로 보인다.
Android 플랫폼으로 빌드를 하니 해당 경로에 알아서 라이브러리를 가져와서 빌드하는 반면, arm Linux 플랫폼으로 빌드를 하니 위 메시지와 함께 실패한다.
https://wiki.iotivity.org/iotivity_porting_to_arm_based_platforms
https://lists.iotivity.org/pipermail/iotivity-dev/2016-September/005531.html
위 문서들을 참조해서 IoTivity arm 크로스 컴파일에 대해서 좀 알아보고, 최후의 방법으로는 라즈베리 파이에서 빌드를 하는 방법도 있을 것이다.
학습자료에 따르면 라즈베리파이에서 빌드를 하는 식으로 해결한 것으로 보인다. 일단 해당 방법을 적용해보도록 하자.
라즈베리파이에서 빌드를 시도하다보면 extlib에 몇개의 레포지토리를 clone 하라는 내용이 뜬다. uuid package를 못찾는 다는 내용은 다음 명령어로 해결이 가능하다.
apt install -y uuid-dev
이후 No package 'gio-unix-2.0' found
라는 에러 메시지가 나타난다.
다음 명령어로 해결해보자
sudo apt-get install libglib2.0-dev
https://askubuntu.com/questions/281984/how-install-gio-unix-2-28-0
이제는 No package' sqlite3' found
가 뜬다
apt install -y sqlite3
apt install -y libsqlite3-dev
이번에는 /bin/sh: 1: autoreconf: not found
가 뜬다.
autoconf를 깔면 autoreconf도 같이 깔리는 듯 하다.
apt install -y autoconf
뭐지.. autoconf에러가 나버렸다.
autoreconf: /usr/bin/autoconf failed with exit status: 1
그래서 libtool이란걸 설치해봤다.
apt install -y libtool
http://sojro.tistory.com/entry/autoreconf-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%97%90%EB%9F%AC-%ED%99%98%EA%B2%BD-%EC%88%98%EC%A0%95 요런것들 해결이 되는듯..
이제는또 다른 에러가 나타났다.
fatal error: curl/curl.h: No such file or directory
이것도 설치..
sudo apt-get install libcurl-dev
이게 안되면
sudo apt-get install libcurl4-openssl-dev
https://stackoverflow.com/questions/11471690/curl-h-no-such-file-or-directory
이번에는 빌드시 시스템이 뻗어버린다. 아마 메모리가 터져서 그럴 것으로 생각되므로 Swap을 붙여서 빌드해봐야 할 것 같다.
http://www.spacek.xyz/mle/?p=375 위 글을 참조해서 2GB 스왑을 붙여보았다.
그리고 멀티 쓰레드로 실행하니 자꾸 에러가 나서, 싱글 쓰레드로 빌드를 해 보았다.
시간이 오래걸리긴 했지만, 정상적으로 완료가 되었다.
이제 각각에 필요한 플랫폼에서 빌드가 되었으므로, 추후 실행을 해 보고 소스코드를 작성하도록 하자.
IoTivity에서 센서나 구동기같은 엔티티는 OCF 리소스 모델에 따라 리소스로써 다루어진다. 각각의 리소스는 장치 타입, CRUDN 연산, URI 정보를 갖는다. 그리고 유저는 리소스를 URI와 RESTful 인터페이스로 접근할 수 있다.
IoTivity 네트워크 토폴로지에서 OCF 서버는 CRUDN 요청을 처리한다. 그리고 OCF 클라이언트는 리소스를 찾고 CRUDN 요청을 보낸다.
여기서 만들어볼 심플 서버, 클라이언트 구성은 다음과 같다. 서버는 온도, 습도 센서이다. 클라이언트는 안드로이드에 설치된 어플리케이션이다. 해당 소스의 레포지토리는 다음과 같다.
https://github.com/gudbooy/IoTivity_Sample_Things.git
해당 리포지토리의 readme 파일에는 다음과 같은 프로세스로 실시하라는 간략한 설명이 있다.
$ cd {iotivity_dir}/resource/examples
$ git clone https://github.com/gudbooy/IoTivity_Sample_Things.git
$ vim {iotivity_dir}/resource/examples/SConscript
Insert SConscript('IoTivity_Sample_Things/SConscript') in example's SConscript
IoTivity 프로젝트 디렉토리에 해당 Simple Server, Client 프로젝트를 클론한 뒤, SConscript에 스크립트를 삽입하라고 되어있다.
하지만 여기서 스크립트를 마지막 줄에 삽입한 이후 다시 빌드를 시도하면 제대로 되지않는다. 서브 프로젝트에서 scons로 빌드를 시도할 시, SConstruct를 찾지 못하고, 따라서 SConstruct가 있는 IoTivity 프로젝트 루트에서 시도를 할 시, thread_env를 찾지 못한다는 알 수 없는 에러가 발생하면서 빌드가 되지 않는다. 아직 원인은 찾지 못하였고 따라서 해결하지도 못했다.
해당 예제 코드를 참조하지 않더라도 IoTivity 프로젝트 자체에서 제공하는 예제 코드들이 있으므로 해당 예제 코드를 통해서 학습을 진행하기로 결정했다.
공식 문서 링크
SCons는 Software Construction Tool의 약자로, 크로스 플랫폼 빌드 툴이다. 고전적인 빌드 툴인 Make와는 다르게 기본적으로 C, C++, D, Java, Fortra, Yacc, Lex, Qt, SWIG, TeX와 같은 프로그램밍 언어와 문서들을 지원하고, 유저가 다른 언어에 대한 빌드를 원할 때에는 유저가 빌더를 정의해서 확장이 가능하다. 또한 다양한 OS, CPU 아키텍쳐를 아우르는 크로스 플랫폼 빌드를 지원한다.
구현은 실제로 파이썬으로 되어있으며, 파이썬과 유사한 SConstruct와 SConscript라는 파이썬 스크립트로 빌드 환경과 방식 등을 기술한다.
Make와는 다르게 쉘에 있는 환경을 그대로 가져오지 않으며, 스콘스크립트 내에서 환경을 정의하고 다른 스콘스크립트로 주고받을 수 있도록 되어있다.
환경 설정
환경이란 프로그램 실행에 영향을 끼칠 수 있는 모든 값들의 집합으로 정의된다. SCons에서는 이러한 환경을 3가지로 분류한다. SCons에서 분류되는 환경의 종류는 다음과 같다.
- External 환경
유저가 SCons를 실행할 때의 환경을 뜻한다. 스콘 스클비트에서는 파이썬의 os.environ에 저장된 변수들과 관계가 있다. - Construction 환경
Construction 환경은 SCons이 빌드를 하는 도중의 환경으로, 스콘스크립트 내에 생성된 객체들에 그 환경이 정의되어 있다. Construction 환경에는 타겟을 빌드하기 위해서 어떠한 행위를 해야하는지, 그리고 어떤 소스로 부터 빌드가 되어야 되는지도 포함된다. SCons의 강력한 기능 중 하나는 여러개의 Construction 환경을 만들 수 있다는 것이다. 기존의 환경을 복제하는 것도 가능하므로 기존 환경을 복제한 뒤 입맞에 맞게 바꾸어서 사용할 수 있다는 뜻이다. - Execution 환경
Execution 환경은 SCons가 타겟을 빌드하기 위해 외부 커맨드(컴파일러나 링커)를 실행할 때 사용되는 값들이다. 이 값들은 External 환경과는 다르다는 것을 알고 있어야 한다.
구매한 라즈베리파이에 운영체제를 업로드 해야한다. 업로드할 운영체제 이미지는 라즈베리파이에 적합하게 커스터마이징된 데비안 계열 리눅스인 라즈비안이다. 라즈비안은 다음 링크에서 다운로드 받을 수 있다.
라즈비안 다운로드 사이트 링크
라즈비안 다운로드 링크
Lite버전과 일반 버전이 있는데 일반 버전을 다운로드 하였다. 다운받은 이미지 데이터를 SD카드에 써야 하는데, 이 방법에 대한 라즈베리 파이 공식 홈페이지에서 제공하는 가이드 링크는 다음과 같다.
라즈비안 이미징 방법 링크
윈도우 계열 OS에서 이미징 작업을 할 때에는 Win32 Disk Imager를 사용하면 편리하다. 해당 소프트웨어는 다음 링크에서 다운받을 수 있다.
Win32 Disk Imager SourceForge 링크
위 절차를 통해서 라즈베리파이의 SD카드에 라즈비안 OS 이미징 작업을 완료하였다. 입력장치로 LED가 포함된 기계식 키보드를 사용할 시, 부족한 전원량으로 인하여 가끔씩 라즈베리파이가 꺼지는 현상이 있었다. 이러한 현상을 방지하기 위해서 LED가 없는 키보드를 사용하거나, Telnet이나 SSH와 같은 원격 쉘을 이용한 작업을 할 것이 권장된다.
라즈베리파이의 기본 유저 이름은 "pi"이고 초기에는 아무런 인증 없이 사용자 로그인이 되었다. 그리고 sudo su 명령어를 통해서 인증 없이 루트 권한을 취득할 수 있다. 이 상태에서 초기 패스워드를 지정해 주었다.
라즈베리파이에 고정 IP를 할당해주기 위해 네트워크 설정파일에 다음과 같이 기입한다.
네트워크 설정 파일의 경로는 다음과 같다.
경로 /etc/network/interfaces
source-directory /etc/network/interfaces.d
auto lo
iface lo inet loopback
iface eth0 inet manual
allow-hotplug wlan0
iface wlan0 inet static
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
address 192.168.35.135
netmask 255.255.255.0
gateway 192.168.35.1
홈 네트워크의 네트워크 IP 대역은 192.168.35.* 대역이며, 라즈베리 파이에 할당한 아이피 주소는 192.168.35.135이다. wpa-conf에 지정한 파일에는 자동으로 연결하는 무선 네트워크의 ssid와 패스워드, 그리고 암호화 방식이 지정되어 있다.
네트워크를 새로 설정해준 이후 재부팅하여 설정이 제대로 되었는지 확인해보았다. 원하는대로 IP주소가 설정된 것을 확인할 수 있었다.
라즈베리파이 3모델에는 위와 같이 192.168.35.135
IP주소를 할당하였고, 라즈베리파이 2모델에는 192.168.35.136
IP주소를 할당하였다.
또한 부팅 시 라즈베리파이에서 ssh 서버 서비스가 자동으로 구동되도록 하기 위해서 다음과 같은 명령어를 입력한다.
sudo systemctl enable ssh
이제 라즈베리파이에 카메라 모듈을 연결하여 동영상과 사진 촬영이 가능한지 확인해보도록 하겠다. 라즈베리파이에서 카메라 사용하는 설정과 관련된 블로그 링크는 다음과 같다. 라즈베리파이 카메라 설정 블로그
일단 카메라 사용을 enable해주어야 한다.
sudo raspi-config
TUI환경에서 5 Interfacing Options를 선택한다. 이후 1 Camera를 눌러서 enable해준다.
설정 이후 재부팅을 해주어야 한다.
다음 명령어로 사진을 찍어볼 수 있다.
raspistill -o [filename.jpg]
5초뒤에 촬영이 되며, 촬영을 해 본 결과 성공적으로 사진이 촬영되지만, 초점이 맞지 않고 파일의 용량이 지나치게 크다.
동영상 촬영 테스트는 다음 명령어로 테스트가 가능하다.
raspivid -o [filename.h264]
5초간 촬영이 되며, 지정한 파일이름으로 저장이 된다.
카메라가 제대로 설정된다면 ffmpeg을 이용해서 비디오 스트리밍이 가능하다. 라즈베리파이용 ffmpeg이 따로 없으므로 별도로 빌드를 해야 한다. 관련 블로그 링크는 다음과 같다.
라즈베리파이 ffmpeg 설치
ffmpeg의 빌드 파일중에서 ARM 아키텍처를 위한 prebuilt 파일은 없기 때문에 직접 소스코드를 통해 빌드를 해야 한다.
일단 의존성이 있는 H264 라이브러리를 설치한다.
git clone git://git.videolan.org/x264
cd x264
./configure --host=arm-unknown-linux-gnueabi --enable-static --disable-opencl
make -j2 # 코어 수에 따라 파라메터가 다르다
sudo make install
ffmpeg를 받아서 빌드한다.
git clone https://github.com/FFmpeg/FFmpeg.git --depth 1 # delta 정보를 빼고 불러온다.
cd FFmpeg
sudo ./configure --arch=armel --target-os=linux --enable-gpl --enable-libx264 --enable-nonfree
make -j2
sudo make install
카메라 장비를 /dev 디렉토리에서 확인을 할 수 있어야 한다. /dev/video0 에 파이 카메라가 인식이 되어야 하는데, 만약 나타나지 않는다면 다음의 조치를 통해 해결할 수 있다.
rpi-update # v4l2 드라이버가 사용가능한 버전으로 업데이트한다
modprobe bcm2835-v4l2 # /dev/video0를 로드하고 생성하기 위한 명령어
/dev/video0
가 제대로 동작하는지 확인하기 위해 다음 명령어로 사진을 찍어서 파일로 저장해볼 수 있다.
ffmpeg -f video4linux2 -s 640x480 -r 1 -i /dev/video0 -vframes 1 -f image2 image.jpg
사진이 정상적으로 촬영된 것으로 보아, /dev/video0에 파이카메라가 정상적으로 바인딩되었다는 것을 확인할 수 있다.
다음 명령어로 h264 비디오를 촬영할 수 있다.
ffmpeg -f video4linux2 -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -an test.h264
촬영 도중 q를 누르면 촬영을 종료한다.
출력 파일을 윈도우 시스템으로 옮긴 뒤, H264 확장자 파일을 재생할 수 있는 VLC 플레이어를 설치해서 재생해보도록 하겠다.
VLC플레이어 다운로드 링크
해당 플레이어로 재생을 하니 H264 확장자 파일을 잘 재생한다. 다만 사진과 비슷하게 파일에 초점이 잘 맞추어져 있지 않다.
영상 스트리밍 방식으로는 GStreamer, MJPEG 스트리밍등의 방법이 있다.
파이카메라 GStreamer
파이카메라 MJPEG 스트리밍
다양한 방법 중에서 적절한 방법을 골라서 CCTV 기능을 추가해보도록 하겠다.
IoTivity wiki에서 아두이노 지원과 관련된 문서에 따르면 지원하는 아두이노 버전과 설정은 Arduino ATMega 2560와 Arduino Due라고 나와있다. 여기서는 Arduino Due를 이용해서 진행하기 위해, 해당 보드를 구매하려고 한다.
해당 보드의 가격이 비싸고 구매 대행을 해야 할 것 같아서, 기존에 가지고 있는 Arduino Uno를 Raspberry pi와 GPIO로 Serial 통신을 통해 제어를 하고, 아두이노에는 IoTivity 어플리케이션을 올리지 않도록 하고 진행하기로 하였다.
IoTivity 시뮬레이터 구동 환경 구축
IoTivity 시뮬레이터는 리눅스에서만 지원이 된다. 현재 작업용 PC의 OS는 Windows 10이므로, 리눅스 작업은 가상머신에서 실시하도록 한다. 가상머신의 Guest OS는 Ubuntu 16.04 LTS 배포판을 이용하기로 한다.
IoTivity 시뮬레이터는 이클립스 플러그인 형태를 띠므로 일단 이클립스 먼저 설치하기로 한다. 이클립스는 이클립스 제단에서 주도적으로 진행하는 오픈소스 IDE 프로젝트이다. 자바로 작성되었으며, 오픈소스지만 강력한 기능을 제공한다. 또한 Windows, Linux, Mac의 플랫폼에서 동작한다.
시뮬레이터 설치와 관련된 링크는 다음과 같다.
IoTivity 시뮬레이터 유저 가이드
위 링크의 문서에 따르면 리눅스 플랫폼에서 4.4버전 이상의 이클립스가 필요하다.
이클립스를 설치하기에 앞서서 JDK가 설치되어 있지 않다면, JDK를 설치한다. OpenJDK 7버전 혹은 Oracle JDK를 설치하면 된다.
apt 패키지 매니저를 통해서 이클립스를 설치할 경우, 4.4 버전 이상의 최신 버전이 설치가 되지 않으므로 이클립스 공식 사이트를 방문하여 다운로드를 받는다. 만약 패키지 매니저를 통해 설치를 했다면 다음 명령어를 통해 삭제한다.
sudo apt-get --purge remove eclipse
이클립스 다운로드 링크는 다음과 같다.
이클립스 다운로드 링크
리눅스 64bit용 설치 파일을 다운로드하면 tar.gz 파일이 나타나게 된다.
다음 명령어로 압축을 풀어준다.
tar xvf [tar.gz file name]
압축을 풀면 폴더 안에 eclipse-inst
라는 ELF파일이 있다. 실행시켜서 이클립스를 설치할 수 있다.
Java IDE로 기본 설정대로 설치한다.
그리고 Eclipse를 실행하여 IoTivity Simulator 플러그인을 설치한다.
메뉴의 Help > Install New Software
를 선택한 뒤, Work with
항목에 다음 URL 중 하나를 입력한다.
- https://downloads.iotivity.org/tools/simulator/latest
- https://mirrors.kernel.org/iotivity/tools/simulator/latest
- ftp://mirrors.kernel.org/iotivity/tools/simulator/latest
매뉴 중Group itesm by category
를 체크 해제하고,Simulator
를 선택 후Next
를 누른다. 이후 나타나는 Simulator를 설치한다.
License에 동의한다고 체크한다.
Unsigned contents warning이 뜰 경우 OK를 눌러 계속 진행한다.
이후 Restart에 대한 내용이 나오면 Yes를 누른다.
시뮬레이터 플러그인이 설치된 후에, 시뮬레이터를 사용하려면 Open Perspective
를 눌러서 Client Controller
나 Service Provider
를 눌러서 진행하면 된다. 시뮬레이터는 두개의 관점으로 이루어져 있는데 IoTivity의 클라이언트 관점과 IoTivity 서버의 관점으로 이루어져 있다.
IoTivity를 활용하여 프로젝트가 진행 될 것이므로, IoTivity를 빌드 및 실행해보아야 한다.
IoTivity 빌드는 우분투 16.04 환경에서 진행한다.
IoTivity 우분투 빌드 가이드
IoTivity 빌드 가이드
빌드 환경 구축 커맨드
$ sudo apt-get -y install \
build-essential git scons libtool autoconf \
valgrind doxygen wget zip
git은 리눅스 토발즈가 만든 유명한 분산 버전관리 툴이다.
wget은 http 클라이언트의 구현체이다.
zip은 압축 유틸리티이다.
scons는 make의 뒤를 잇는 오픈소스 빌드 툴이다.
doxygen은 주석을 통해 자동적으로 문서를 만들어주는 도구이다.
valgrind는 메모리 디버깅 툴이다.
libtool은 컴파일된 포터블 라이브러리를 만드는 데 사용된다.
외부 라이브러리 설치 커맨드
$ sudo apt-get install \
libboost-dev libboost-program-options-dev libboost-thread-dev \
uuid-dev libexpat1-dev libglib2.0-dev libsqlite3-dev libcurl4-gnutls-dev
의존 라이브러리 설치(tinycbor, crypto lib)
$ git clone https://github.com/01org/tinycbor.git extlibs/tinycbor/tinycbor
$ git clone https://github.com/ARMmbed/mbedtls.git extlibs/mbedtls/mbedtls -b mbedtls-2.4.2
빌드
소스코드 받아오기
$ git clone https://github.com/iotivity/iotivity
릴리즈 버전 바이너리 빌드 커맨드
$ scons
디버깅 바이너리 빌드 커맨드
$ scons RELEASE=false
Verbose 모드
$ scons VERBOSE=true
클리어
$ scons -c
소스코드는 github에 공개된 소스코드를 git clone하여 받아서 사용하였다.
scons라는 빌드 툴을 이용하여 간단한 명령어로 빌드를 할 수 있다. i3-CPU 랩탑에서 수 분 정도 소요된다.
샘플 실행
$ export LD_LIRBRARY_PATH=<iotivity>/out/linux/x86_64/release
$ ./IotivitySample
샘플 코드를 실행하기 위해서는 공유 라이브러리(.so) 파일의 경로를 지정해주어야 한다. 인라인에서 "LD_LIBRARY_PATH"라는 환경변수의 설정을 통하여 라이브러리 위치를 지정해줄 수 있다.
bash 쉘 환경변수 고정 설정
LD_LIBRARY_PATH 환경변수를 고정적으로 설정하기 위해서는 /etc/bash.bashrc 파일에 값을 지정해주어야 한다. 다음 명령어를 실행하여 설정할 수 있다.
$ sudo echo "export LD_LIBRARY_PATH=/home/bobgil/Desktop/iotivity/out/linux/x86_64/release:$LD_LIBRARY_PATH" >> /etc/bash.bashrc
위 명령어를 적용한 후 새로 여는 터미널은 해당 환경변수가 설정된 채로 생성되게 된다. 해당 환경변수가 제대로 설정되었는지 확인하고 싶으면 다음 두가지 명령어 중 하나로 확인할 수 있다.
$ echo $LD_LIBRARY_PATH
혹은 다음 명령어로도 확인 가능하다.
$ env | grep LD_LIBRARY_PATH
env 명령어에 grep을 조합해서 사용하는 경우 LD_LIBRARY_PATH 내용을 전부 치지 않고, LD_ 정도의 해당 변수명의 부분문자열만 입력하여도 확인이 가능하다는 장점이 있다.
bashrc 파일에 입력한 환경변수 설정은 현재 열려있는 터미널에는 곧바로 적용되지 않는다. 만약 이미 열려있는 터미널에도 해당 설정을 적용하고 싶으면 다음 명령어를 입력하면 된다.
$ source /etc/bash.bashrc
IoTivity 샘플 코드에 대한 내용은 다음 링크에 담겨있다.
IoTivity Examples
샘플 코드 중 리소스 디스커버리 관련 샘플 소스코드를 확인해보자. 해당 소스코드는 다음 경로에 존재한다.
iotivity/out/linux/x86_64/release/resource/examples
사실 일반화되면 해당 경로는 다음과 같다.
[ProjectDir]/[TargetOS]/[TargetArch]/[BuildMode]/resource/examples
해당 디랙터리에 simpleclient 바이너리와 simpleserver 바이너리가 존재한다. 각각의 바이너리를 각자 다른 터미널에서 로컬 환경에서 구동해보면 어떤식으로 동작하는지 확인할 수 있다. 해당 예제를 인자 없이 실행하면, 다음과 같은 동작을 보인다.
- 서버는 클라이언트 요청이 오기 전까지는 Idle한 상태로 있는다. 클라이언트 요청이 오면 그에 맞는 응답을 준다.
- 클라이언트는 실행되면 리소스(서버)를 찾는다. 리소스를 찾고 나서 Notify 요청을 통해서 Observer에 등록한다. 이후 주기적으로 서버로부터 상태를 응답받는다.
- 이후 등록된 옵저버가 사라지면, 서버는 다시 Idle한 상태가 된다.
simpleserver의 소스코드를 한번 참조해보았다. example이 있는 SConscript, 즉 /iotivity/resource/example/SConscript를 확인해보니, example_names라는 리스트의 엔트리들을 examples_env.Program이라는 명령어로 빌드를 한다. 단일 cpp 파일로 빌드된다고 볼 수 있다. 따라서 simpleserver 바이너리는 simpleserver.cpp를 단일 빌드한 결과물로 볼 수 있다.
시작부분의 주석을 읽어보면, 이 샘플은 리소스를 위해 인터페이스를 정의하는 방법과, 리소스를 서버에서 제공하는 방법들을 보여준다고 한다.
소스코드는 740라인이지만, main 함수는 100줄이 채 되지 않는다. 처음 수십 은, 커맨드라인 인자를 통해 변수를 설정하고, PlatformConfig 객채를 만든 뒤 적절한 값을 넣고, OCPlatform::Configure 함수를 이용해서 Configure을 한다.
그리고 중간에 OC_VERIFY라는 함수가 있는데 이 함수는 No Debug 환경설정이 되지 않은 경우 assert를 하고, No Debug 환경이 설정되어 있는 경우 아무런 동작도 하지 않는 코드가 된다.
직접 선언한 SetPlatformInfo를 통해서 스트링들로 이루어진 플랫폼 정보를 지정한 뒤, OCPlatform::registerPlatformInfo 함수를 호출해서 플랫폼 정보를 등록한다.
그리고 SetDeviceInfo라는 함수를 호출해서 디바이스 정보를 하나하나 등록한다. SetDeviceInfo함수는 내부적으로 OCPlatform::setPropertyValue라는 함수를 값마다 등록한다.
이후 LightResource 클래스를 통해서 리소스를 생성하고, 타입과 인터페이스를 설정한다. 그리고 mutex, condition_variable, unique_lock을 이용하는 코드가 있는데, 코드 내용을 찾아보고 해당 코드 바로 위에 있는 주석들을 확인해보니. while(true); 와 같은 pending 코드와 같지만, non-processor intensive version이라고 한다. 즉, CPU Computing Power를 잡아먹지 않는, 코드의 진행을 방해하는 코드이다.
메인 함수를 확인해 보았을 때, simpleserver의 핵심 코드는 LightResource 클래스와 관련이 있어 보인다.
LightResource 클래스에는 createResource라는 멤버함수가 있는데, 주석에 따르면 이 함수는 궂이 멤버 함수로 지정할 필요가 없고, free function(non-member function)이어도 상관없다고 한다. 그리고 내부적으로 OCPatform::registerResource 함수를 호출한다. 해당 함수를 호출하는 것이 리소스 등록의 핵심 로직으로 보인다. 여태까지 계속 확인해온 바로는 OCPlatform 네임스페이스의 함수들이 리소스, 플랫폼, 디바이스 등록의 핵심적인 역할을 한다.
요청이 왔을 때 처리하는 부분은 entityHandler라는 함수로 정의한다. 특정 조건에 맞는 요청일 경우 쓰레드를 하나 만들어서 그 쓰레드에서 요청을 처리하도록 프로그래밍 되어있다.
IoTivity 안드로이드 어플리케이션 제작
이제 IoTivity의 대략적인 부분은 파악했으니, 일단 안드로이드 클라이언트부터 작성해보자. 안드로이드의 경우 일반적인 텍스트 에디터로 작업을 하면 개발이 어려운 부분이 있으므로 안드로이드 스튜디오로 작업하는 방법에 대해 알아보자. 다음 링크의 아랫 부분에 있는 Using IoTivity Base Android API in an Android Studio Project
부분을 참고하여 Windows 계열 플랫폼에서 안드로이드 스튜디오를 이용하여 IoTivity 안드로이드 앱을 제작할 수 있다. jar파일과 aar파일을 import하는 방식으로 간단하게 개발할 수 있다. jar파일은 자바 아카이브 파일이고, aar파일은 안드로이드 아카이브 파일이다. 안드로이드 라이브러리 파일은 AAR 파일로 컴파일된다. JAR파일과의 차이점으로는 안드로이드 리소스와 매니페스트 파일이 포함될 수 있다는 점이다.
안드로이드 라이브러리 관련 문서
IoTivity 안드로이드 앱 개발 관련 문서
일단 첫번째로 안드로이드 스튜디오를 설치한다. Windows 10에서 진행하였다.
기존에 iotivity 프로젝트 디렉토리에 있는 안드로이드 프로젝트를 그대로 임포트해서 사용해보려고 했는데 안드로이드 스튜디오 기반과 조금 차이점이 있는 듯 했다. gradle path 정보관련 메타 파일을 생성하고 하는 부분이 있는데, 이러한 점을 배재하기 위해서 별도로 안드로이드 스튜디오 프로젝트를 생성해서 진행하기로 했다. iotivity wiki에서도 이러한 방식을 추천했다. 따라서 다음 단계를 통해서 진행하였다.
-
안드로이드 스튜디오에서 프로젝트를 생성
-
타겟 디바이스를 테블릿과 스마트폰으로 지정
-
Minimum SDK를 API 21 Lolipop으로 설정
그 외 설정은 일반적인 안드로이드 스튜디오 프로젝트 생성과 비슷하다. -
이후 File - New - New Module 매뉴를 실행한다.
-
Import JAR/AAR Package를 선택한다.
임포트 하는 아카이브 파일의 경로는 다음과 같다.
<iotivity>/java/iotivity-android/build/outputs/aar/iotivity-base-<your arch>-<release mode>.aar
빌드가 되지 않은 경우 해당 아카이브 파일이 없다. 만약 다른곳에서 빌드를 한 뒤, 그 결과물인 aar파일을 git에서 관리하고자 하더라도, gitignore 파일에 build 디렉토리가 추가되어 있으므로, git에 의해 버전관리가 되지는 않는다. 따라서 해당 빌드된 aar파일만 별도로 가져와서 사용하기로 하였다.
- 왼쪽 프로젝트 디렉토리 구조에서 최상단의 app을 선택하고 우측 마우스 클릭을 누른 뒤, Open Module Setting을 선택한다.
- 상단 탭 중 Dependencies를 선택한다.
- 우측 상단의 + 버튼을 누른 뒤, 3번의 Module dependency를 선택한다.
- 나타나는 항목 중 :iotivity-base-release를 선택한다.
임포트한 내용들이 제대로 잘 동작하는지 확인하기 위해서 안드로이드 예제 코드 중, simple client를 구현해본 뒤 디바이스에 설치해서 결과를 확인해본다.
위 과정들을 진행해보니, scons로 빌드한 apk파일과 안드로이드 스튜디오로 만든 앱은 동일한 동작을 한다.
IoTivity 기능들
IoTivity는 다양한 Feature를 가지고 있다.
- Connection Abstraction : Gateway가 Bluetooth나 IP와 같은 다양한 network transport를 갖고 통신을 할 때 크게 상관하지 않고 쉽게 프로그래밍해서 통신하도록 해주는 feature이다.
- P2P Connection : RESTful API를 통해서 client와 server가 적절히 peer-to-peer 통신하는 기능이다.
- Scene Manager : 여러개의 Node에 대하여 필요한 설정(Scene)을 사전에 정의해서 한번의 동작으로 Multiple node가 약속된 동작을 하도록 설정할 수 있다.
- Resource Encapsulation : RESTful API를 이용해서 Remote Node를 제어하는것이 복잡하므로, 추상화된 계층을 하나 추가해서 쉽게 원격 노드를 제어할 수 있는 인터페이스를 제공한다.
- Resource Hosting : 리소스 호스팅은 Rich device가 Light Device에 대하여 subscribe를 해서 상태가 변할 때 알림을 받고, 그 리소스에 대한 정보를 자신이 캐싱하고 있는 것이다(Mirror Server). Consumer, Resource Hosting, Provider의 3개의 컴포넌트로 이루어진 아키텍쳐로 이해하면 된다. Resource Hosting이 Provider의 정보를 가지고 있다가(Caching) Consumer가 필요로 할 때 Hosting이 알려준다. 실제 리소스와 같은 정보를 같이 가지고 있는다. request에 대한 업무를 분담해준다.
- Resource Directory : Resource Hosting과 유사하지만 thin 장비를 위해 요청을 처리한다. Resource Directory가 Thin Device에게 오는 request를 대신 response한다. 대신해서 일을 처리한다.(Cached Server)
- Resource Container : 리소스 컨테이너는 OIC 리소스와 Non-OIC 리소스간의 호환성을 유지하도록 브릿지 역할을 한다. OIC 클라이언트는, OIC 서버 역할을 하는 리소스 컨테이너를 통해서 Non-OIC 리소스를 접근할 수 있다. 리소스 컨테이너는 네이티브 번들(라이브러리) 파일을 컨테이너 내부의 필요한 함수들로 mapping 시키는 방식으로 동작한다.
- IoTivity Cloud : 접근성을 로컬 네트워크에서 확장시키는 것이다. Easy-Setup으로 입력장치 없이 포장을 뜯지 않은 장비의 네트워크 설정을 쉽게 한다. Remote-Control으로 다른 네트워크 지역 간 리소스 서버와 클라이언트 통신이 가능하도로 한다. 두개의 통신은 클라우드가 매게한다. Service-Integration은 제3의 서비스 제공자가 리소스 서버를 보고 제어할 수 있도로 한다.
- Easy Setup Manager : UI가 없는 장비를 손쉽게 IoTivity 네트워크에 연결시키기 위한 기능이다. Easy Setup을 통해서 핵심 정보들을 장비에 전송할 수 있다. AP 정보, 장비 설정, 클라우드 접근 정보 등을 전송할 수 있다.
- Notification Service : Noti 서비스를 시작/정지하고 Noti 서비스를 찾고 구독한다. Notify 메시지를 보내고 Noti 메시지와 동기화한다. IoTivity 기본 API만 가지고도 Noti를 구현할 수 있으나 여러 문제가 있다. 이러한 점을 해결해줄 만한 feature를 많이 제공하는 것이 Notification service이다.
- Provisioning Manager : IP 서브넷에 있는 장비들의 보안 매니저역할을 한다. 소유권을 가지고 와서 ACL을 기반으로 접근통제를 한다. 크게 소유권 전환과 소유하는 장비에 대한 보안관리(비밀번호, ACL 관리)를 한다.
위와 같은 IoTivity Feature 중에서 사용할 것과 안할 것을 추려보자.
- Connection Abstraction : 별도로 여러개의 게이트웨이를 갖는 복잡한 네트워크 구성이 필요하지 않으므로 사용하지 않을 예정이다.(X)
- p2p Connection : 기본적으로는 사용할 예정이다.(O)
- Scene Manager : 사용해서 상황(Scene)에 따른 Multi Node의 동시적인 Configuration을 사용해볼 예정이다.(O)
- Resource Encapsulation : 사용할 수도 있으나, 일단은 사용하지 않을 계획이다.(X)
- Resource Hosting & Resource Directory : Resource Directory만 사용할 예정이다.(O)
- Resource Container : Non-OIC 장비를 사용하지 않을 것이므로, 사용하지 않을 예정이다.(O)
- IoTivity Cloud : 원격에서 제어가 가능하도록 사용할 예정이다.(O)
- Easy Setup Manager : 다른 AP에 설치가 가능하도록 사용할 예정이다.(O)
- Notification Service : 사용하면 좋으나, IoTivity Cloud에 대한 적용에 있어서 선택적으로 사용할 수도 있다.(X)
- Provisioning Manager : 보안성 향상을 위해서 사용하는것이 좋으나, 선택적으로 사용해볼 예정이다.(X)
[코딩 작업] 첫번째로 simpleserver.cpp를 기반으로 간단한 요청에 대해 응답하는 서버를 만들어 보기로 하였다. 필요없는 기능을 제거하고 필요한 기능을 추가하는 방식으로 진행하기 위해 einstrasse라는 별도의 디렉토리를 만들어서 테스트 해 보았다. 클라이언트 기능은 IoTivity Simulator를 이용하면 클라이언트를 직접 구현하지 않고도 간단하게 테스트 해 볼 수 있는장점이 있다.
Einstrasse라는 디렉토리를 만들어서 SConscript를 적절히 커스터마이징 하여 사용할려고 했는데, 원인을 알 수 없이 제대로 동작하지 않았다. SConscript가 적절하게 설정되지 않았기 때문으로 생각되어 example 디렉토리에 같이 lightserver.cpp를 만들어서 작업하기로 하였다.
Simulator에서 보낸 요청이 lightserver 어플리케이션의 entityHandler에 도달하지 조차 못하여서 몇일을 끙끙 싸매면서 원인을 파악하려고 노력해보았다. 확인해본 결과 Security Configuration관련된 문제로 알려졌다.
IoTivity Wiki 초기 설정
IoTivity wiki 보안 리소스 메니저
위 문서들을 참조하면 OCPersistentStorage를 설정하는 부분에 *.dat 파일에 대한 경로를 지정하는 부분이 있다. 그리고 보안 리소스 메니저 부분에 보면 해당 *.dat 파일에 내용을 토대로 ACL(Access Control List)를 만드는 등의 작업을 한다. 해당 cbor(Concise Binary Object Representation)파일에 있는 데이터를 토대로 보안 정책을 설립하는 것으로 보인다. 따라서 해당 파일에 href부분에 리소스 접근하는 URI를 설정해주지 않으면 entityHandler에 도달하지도 못하고 요청이 reject된다고 볼 수 있다.
해당 CBOR파일을 어떻게 만드느냐에 대한 고민이 있을 수 있는데 json파일 형태로 만들면, 같은 이름에 다른 확장자(.dat)로 scons으로 빌드 시 알아서 json2cbor 과 같은 툴을 이용해서 바이너리 형태로 바꾸어준다. 따라서 소스코드 작성과 더불에 적절한 configuration을 설정을 json파일로 해주어야지만 제대로 동작하게 된다.
IoTivity Wiki의 초기설정 문서를 참조하면, 서버에서 (Secure) 버전과 아닌 버전이 있다. PersistentStorage를 설정해주느냐 아니냐에 대한 차이인데, 해당 설정을 빼고 실행을 해 보았는데, 정상적으로 동작하지 않았다. 그래서 다음 명령어로 새로 빌드한 후 실행해 보았다.
scons resource SECURED=0
해당 빌드 커맨드로 빌드를 할 시, PersistentStorage를 Disable한 코드에서도 제대로 동작하게 된다. Default value는 SECURED=1이고, 그 경우 PersistentStorage에 접근 정책에 관한 JSON 파일을 빌드한 CBOR파일을 넣어주어야 정상적으로 동작한다. default가 secured인 것으로 보아 보안적으로 안전하게 제작하는 것을 권고하는 것으로 보인다.