Simple IoT accelerometer game Tutorial

2020/07/09 update : Node-Red설정
2020/07/15 update : 코드수정

1. Overview

디바이스의 센서데이터를 cloud상에 저장시키고, 저장된 데이터를 왓슨스튜디오로 분석하여 센싱데이터의 에너지 총량을 도출할 수 있는 application입니다.

IBM Developer blog에 게재된 “Create a fun, simple IoT accelerometer game“를 따라 진행해보도록 하겠습니다.

기대효과

  • IoT에 대한 흥미유발
  • IBM Cloud 사용법과, Watson Studio의 사용법 숙지
  • 다수가 모인 자리에서 킬링타임용 게임진행

2. Prerequisites

IBM CloudIBM Watson계정을 만들어주세요.
IBM Cloud : link
IBM Watson : link
+) 센서 데이터를 수집해야 하므로, 테스트할 기기로 스마트폰 또는 노트북을 지참해주세요.

3. Deploy Application

센서데이터를 수집할 수 있는 웹 애플리케이션을 클라우드상에 배포해보는 과정입니다.

다음 버튼을 클릭해서 IBM cloud상에 배포해봅시다.
Deploy to Bluemix

출처: romeokienzler/discover-iot-sample

cloud에 배포하기전 설정 화면이 나타납니다.
1

주의 : 주의해야할 점은 지역을 댈러스로 선택해야 한다는 것입니다. 댈러스 외의 다른 지역을 선택하면 앱을 실행하기 위한 몇가지 플러그인이 존재하지 않는 것 같습니다.

지역을 선택한 뒤, API키 작성을 눌러 API키를 생성하고 Deploy버튼을 눌러 앱을 클라우드상에 배포합니다.
2
3

Deliver Pipeline을 클릭해보면 github에서 가져온 코드가 클라우드상에 배포되고 있는 모습을 확인할 수 있습니다.
4

몇가지 설정을 바꾸기 위해 Deploy Stage의 단계구성을 클릭해줍니다.
5

아래 사진과 같이 입력유형을 Git 저장소, 분기를 master로 바꿔준 뒤 저장해 줍니다.
6
저장하고 난 뒤, 빌드부터 새로 재시작해줍니다.

앱이 정상적으로 가동된다면 앱URL방문을 클릭합니다.
7

방문하게 되면, Step1에 하나의 링크가 보이게 됩니다. 이 링크는 디바이스에서 센서데이터를 측정해서 화면에 띄워주는 웹기반 application입니다.
8
이 링크를 따라 접속해봅시다.

User의 Id와 Pw를 입력하고나면 연결되었다는 표시와 함께 Movement, Acceleration에 관한 센서값들을 확인할 수 있습니다.
9

4. Node-Red 설정

센서데이터를 클라우드로 가져오기 위해서, Node-Red라는 오픈소스 GUI flow 에디터를 사용하겠습니다. Node-Red를 통해 디바이스에서 송신되는 MQTT기반 데이터들을 DB에 저장할 것입니다.

app을 배포하게되면 클라우드 리소스리스트는 아래와 비슷하게 보일 것입니다.
image

Node-Red 배포

리소스 검색에서 Node-Red를 검색한 뒤, 생성해줍시다.

image

지역은 배포한 app이 있는 지역으로 맞춰주시기 바랍니다.
image

이런 식으로 화면이 뜨게 됩니다. 이제 Node-Red를 클라우드에 배치하기 위해 Continuous Delivery를 구성해주겠습니다.
우측의 앱배치를 눌러주세요.
image

API키는 신규 생성으로 만들어줍니다. 메모리는 기본으로 256MB가 할당되긴합니다. 최소요구량은 128MB이니 참고하시기 바랍니다.
image

DevOps 도구 체인 이름을 설정해주고 작성하기를 클릭 :
image

좀 기다리면 앱배치가 성공적으로 마무리 되고, 앱URL이 뜹니다.
image

배치하는 도중에 에러가 발생한다면 재배치를 눌러보세요.

Node-Red 초기 설정

배치가 성공하고나서 앱 URL을 누르게되면 Node-Red 앱으로 이동하게 됩니다.
초기설정을 해주겠습니다. id와 password를 설정해주고 Next:
image

초기설정을 마치면 Node-Red초기 페이지가 뜨게 됩니다.
image

IoT 모듈 추가

뒤에서 진행할 Node-Red플로우를 그리기 위해 필요한 IoT모듈을 Node-Red 노드에 추가해보겠습니다.

Deployment Pipeline에서 GIT을 선택해 Node-Red의 깃랩프로젝트로 이동합니다.
image

프로젝트 파일 중 package.json을 선택 :
image

dependencies에 다음 라인을 추가해줍니다.

 "node-red-contrib-scx-ibmiotapp": "0.x",

image

그리고나서 커밋해주면 자동으로 재빌드, 재배포 됩니다.
image

기본 서비스 연결

이제 이 Node-Red서비스와 IoT서비스를 서로 연동시켜줄 것입니다.

Node-Red 오버뷰의 서비스부분에서 기존서비스추가를 눌러서 위의 iot앱을 생성할 때 같이 생성되었던 IoT서비스를 추가해줍니다.
image

정상적으로 추가하고 나면 다음과 같은 화면이 됩니다.
image

그 다음, IoT서비스로 이동해서 연결 > 연결작성을 클릭합니다.
image

위에서 작성했던 Node-Red 앱 선택
image

리스테이징 선택:
image

이렇게 하면 IoT서비스와 Node-Red앱이 연동되게 됩니다.

5. Making Node-Red Graph

지금까지 과정은 단순히 클라우드에 앱을 배포하는 것입니다. 의미있는 데이터를 뽑아내기위해, 센서데이터들을 저장할 수 있는 DB가 필요합니다. 이번 챕터에서는 데이터들을 저장시킬 수 있는 DB설정에 대해 다뤄보겠습니다.

우선 Watson IoT Platform을 시작시킵니다.
13

실행시키면 왼쪽 메뉴가 가려져서 잘 안보이는데 마우스를 올리면 잘 보이게 됩니다. 자물쇠처럼 생긴 Security메뉴를 클릭합니다. 뜨는 리스트 중, 연결보안(Connection Security) 수정버튼을 클릭합니다.
14

Security Level을 TLS Optional(TLS 선택적)으로 변경시켜준 뒤, Refresh 시켜줍니다.

TLS Optional
TLS Optional에서는 장치가 TLS 1.1 이상과 연결하지 않을 때 네트워크 통신의 암호화를 강제 실행하지 않습니다. 비TLS 연결을 사용하면 네트워크에 있는 다른 사용자가 디바이스 신임 정보와 민감한 데이터를 볼 수 있습니다. TLS Optional을 통해 전송되는 데이터를 보호할 책임은 전적으로 사용자에게 있습니다.

저장하고 다시 IBM Cloud Foundry Apps로 돌아옵니다.
App URL방문을 통해 Node-Red를 실행시킵시다. 15

가이드에 따라 쭉쭉 진행한 뒤, 에디터 화면을 살펴보면 요상한 그래프들이 많이 보일겁니다. 다 지우고 아래 사진과 같이 세팅해 주세요.
16

IBM IoT노드의 Authentication을 Bluemix Service로 바꿔줍니다. 이는 IBM IoT node가 MQTT브로커와 연결하기위한 credential를 Cloud Foundry credentials injection을 통해 가져오겠다는 뜻입니다.
17
설정이 끝났다면 오른쪽상단의 Deploy버튼을 눌러줍니다.
이전에 배포했던 IoT app을 디바이스에서 실행시킨 뒤, Debug탭을 눌러 날아오는 msg들을 확인할 수 있습니다.
18
날아가는 데이터들은 discover-iot-try-serviceWatson IoT Platform>Divices탭에서 확인할 수 있습니다.
19

근데 msg가 object타입으로 날아와서 한눈에 알아보기가 힘드네요. function노드를 통해 msg를 꾸며봅시다.
18 5

//function에 들어가야 할 부분
msg.payload =
{
X : msg.payload.d.ax,
Y : msg.payload.d.ay,
Z : msg.payload.d.az,
SENSORID : msg.payload.d.id
}
return msg;

날아오는 데이터를 Debug탭에서 확인해보면 바뀐것을 확인할 수 있습니다.
20

이제 클라우드상에 데이터를 저장할 NoSQL DB로서 Cloudant를 추가시킵니다. db이름은 아무거나 설정해주시면 됩니다.

IBM CloudantApacheCouchDB에 기반하고 있습니다.

cloudant
21

추가적으로 데이터가 너무 빨리 송신되는 것을 막기 위해, delay node를 추가적으로 생성해 줍시다.
delay

노드의 전체 도식도는 다음과 같습니다.
image

이제 센서데이터를 송신받아 Cloudant에 저장하는 것까지 완성되었습니다!
하지만 단순히 데이터를 저장만 하는 것은 아무런 의미를 갖지 못합니다. 때문에 데이터를 분석하여 의미있는 값을 도출해 내는 것이 중요합니다.

6. Analyze Data with Watson Studio

watson studio

왓슨스튜디오를 처음 사용하는 유저는 먼저 상단의 Upgrade 버튼을 누른 뒤, Watson Studio와 Knowledge Catalog Bundle들을 설치해주세요.
image

새로운 프로젝트를 생성해 주세요.
22
23

프로젝트에 Object Storage를 추가해 줍니다.
24
25

추가하고나서 Refresh버튼을 눌러줍니다.
26

add spark

프로젝트를 생성하고 나서, Spark 서비스를 추가시킵니다.
27
28
프로젝트의 초기 설정은 끝!

notebook

다음은 실제로 어떻게 데이터를 분석할 것인지 정하는 Notebook을 구성해봅시다.
프로젝트 상단에 Add to project버튼을 눌러보면 Notebook을 생성하는 버튼이 있습니다.

이 튜토리얼은 하단의 github링크로부터 Notebook을 가져올 것입니다.

https://raw.githubusercontent.com/romeokienzler/developerWorks/master/boomboomshakeshakesparkv2.ipynb

image
runtime은 방금전에 만들었던 spark서비스를 가져옵니다.

Notebook에서 분석용으로 사용할 DB Connection을 만들어줘야 합니다. 다음 사진을 보고 project page로 돌아가줍니다.
30
Connection을 클릭하고, 만들었던 Cloudant를 클릭한 뒤, Create버튼을 클릭해줍니다.
image

다시 Notebook페이지로 돌아가서 하단의 코드블럭안에 Connection을 Insert합니다.

#PLEASE INSERT TO CREDENTIALS TO CLOUDANT HERE USING THE IBM WATSON STUDIO CONNECTIONS TAB RIGHT TO THIS NOTEBOOK
#이곳에 Insert

34

주의 : DB를 넣는 코드블럭 밑에 credentials을 참조하는 변수가 있습니다. credentials_1을 변수네임으로써 사용하고 있으므로 Connection을 Insert한 뒤, 이름을 credentials_1로 바꿔주어야 합니다.

코드를 RUN하기 전에 고쳐야할 부분이 몇가지 있습니다. 패키지를 다운로드 받는 부분인 첫번째 코드블럭을 봐주세요.

import pixiedust
pixiedust.installPackage("https://github.com/romeokienzler/developerWorks/raw/master/coursera/spark-sql-cloudant_2.11-2.3.0-SNAPSHOT.jar")
pixiedust.installPackage("com.typesafe:config:1.3.1")
pixiedust.installPackage("com.typesafe.play:play-json_2.11:jar:2.5.9")
pixiedust.installPackage("org.scalaj:scalaj-http_2.11:jar:2.3.0")
pixiedust.installPackage("com.typesafe.play:play-functional_2.11:jar:2.5.9")

위 코드의 첫줄인 github에서 패키지를 다운로드 받는 부분은 주석처리를 해야합니다.

#pixiedust.installPackage("https://github.com/romeokienzler/developerWorks/raw/master/coursera/spark-sql-cloudant_2.11-2.3.0-SNAPSHOT.jar")

첫번째로 예제로 올라온 링크가 유효하지 않다는 점.
두번째로 유효한 링크를 넣어도 ‘NoneType’ object has no attribute ‘strip’ 에러가 발생합니다.
없애도 정상적으로 돌아갑니다…

spark-sql-cloudant_2.11-2.3.0-SNAPSHOT.jar파일이 정확히 어떤 역할을 하고, 없어도 제대로 돌아가는 이유에 대해서는 파악하지 못했습니다.

다음으로 바꿔야 할 부분은 DB의 네임입니다.

df=spark.read.load({'cloudant의 이름'}, 'org.apache.bahir.cloudant')
df.createOrReplaceTempView('data')

이 튜토리얼에서 제가 썻던 이름은 harlemshake였으니 다음과 같이 구성될 것입니다.

df=spark.read.load('harlemshake', 'org.apache.bahir.cloudant')
df.createOrReplaceTempView('data')

수정해야할 부분을 수정했다면 Cell>Run All 버튼을 클릭합시다. image
Cloudant에 접속하여 데이터를 전송했던 id들의 리스트가 Notebook에서 정의했던 규칙대로 정렬된 모습을 확인할 수 있습니다.

에너지 총량 계산 방법 :

select sqrt(sum(X*X)+sum(Y*Y)+sum(Z*Z)) as energy, SENSORID from data group by SENSORID order by energy desc

image
energy값으로 내림차순

noteboot(without spark)

2020-07-13 수정

이번에는 스파크를 이용하지 않고 파이썬만 사용한 코드로 돌려보겠습니다.

ipynb파일은 아래 링크껄로 사용하겠습니다.

https://raw.githubusercontent.com/GRuuuuu/ghfhfflwjwkdth/master/Program/resources/boomboomm.ipynb

위와 비슷하게 진행해주시면 되고, 런타임으로 spark를 사용하는 대신 python3.x를 쓰시면 됩니다.

db connection 추가까지는 위 챕터를 참고해주세요.

해당 코드에서는 python-cloudant모듈을 사용하였습니다.

주 로직을 살펴보겠습니다.

from numpy.lib.scimath import sqrt
from pprint import pprint as pp

# dictionary타입의 변수를 생성
# 여기에 결과값들을 저장할 것
energy=dict()

# 아래 sql을 코드로 풀어낸 부분
# select sqrt(sum(X*X)+sum(Y*Y)+sum(Z*Z)) as energy, SENSORID from data group by SENSORID order by energy desc
for doc in df:
    e=(doc['X']*doc['X'])+(doc['Y']*doc['Y'])+(doc['Z']*doc['Z'])
    if(doc['SENSORID'] not in energy):
        energy.update({doc['SENSORID']:e})
    else:
        energy.update({doc['SENSORID']:e+energy[doc['SENSORID']]})

# value(energy)값들에 제곱근을 취해줌
for key, val in energy.items():
    energy.update({key:sqrt(val)})

# 내림차순으로 정렬
res=sorted(energy.items(),key=(lambda x:x[1]),reverse=True)

# value(energy)가 높은 순으로 출력
pp(res)

결과를 표로 이쁘게 출력하기위해 pandas를 사용하겠습니다.

from pandas import Series, DataFrame
import pandas as pd

data=pd.DataFrame(res)
data.columns=['userId','energy']
print(data)

표가 아래와 같이 출력됩니다.
image


댓글남기기