안녕하세요, "생각의 웹"입니다.


이번에는 갖은 시행 착오 끝에 설치를 완료한 NLTK를 활용해 IoT로 검색해 얻은 600 건의 트윗의 내용을 

word cloud로 만든 사례를 소개하고자 합니다.





이를 위해 python의 tweeter module을 이용해 아래와 같이 코딩했습니다.


# coding=UTF-8

import os.path
import json
import sys
import nltk

import collecttweets
import jsonreader

from collections import Counter
from prettytable import PrettyTable

##
# Get tweets from JSON dump file or twitter API
#
def get_tweets() :
	file_path = "tweets.json"
	if os.path.exists(file_path) :
		return jsonreader.read(file_path)
	else:
		return collecttweets.search_tweets_by_hash_tag('IoT', 5, 100)

##
# Tokenize all tweet messages
#
def tokenize(statuses) :
    status_texts = [ status['text']
        for status in statuses ]

    tokens = []
    for s in status_texts:
        tokens += nltk.tokenize.word_tokenize(s.lower())
    return tokens

##
# Get stemmed list
#
def get_stemmed_list(tokens) :
    from nltk.corpus import stopwords
    stop_words = stopwords.words('english') + ['.', ',', '--', '\'s', '?', ')', '(', ':', '\'', '\'re', '"',
        '-', '}', '{', u'—', 'rt', 'http', 't', 'co', '@', '#', '/', u'…',
        u'#', u';',  u'amp', u't', u'co', u']', u'[', u'`', u'`', u'&', u'|', u'\u265b', u"''", u'$', u'//', u'/'
        u'via',  u'...', u'!', u'``', u'http']

    from nltk.stem import PorterStemmer
    stemmer = PorterStemmer()
    stemmed = []
    for token in tokens:
        # try to decode token
        try:
            decoded = token.decode('utf8')
            #print decoded
        except UnicodeError:
            decoded = token

        if decoded is '' or decoded in stop_words:
            continue
        stem = stemmer.stem(decoded)
        #print stem
        # Skip a few text. I don't know why stopwords are not working :(
        #skip t.co things
        if stem.find(u't.co') > 0:
            continue
        #skip http things
        elif stem.find(u'http') >= 0:
            #print stem
            continue
        else:
            stemmed.append(stem)
    return stemmed

def write_file(filename, lines) :
    f = file(filename, 'w')
    for word in lines:
        try:
            f.write(word.encode('utf-8') + '\n')
        except UnicodeEncodeError, e:
            print 'Encoding error ' + word + '\n'
    f.close()

# Simple test
statuses = get_tweets()
tokens = tokenize(statuses)
print tokens
stemmed = get_stemmed_list(tokens)
print stemmed
write_file('word.txt', stemmed)



간략히 설명하면 

1) twitter API로 관심주제 (저 같은 경우는 IoT)로 tweet를 수집한다. 

2) tweet의 내용을 token으로 쪼개 모은다.

3) stemmer로 token를 분석해 불필요한 단어들을 제거한다. 

4) 남은 word들을 파일로 출력한다. 만들어진 word.txt를 아래 사이트에서 word cloud로 만들면 앞서 그림과 같이 예쁜 그림을 얻을 수 있습니다. 

(silverlight로 제작된 사이트니 IE에서 접속하는 걸 추천합니다 ;-) ) 

http://www.tagxedo.com/app.html 


이상입니다. 


감사합니다.

안녕하세요. "생각의 웹"입니다.




python 2.7.x 버전으로 twitter open API로 가져온 data를 자연어 처리 (Natural Language Processing - 이하 NLP)로 가공해 보여주는 프로젝트 수행 중 

제 windows 8.1 64bit 버전에서 관련 라이브러리 설치 중 발생한 문제로 

골머리 앓았던 사례와 그 해결 방법을 공유하고자 이렇게 글을 적습니다.


먼저 환결 설정에 필요한 도구들과 라이브러리는 다음과 같습니다.


python-2.7.msi (32 bit)

numpy-1.9.2-win32-superpack-python2.7.exe

nltk-3.0.1.win32.exe

PyYAML-3.11.win32-py2.7.exe

ez_setup.py

pycharm-community-4.0.5.exe


(주의!) NLTK 의 호환성 문제로 인해 64bit OS라도 32bit 버전을 설치해야만 합니다.


설치 순서는 다음과 같습니다.

1) python-2.7.msi 설치

2) ez_setup.py 파일을 python 설치 경로(e.g. C:\Python27)에 복사 후 terminal (cmd.exe)에서 'python ez_setup.py' 수행

3) Scripts 폴더로 이동해 'easy_install pip' 수행

4) 관리자 권한으로 numpy-1.9.2-win32-superpack-python2.7.exe 설치

5) 관리자 권한으로 nltk-3.0.1.win32.exe 설치

6) 관리자 권한으로 PyYAML-3.11.win32-py2.7.exe 설치


설치가 모두 정상 완료된 후 pip를 통해 python 모듈을 설치할 때 발생하며 다음과 같은 인코딩 에러가 출력됩니다.


UnicodeEncodeError: 'charmap' codec can't encode characters ...   


안타깝게도 이 메세지를 기반으로 다양한 검색을 통해 해결방법을 모색했지만 결국 해결책을 찾을 수 없었습니다.


그러던 중 지인 중 하나가 python IDE로 pycharm를 추천하길래 혹시나 하는 마음에 pycharm IDE을 설치하게 되었고 

이 도구 안에서도 모듈 설치 기능을 제공함을 알게 되었습니다.


7) pycharm-community-4.0.5.exe 설치


pycharm 설치가 완료되고 수행하면 설치된 python 버전과 python 프로젝트를 만들 수 있는 시작화면이 나옵니다.

임의의 프로젝트를 생성하여 작업환경으로 진입합니다.


pycharm은 Intellij IDE 기반으로 만들어진 IDE라 eclipse IDE와는 메뉴 구성이 달라 어색할 수도 있습니다.

모듈을 추가하기 위해서는 File > Settings 메뉴로 진입합니다.



좌측 메뉴 항목에서 Project: ... / Project Interpreter 를 선택하면 설치된 패키지들이 나열됩니다.

우측 + - 버튼을 통해 패키지를 추가, 삭제 할 수 있는데 이렇게 설치하게 되면 terminal에서 발생하는 에러 없이 패키지 설치가 가능합니다.




사족으로 pip 설치 시 발생하는 원인은 모듈이 설치되는 경로에 한글 경로가 포함되기 때문인 것으로 보입니다.

혹시나 이런 문제로 인해 저와 같은 삽질하시는 분들께 도움이 되길 바라는 마음으로 공유합니다.


감사합니다.



안녕하세요. "생각의 웹"입니다.


2월 9일(월) 15:00~18:00 강남역 근처 강남토즈 타워점에서 개최한 제 34차 W3C 대한민국 관심 그룹 회의 참석 후기를 공유하고자 이렇게 포스팅합니다.

http://onoffmix.com/event/41031 


이번 회의에서는 KIG를 이끌고 있는 이원석 박사님의 주관으로 W3C 표준화가 한창인 service worker, ETRI의 hybrid web platform인 HyWAI 소개 및 이를 이용한 web bluetooth app 개발 사례에 대해 다뤘습니다. 계획 상으로는 W3C CEO인 Jeff Jaffe가 참석할 예정이었으나 급작스런 부친 상으로 모든 일정을 취소하고 귀국한 관계로 대면할 기회를 갖지 못해 아쉬웠습니다. 각 세션에 앞서 이원석 박사님은 올 해 KIG 정기 회의를 통해 HTML5 최신 기술 동향 및 hybrid app 개발 사례에 포커스할 예정이며 공개로 진행되는 만큼 많은 참석과 의견 교류를 바란다고 말씀하셨습니다.



첫 번째 세션으로 service worker spec의 editor이자 삼성전자 책임 연구원인 송정기 님이 발표한 사례를 들어 알기 쉽게 정리한 service worker 입니다. 
발표자에 따르면 service worker API를 통해 개발 가능한 기능은 크게 오프라인 우선 지원(offline first)백그라운드 수행(background processing)을 통한 푸시 알림(push notification) 두 가지 입니다.
오프라인 우선 지원의 경우, service worker의 API와 개발자의 필요에 따라 캐쉬(cache)를 생성할 수 있는 전역 cache API 및 WHATWG에서 표준화 중인 fetch event를 처리하는 API를 통해 HTTP 요청(request)의 프록시(proxy) 역할을 수행하는 service worker를 구현할 수 있습니다. 이는 URL을 입력하거나 링크를 클릭하는 요청(client request)이나 AJAX 요청 혹은 내부 리소스 요청(resource request) 등을 대신하는 proxy를 service worker로 등록함으로써 offline 환경에서 캐쉬 데이터로 브라우징이 가능하도록 한 것으로 이에 대한 자세한 API 사용 사례(usage)는 spec. editor의 한 명이자 구글의 엔지니어인 jake의 블로그를 읽어 보기를 바랍니다. HTML5Rocks에 도창욱 님이 번역한 글도 참고하면 좋습니다.현재 구현이 상당 부분 진행되어 Chrome 40 버전 이상 혹은 Firefox의 nightly version에서 약간의 환경 설정을 통해 테스트 가능합니다. 마지막으로 service worker에 대한 spec 진행 사항에 대한 알고 싶은 분들은 트위터에서 @jungkee 를 follow 하고 spec 자체를 github를 통해 작성하고 있으니 자유롭게 의견을 개진할 수 있습니다.
시간 관계 상 백그라운드 수행을 통한 푸시 알림 기능은 다루지 못한 관계로 추후 KIG에서 이 부분에 대해 다룰 예정이라고 합니다.

두 번째 세션은 Hybrid Web Application Interface를 줄인 HyWAI (하이웨이)에 대해 ETRI 전종홍 책임 연구원 님이 발표했습니다. 이 프로젝트는 PhoneGap 이 발표된 시점인 2009년 1.0을 시작으로 현재 3.5 버전에 이르렀으며 3.5 버전의 경우 re-engineering를 통한 구조 개선 및 BT/BLE를 포괄하는 Web Bluetooth API가 주안점이라고 합니다. 
ETRI 정책 상 open source로 진행할 수 없어 간략한 sample app을 mobile2.tistory.com/8 에 공개했으니 다운로드 받아 써 볼 수 있습니다.


세 번째 세션은 HyWAI 프로젝트를 수행한 엠트리 소프트의 신현진 이사님의 HyWAI를 통한 Web Bluetooth app 개발 사례 소개입니다. hybrid app 개발 사례 소개에 앞서 hybrid app 개발 시 경험한 이슈 사항들을 공유해 주셨는데 그중 cross platform 지원 시 web view 호환성 및 파편화 문제(fragmentation issue)가 심도 있게 다뤄졌습니다. 특히   Crosswalk, wkwebview (iOS) 프로젝트는 지켜 볼만한 오픈소스 프로젝트라고 합니다. 데모 앱으로 구글이 주창한 BLE 기반의 physical web 사용 사례 (use case)를 hybrid app으로 구현해 bluetooth로 전송한 URL를 실행하는 과정을 코드와 함께 시연했습니다.


이상입니다.

이후 소개된 발표 자료가 공유되면 업데이트하도록 하겠습니다.



감사합니다.


 

생각의 웹입니다.


벌써 한 해의 마지막 날이 되었습니다. 

마지막이라는 생각이 드니 미뤄두었던 일들을 서둘러 마무리해야 한다는 생각이 들어 

최근 알게 된 웹 API 시작부터 끝까지 라는 주제의 읽어 볼만한 좋은 포스팅을 공유합니다.


 그 시작으로

Matt McLarty의 비즈니스 관점에서의 웹 API

라는 포스팅을 간략하게 한글로 요약합니다. 



  • 내부 데이터의 가용성 수준 평가 척도
    1. 데이터 적용 가능성
      • 이 데이터가 핵심 비즈니스 목표를 추구하는데 도움이 될 것인가?
      • 이 데이터가 비즈니스를 차별화 해주는가?
      • 이 데이터를 공개해서 상품화할 예정인가?
    2. 데이터 정확성
      • 이 데이터는 현재 어떻게 제공되고 있는가?
      • 이 데이터가 권위있는 출처에서 오는 것인가?
      • 올바른 목적으로 올바른 사용자가 사용하는 데이터인가?
    3. 데이터 접근성
      • 프로그래밍하기 위해 어떤 데이터가 적합한가?
      • 이 데이터를 사용하기 위한 다른 방법은 무엇인가?
      • 개발자들이 이 데이터를 이용하는 앱들을 만들기에 얼마나 쉬운가?
      • 많은 클라이언트의 요청을 수용할 만큼 데이터 처리 용량을 늘릴 수 있는가?
  • 평가 결과에 따라 두 종류의 API가 존재
    1. 유용한 API
      • 정확하고 응용할 수 있는 데이터를 제공
        • “medium is the message” thinking fails - APIs and Open Data만으로는 충분치 않다.
        • right data through right APIs - brings desired revenue and innovation benefits
        • 사례
          • Google Maps
          • SNS (Twitter, Facebook, ...) API - 선거 유세에도 영향을 미칠 정도로 영향력이 커짐
          • 아마존 사례
            1. 제품과 솔루션 공급을 API를 통해 할 수 있게 함
            2. 가치있는 데이터를 수집, 분석, 개선, 배포하는 API 기반 접근을 수행함
              • CEO 제프 베조스 曰 우리는 물건을 팔 때 돈을 버는 것이 아니라 고객들로 하여금 구매를 결정할 수 있게해서 돈을 법니다. (“We don’t make money when we sell things. We make money when we help customers make purchase decisions.” - Jeff Bezos )
              • Envision -> Focus -> Disrupt -> Iterate -> Persist -> Broaden -> Envision -> ...
            3. 전략적인 포지셔닝과 전술적인 공급 간의 균형을 유지하는 단련된 방식이 존재
          1. 지속적으로 응용 가능한 데이터를 수집
          2. API를 데이터에 대한 보편적 접근 법으로 이용
          3. 단기적으로 필요한 것 뿐 아니라 장기적으로 명확히 필요한 것을 제공
          4. 강점(position of strength)에서 부터 확장하라
    2. 가용한 데이터
      • 사용할 수 있는 데이터를 제공
      • 엔터프라이즈 앱 개발의 패러다임 변화
        • n-tiered web model to API centered topology
        • Java EE to JavaScript
      • Twilio 사례
        • 임의의 통신사의 SMS 이나 VOIP를 사용할 수 있는 API를 개발자에게 제공하여 수익 창출
      • Ingenie 사례
        • 16~25세의 고객이 보유한 스마트폰을 통해 수집한 운전 데이터로 자동차 보험 요금을 줄여주는 서비스 제공
      • API 설계의 중요성이 부각
        • 새로운 개발자들에게 API 사용성 증대를 통해 API 사용을 촉진할 필요성 대두
  • 요약
    1. 비즈니스 전략에 맞춰 API를 정비하라
    2. API를 통해 접근 가능하고 정확하고 응용가능한 데이터를 제공하라
    3. API가 유용하고 사용할 수 있도록 만들라
    4. 아마존처럼 데이터를 통해 가능한 분열(Data-Enabled Disruption)이 반복되는 문화를 수립하라
    5. Twilio 처럼 비즈니스를 다른 대형 경쟁사들과 차별화하는 API 개발자 경험을 만들라



모든 것이 연결되는 초연결 사회로 향해 가는 시점에서 

웹 API를 통한 메시업(mesh-up)를 비즈니스 시작부터 염두해 두지 않고는 더 이상 지속적으로 경쟁력 있는 서비스를 

도출할 수 없는 시대가 되고 있습니다.


올바른 이해를 기반한 전략 수립과 기민한 실천으로 미래 사회의 개척자가 되길 희망합니다.

감사합니다.   




안녕하세요. 

"생각의 웹"입니다.


지난 AppIN 세미나를 통해 소개했던 Do IoT Yourself 프로젝트를 기반으로 

thermistor 대신 온습도 센서(DHT11)를 달아 며칠 간 안방의 온습도 트랜드를 측정해 보았습니다.


먼저, 검색해 보니 계절 별로 생활하기 적정한 온/습도에 관련 내용이 있더군요.


실내 적정 온도와 습도


 지금과 같이 겨울철에는 적정온도 18~21도, 습도 40% (알레르기 비염환자의 경우 50%)라고 하는군요.



사실, 이 프로젝트를 적극적으로 시작한 계기는 

제 아내와 아이들이 알레르기 비염 증상이 있어 잠자는 도중에 재채기를 심하게 하는 경우가 많아서 입니다.

(가끔 저도 같은 증상을 겪기도 했습니다.)


비염을 예방하기 위해서 가.성.비가 탁월하다는 공기청정기를 구매해 사용하니 

방 안 먼지 때문에 나오는 재채기는 줄어 들었으나 

잠자는 도중 하는 재채기가 줄어들지 않더군요.


따라서 잠자는 도중 하는 재채기의 원인을 온,습도의 변화로 지목하고

제 때 물 갈기가 귀찮아서 사놓고 방치했던 가습기를 켠 상태에서 

방 안의 온, 습도를 모니터링하기로 결정했습니다.


다음은 날짜 별로 온습도 변경 기록 및 요약입니다.




11월 18일



- 시스템 설치 첫 날 오후 2시 경부터 온습도 기록을 시작했습니다. 온도는 23도에서 +- 2도 정도의 변화를 보였습니다. 

   보일러의 목표 온도가 22도로 맞추어져 있기 때문에 추워지면 보일러가 돌아간 것으로 보입니다. 


- 가습기의 목표 습도를 50%로 설정하고 잠자리에 들기 전부터 가동했습니다.


- 가습기를 가동한 저녁부터 습도가 34%에서 37%로 증가했습니다.

  가습기 자체에 습도계가 있어 목표 습도인 50%가 되면 습기량이 줄어들고 

  습도가 다시 낮아지면 습기량이 느는 동작을 반복합니다.


- 다행히도 가습기를 튼 당일부터 잠자는 도중 하던 재채기가 사라졌습니다. 

  적용 첫날부터 효과가 있는 걸로 보아 기침의 원인은 습도였나 봅니다. ^^




11월 19일



- 밤, 새벽 시간 온도는 22도 수준을 유지하다 낮에는 24도 수준으로 올라갔습니다.


- 가습기가 동작하던 오전 9시 경까지 습도가 36~37%를 유지하다 가습기를 끈 낮에는 34% 수준으로 떨어졌습니다.


- 가습기가 동작한 저녁 8시부터 습도가 다시 2% 정도 증가했습니다. (여전히 목표 습도는 50% 입니다.)



11월 20일


- 11월 19일과 유사한 환경에서 오전만 측정했습니다. 

   (오후에는 시스템 개선 작업을 진행하느라 잠시 꺼두었습니다. ^^a )


- 밤 12시에 24도에서 점차 떨어져 새벽 6시 경에는 21도가 되었다가 해가 뜨니 25도까지 올랐습니다.


- 가습기가 동작한 밤에는 습도가 37% 수준에서 유지되다가 아침에 가습기를 끄니 34% 수준으로 떨어졌습니다.



11월 21일


- 온도가 밤부터 새벽 시간에는 23도에서 머무르다 낮이 되니 25도까지 올랐다가 다시 밤에는 23도로 돌아왔습니다.


- 가습기가 동작할때의 습도는 35~37%, 가습기를 끄면 34%까지 내려갑니다. 

  안방의 습도는 34% 수준에서 평형을 유지하는가 봅니다. 



11월 22일


- 온도가 밤부터 아침까지 22도에서 24도로 올랐다가 낮에 25도가 되었습니다.

  그날 따뜻했는지 21일보다 1도 정도가 더 높네요.


- 습도는 가습기가 동작하는 밤에는 37%였다가 가습기를 꺼두어도 35~36% 수준을 유지했습니다.



11월 23일


- 온도가 새벽 2시부터 올라 23도에서 26도까지 올랐습니다. 아침 10시경 외출했더니 낮임에도 불구하고 23도로 내려왔습니다.


- 가습기의 목표 습도를 60%로 설정하고 동작했음에도 습도는 35~6% 수준에서 

  머물러 있습니다. 



마무으리~로 지난 시험의 결과를 요약해 보면


- 방 안의 온도가 겨울철 적정 온도(18~21도)보다 3~5도가 높아서 너무 따뜻하게 지내는 것일 수 있을 듯 합니다.

  난방비를 생각해서 희망 온도를 22도에서 20도로 줄이는 걸 고려해 봐야 겠습니다.     


- 습도는 가습기를 동작시켜도 적정 습도인 40%에는 부족한 37% 수준까지만 올라갑니다. 

  희망 습도를 60%으로 올리더라도 습도 변화에 큰 차이가 없는 걸 보니 가습기의 습도계를 믿어선 안될 듯 싶네요.

  비염 환자를 위한 적정 습도인 50%까지 올리려면 지속적으로 가습기를 켜 두어야 할 것 같습니다.


이 측정을 하기 전에는 

바닥에서 자는 아내가 새벽에 코가 시릴 정도로 춥다고 해서 난방 온도를 올리는 방향으로 결정했으나 

측정 결과, 난방 온도를 올리면 상대적으로 습도가 낮아지고 온도 차에 의한 순환 때문에 외풍이 부는 것처럼 느껴지는게 아닐까 하는 의심이 들었습니다.


따라서, 오늘 밤부터는 난방을 줄이고 가습을 더 하는 방향으로 시험해서 체감 온도를 느껴봐야 겠습니다.


이처럼 단순히 온도 (+습도)를 측량하는 간단한 D.IoT.Y 기기만으로도 작지만 의미있는 일들을 

(가정에서 부터) 시작할 수 있습니다.


여러 분들도 손쉽게 D.IoT.Y 하시면서 비용도 줄이고 건강도 챙기는 일석이조의 효과 얻기를 바랍니다.

여기까지 읽어 주셔서 감사합니다.


행복한 (그리고 건강한) 겨울철 보내시길!


"생각의 웹"입니다.


지난 Do IoT Yourself 강연 시 가장 널리 알려진 MySQL를 이용해서 data logging를 했으나 

프로그래밍에 문외한인 분들에게 교육하기 어려운 점과 

MySQL과 같은 RDMS (관계형 데이터 베이스 시스템)과 JavaScript의 궁합이 썩 맞지 않는 면들이 있었습니다.

불편한 점들을 나열하면 다음과 같습니다.


- MySQL 설치가 까다롭다.

- database를 설정하고 schema를 만드는 과정에서 실수하기 쉽다. (error-prone)

- JavaScript 객체 (JSON)의 속성들을 일일히 DB 스키마에 맞춰 저장한 뒤 읽어 들일 때 JSON 객체로 만들어 주는 과정이 필요하다.

- JavaScript Date 객체와 DB의 Date 객체는 호환되지 않는다.

 


따라서, NoSQL 중 하나인 mongoDB를 대안으로 사용하기로 결정했습니다. 그 이유는 다음과 같습니다.


- database를 설정하고 schema를 만드는 과정이 필요 없다.

- JSON 객체로 저장하고 읽어 들인다.


제 개발환경인 windows 8.1에서는 msi 형태의 설치 파일을 통해 별도의 설정 없이 손쉽게 설치가 가능했으나 

실행 환경인 raspberry PI는 조금 복잡하고 오랜 과정이 필요했습니다.


다음은 설치 과정을 정리한 포스팅입니다.


http://c-mobberley.com/wordpress/2013/10/14/raspberry-pi-mongodb-installation-the-working-guide/


영어의 압박이 있어 보이지만 순서대로 따라하면 큰 무리 없이 설치가 가능합니다.

다만, 어디서나 mongo 콘솔을 사용할 수 있도록 설정하는 부분이 빠진 것 같아 다음과 같이 추가합니다.


sudo ln -s /opt/mongo/bin/mongo /usr/bin/mongo


설치된 mongoDB 버전이 2.1.1 에 불과하다는 포스팅도 있으나 사용하고자 하는 기능에는 크게 무리가 없을 듯 합니다.


이번 포스팅은 여기까지 입니다.

감사합니다.



안녕하세요, "생각의 웹"입니다.


앞서 라즈베리 파이에 WiFi USB dongle 설치한 포스팅을 공유한 바 있습니다.

라즈베리 포럼을 뒤지다 당시 라즈베리안 커널 버전에 맞는 드라이버를 컴파일해서 dropbox로 제공해준 MrEngMan 덕분에 일단 사용할 수 있게 되었지요.


그러나, 문제는 커널이 업그레이드 될 때마다 해당 커널 버전으로 빌드한 드라이버를 구해서 수작업 설치를 해야 한다는 문제가 있었습니다.

무심코 아래와 같이 라즈베리파이의 커널 업그레이드 후 재부팅을 하니 더 이상 와이파이 동글이 사용할 수 없는 상태가 되어 버렸습니다. ㅠ.ㅠ.


sudo apt-get update
sudo apt-get upgrade
sudo reboot -t NOW


문제의 원인을 찾기 위해 로깅 메세지를 보니 MrEngMan이 제공한 드라이버가 커널과 호환되지 않았습니다.

당시엔 (지금도) 드라이버를 빌드하기 위해 필요한 절차를 이해하지 못하고 있었기 때문에 제가 할 수 있는 최선은 라즈베리파이 포럼에 해당 버전에 맞춰 드라이버를 컴파일해 달라는 읍소형 댓글을 다는 것 뿐이였습니다.


그런데 안타깝게도 몇 달이 지나도록 댓글이 달리지 않더군요.


결국 어쩔 수 없이 Ethernet으로 연결하여 사용하던 중 다시 와이파이가 필요한 상황이 되어 다시 한번 (용기를 내어) 구글링하기 시작했습니다.


그 결과, 다행히 N150UA에 사용된 WiFi 칩셋인 MediaTek-MT7601의 드라이버를 라즈베리파이에서 빌드하는 법을 정리한 포스팅을 발견해 기쁜 마음에 링크를 공유합니다.


http://groenholdt.net/Computers/RaspberryPi/MediaTek-MT7601-USB-WIFI-on-the-Raspberry-Pi/MediaTek-MT7601-USB-WIFI-on-the-Raspberry-Pi.html


상기 포스팅 내용을 한글로 재 정리하면 다음과 같습니다.

// root 계정으로 변경
sudo -s

// 최신 version download
apt-get update
apt-get upgrade
rpi-update

// 리눅스 커널 소스 코드 다운로드
cd /usr/src
git clone https://github.com/raspberrypi/linux.git
sudo ln -s /usr/src/linux /lib/modules/`uname -r`/build
cd linux

// 현재 수행 중인 시스템 커널 설정으로 지정
make mrproper
zcat /proc/config.gz > .config
cp .config .config.org
make modules_prepare


// 커널 모듈 심볼 다운로드 (커널 재 컴파일을 막기 위함)
wget https://raw.github.com/raspberrypi/firmware/master/extra/Module.symvers

// MT7601 USB 드라이버를 압축해제
cd ~ 
tar -xvjpf DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2 
cd DPO*


드라이버에서 엄청난 양의 로그를 뱉기 때문에 이를 막기 위해서 os/linux/rt_linux.c 파일에서 다음 문장을 수정합니다.

ULONG RTDebugLevel = RT_DEBUG_TRACE; 
ULONG RTDebugLevel = 0; // RT_DEBUG_TRACE; 

마지막으로 드라이버를 빌드하고 인스톨 합니다.

make
make install


혹시 이전 제 포스팅에서 설명한 방식대로 driver를 설치하신 분은 최종 설치 과정 (make install) 전에 이전 드라이버를 삭제해 주셔야 합니다.

제거 명령은 다음과 같습니다.


sudo rm -rf /etc/Wireless/RT2870STA

감사합니다.

안녕하세요, "생각의 웹"입니다.


앞서 아두이노 보드와 Node.js를 이용해 RESTful Web API와 JavaScript API를 제공하는 Do IoT Yourself 프로젝트를 소개한 바 있습니다.

문득 누군가 이와 유사한 프로젝트를 이미 하지 않을까 하는 생각이 들어 'arduino rest api'로 구글링해 보았습니다.

(친절한 구글 신은 자동 완성 기능을 통해 이런 프로젝트가 존재할 것이라는 제 예상에 힘을 실어 주었습니다.)


그 결과 발견한 프로젝트가 바로 aREST - arduino REST의 축약으로 보입니다. - 입니다.


http://arest.io/


상세 내용에 앞서 이 프로젝트를 통해 가능한 데모 영상 하나 보시죠. 




아직 사이트의 컨텐츠가 모두 완성되지 않은 상태로 보이나 (docs 메뉴에 가보면 under construction으로 되어 있습니다)
공개된 소스 코드의 README 파일이나 블로그에 포스팅 된 내용으로 보아 충분히 사용 가능한 수준으로 보입니다.

간략하게 정리하면 먼저 이 프로젝트는 다음과 같은 특성을 가지고 있습니다.



- REST API를 통한 아두이노 제어 가능

// 1. Connect a LED & resistor to pin number 8 of your Arduino board
GET 192.168.2.2/mode/8/o  // 2. Set the pin 8 as an output
GET 192.168.2.2/digital/8/1 // 3. Turn on LED

- 다양한 아두이노 보드 지원

  : Uno, Mega, Due, Yun and Teensy 3.x.

  

- 다양한 connectivity 지원

  : USB나 XBee를 통한 Serial 통신

  : CC3000 WiFi chip를 통한 HTTP 통신

  : Ethernet shield를 통한 HTTP 통신

  : nRF8001 chip를 통한 Bluetooth Low Energy 통신


- multicast DNS 프로토콜 지원으로 discovery 가능

  : Bonjour 서비스 필요


http://arest.io/ 를 보면 arduino library, Node.js module, JavaScript client 세 프로젝트로 구분되어 있는데 각각의

코드를 상세 검토(deep dive) 해 보면 다음과 같이 요약할 수 있습니다.


- arduino library: aREST의 핵심 모듈입니다. arduino IDE 프로젝트 파일 (*.ino)로 다양한 connectivity 하에서 

http server 기능을 C/C++로 구현하고 있습니다. 


- Node.js module: serial 통신을 통해 연결된 arduino 보드와의 gateway server 역할


- JavaScript client: aREST의 API를 호출하는 AJAX 코드


마무~으리로 이 프로젝트의 장/단점을 정리해 보겠습니다.  


- 장점

  : 다양한 connectivity를 지원합니다. 필요한 요구사항에 맞춰 가져다 쓸 수 있다는 점은 매우 매력적입니다.

  : 아두이노 보드(+ Ethernet or WiFi chip) 만으로도 독립된 인터넷 노드를 만들 수 있습니다.

  : 통신 시 전송량이 적은 JSON respresentation를 사용합니다.


- 단점

  : 보다 복잡한 기능을 추가하기 위해서는 arduino IDE를 통해 펌웨어를 업데이트해야 합니다.

    아두이노 펌웨어에 올릴 수 있는 코드 용량이 한정되어 있는 것으로 알고 있기에 제한을 받으리라 보입니다.

  : 제공하는 REST API의 성숙도 수준이 낮습니다. 

    상태를 변경시키는 unsafe 행위(e.g. LED를 켬)를 GET 명령으로 수행하고 있습니다.

    앞서 포스팅한 리처드슨 REST 성숙도 모델에 따르면 Level 1에 해당하며 클라이언트 프로그래밍 시 오류를

    야기시킬 수 있습니다.

  : 라이센스가 GPL입니다. 상업적인 목적으로 사용하시려는 분은 GPL이 모든 소스코드와 함께 빌드 방법까지 공개해야 하는 점을 유념하시기 바랍니다.  



이번 포스팅은 여기까지 입니다.

감사합니다.

안녕하세요,

"생각의 웹"입니다.


혹시 지난 "AppIN 세미나 - Do IoT Yourself" 강연에 참석하시고 꾸준히 이 블로그에 방문해 주시는 분들이 계신가요?

글을 시작하기 앞서 그 분들께 먼저 감사 말씀드립니다.


이번 포스팅에는 D.IoT.Y 두 번째 강연 시 대디스랩 송영광 대표님과 함께 만들었던 온도센서를 JavaScript로 구현해보고자 합니다.

이 강연은 다음 포스팅을 참조하시기 바랍니다.


Intuitive Understanding Arduino for IoT: Do IoT Yourself 2nd



여기서 실습한 온도 센서 만들기는  Sparkfun Starter Kit for RedBoard에 내장된 센서/엑추에이터로 한정해야 했기에 가격이 저렴한 서미스터 센서(Thermistor)로 기능을 구현하기 위해 arduino IDE에서 꽤 복잡한 코딩을 해야 했습니다. 


다음 코드는 실습 당시 복사/붙여넣기 했던 코드입니다.


#include <avr/pgmspace.h>

int led_state;
unsigned long time;

#define THERM_PIN   0  // 10k thermo & 10k resistor as divider.

/*
 *  Big lookup Table (approx 750 entries), 
 *  subtract 238 from ADC reading to start at 0*C. 
 *  Entries in 10ths of degree i.e. 242 = 24.2*C Covers 0*C to 150*C 
 *  For 10k resistor/10k thermistor voltage divider w/ therm on the + side.
 */
const int temps[] PROGMEM = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
    15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
	34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 
	69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 
	87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 
	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 
	115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 126, 127, 
	128, 129, 130, 131, 132, 133, 134, 134, 135, 136, 137, 138, 139, 140, 
	141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 
	153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 164, 165, 
	166, 167, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 
	178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
	190, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 202, 
	203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 
	215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 
	228, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 239, 
	240, 241, 242, 243, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 
	252, 253, 254, 255, 256, 257, 258, 259, 260, 260, 261, 262, 263, 264, 
	265, 266, 267, 268, 269, 269, 270, 271, 272, 273, 274, 275, 276, 277, 
	278, 279, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 289, 
	290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 301, 302, 
	303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 315, 
	316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 
	330, 331, 332, 333, 334, 335, 335, 336, 337, 338, 339, 340, 341, 342, 
	343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 
	357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 
	371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 
	385, 386, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 398, 399, 
	400, 401, 402, 403, 404, 405, 406, 407, 408, 410, 411, 412, 413, 414, 
	415, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 
	430, 432, 433, 434, 435, 436, 437, 438, 439, 441, 442, 443, 444, 445, 
	446, 448, 449, 450, 451, 452, 453, 455, 456, 457, 458, 459, 460, 462, 
	463, 464, 465, 466, 468, 469, 470, 471, 472, 474, 475, 476, 477, 479, 
	480, 481, 482, 484, 485, 486, 487, 489, 490, 491, 492, 494, 495, 496, 
	498, 499, 500, 501, 503, 504, 505, 507, 508, 509, 511, 512, 513, 515, 
	516, 517, 519, 520, 521, 523, 524, 525, 527, 528, 530, 531, 532, 534, 
	535, 537, 538, 539, 541, 542, 544, 545, 547, 548, 550, 551, 552, 554, 
	555, 557, 558, 560, 561, 563, 564, 566, 567, 569, 570, 572, 574, 575, 
	577, 578, 580, 581, 583, 585, 586, 588, 589, 591, 593, 594, 596, 598, 
	599, 601, 603, 604, 606, 608, 609, 611, 613, 614, 616, 618, 620, 621, 
	623, 625, 627, 628, 630, 632, 634, 636, 638, 639, 641, 643, 645, 647, 
	649, 651, 653, 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, 674, 
	676, 678, 680, 683, 685, 687, 689, 691, 693, 695, 697, 700, 702, 704, 
	706, 708, 711, 713, 715, 718, 720, 722, 725, 727, 729, 732, 734, 737, 
	739, 741, 744, 746, 749, 752, 754, 757, 759, 762, 764, 767, 770, 773, 
	775, 778, 781, 784, 786, 789, 792, 795, 798, 801, 804, 807, 810, 813, 
	816, 819, 822, 825, 829, 832, 835, 838, 842, 845, 848, 852, 855, 859, 
	862, 866, 869, 873, 877, 881, 884, 888, 892, 896, 900, 904, 908, 912, 
	916, 920, 925, 929, 933, 938, 942, 947, 952, 956, 961, 966, 971, 976, 
	981, 986, 991, 997, 1002, 1007, 1013, 1019, 1024, 1030, 1036, 1042, 
	1049, 1055, 1061, 1068, 1075, 1082, 1088, 1096, 1103, 1110, 1118, 1126, 
	1134, 1142, 1150, 1159, 1168, 1177, 1186, 1196, 1206, 1216, 1226, 1237, 
	1248, 1260, 1272, 1284, 1297, 1310, 1324, 1338, 1353, 1369, 1385, 1402, 
	1420, 1439, 1459, 1480, 1502 
};


void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(19200);
  time=millis();
  //Serial.println("Ready");
}

void loop() { 

  int therm;   
  therm = analogRead(THERM_PIN) - 238;
  therm = pgm_read_word(&temps[therm]);
  
  //Serial.println(therm, DEC);
  float temp = (float)therm / 10.0;
  Serial.println(temp, 1);
  
  if (millis()-time > 1000) {   
    time = millis();
    digitalWrite(13,led_state);
    led_state =! led_state;
  }
  delay(2000);
}

약간 코딩 지식이 필요하기에 실습 시에는 많은 설명이 되지는 않았지만 여기서 조금 설명하자면
 look up table를 만들어 A0에서 읽어들인 값을 table에 있는 값에 대응해서 serial로 출력하는 logic이 되겠습니다.


보시듯, 여기서 이 프로그램의 logic의 핵심은 look up table을 어떻게 만들었는가이고 

이에 대한 답변은 table를 만들기 위해서는 서미스터 혹은 하드웨어 부품들에 대한 이해가 필요하다는 것입니다. 

즉 아래의 그림처럼 서미스터의 데이터 쉬트에서 table이 도출되었습니다. (송영광 대표님이 엑셀 신공을 사용하셨다고 하더군요. ^^a) 


서미스터는 회로 구성을 어떻게 했는가에 따라 (즉, 어떤 저항을 달았느냐)에 따라 다른 값을 내어 놓습니다. 

다시 말해 이 값은 위의 그래프에서 온도 X일때의 Y값과 같은 형태로 나옵니다.

하드웨어의 경우 물리의 세계에 닿아 있기에 재료의 특성과 환경에 따라 영향을 받기에 로직 만으로 이해하고자 하는 SW 쟁이는 이해하기 쉽지 않죠.  


따라서, 사실 원하는 동작을 얻기 위해서는 arduino 회로를 적절히 구성할 뿐 아니라
arduino IDE를 이용해 관련 로직을 구현한 후 해당 프로그램(속칭 펌웨어)을  

arduino 에서 전송해 테스트해 보는 일을 반복해야 합니다.


여기서 문제는 arduino에 이 동작 외에 추가로 기능을 구현해야 할 경우, 

반드시 arduino IDE로 펌웨어를 업드레이드해 주어야 합니다. 

이는 꽤 불편한 일이 아닐 수 없습니다. 


쓰다 보니 문제 제기로만으로도 꽤 길어졌는데 이에 대해 제가 제시하는 해결책은 다음과 같습니다.


1. arduino의 펌웨어에 호스트(host)의 명령을 처리해 동작을 수행하는 인터프리터(interpreter) 를 전송합니다.


2. 호스트는 arduino에 명령을 전송합니다. (e.g. A0 포트에서 아날로그 값을 읽어 오기)


3. 인터프리터는 명령을 받아 동작을 수행 후 결과를 호스트에 전송합니다.



혹시, 이 방식을 어디선가 본 듯한 느낌을 받은 분이 있나요? ;-)

앞서 소개한 바와 같이 이 방식으로 구현된 node.js 모듈이 바로 duino 입니다.   


관련 포스팅 : http://webofthink.tistory.com/13



이번에는 duino 모듈로 이 똑같은 동작을 수행해 보도록 하겠습니다. 


먼저, 아래 파일을 다운로드 받기 바랍니다.


duino.zip

(이 모듈은 현재 버전인 v0.0.9를 조금 수정해서 DHT11 센서 지원 및 윈도우즈에서 동작하도록 수정 확장한 버전입니다. 리눅스나 OS X는 기존 버전을 써도 무방합니다.)


이 파일의 압축을 풀어 src/du/du.ino 파일을 실행합니다. 

(먼저 Arduino IDE가 설치되어 있어야 합니다. 참고바랍니다.)


해당 arduino 펌웨어를 arduino 보드에 다운로드합니다.


정상적으로 전송되면 이제 node.js로 동일한 역할을 하는 코드를 구현해 봅니다.

코드를 다음과 같이 작성해 temp.js로 저장하고 콘솔에서 node temp 로 실행합니다.


var arduinoPort = 'COM7'; // only works in windows with patched duino module.
var pinName = '00'; // it means A0 pin

// look up table for resolving data to the appropriates temperature
var temps = [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
    15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
	34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 
	69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 
	87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 
	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 
	115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 126, 127, 
	128, 129, 130, 131, 132, 133, 134, 134, 135, 136, 137, 138, 139, 140, 
	141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 
	153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 164, 165, 
	166, 167, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 
	178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
	190, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 202, 
	203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 
	215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 
	228, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 239, 
	240, 241, 242, 243, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 
	252, 253, 254, 255, 256, 257, 258, 259, 260, 260, 261, 262, 263, 264, 
	265, 266, 267, 268, 269, 269, 270, 271, 272, 273, 274, 275, 276, 277, 
	278, 279, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 289, 
	290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 301, 302, 
	303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 315, 
	316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 
	330, 331, 332, 333, 334, 335, 335, 336, 337, 338, 339, 340, 341, 342, 
	343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 
	357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 
	371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 
	385, 386, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 398, 399, 
	400, 401, 402, 403, 404, 405, 406, 407, 408, 410, 411, 412, 413, 414, 
	415, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 
	430, 432, 433, 434, 435, 436, 437, 438, 439, 441, 442, 443, 444, 445, 
	446, 448, 449, 450, 451, 452, 453, 455, 456, 457, 458, 459, 460, 462, 
	463, 464, 465, 466, 468, 469, 470, 471, 472, 474, 475, 476, 477, 479, 
	480, 481, 482, 484, 485, 486, 487, 489, 490, 491, 492, 494, 495, 496, 
	498, 499, 500, 501, 503, 504, 505, 507, 508, 509, 511, 512, 513, 515, 
	516, 517, 519, 520, 521, 523, 524, 525, 527, 528, 530, 531, 532, 534, 
	535, 537, 538, 539, 541, 542, 544, 545, 547, 548, 550, 551, 552, 554, 
	555, 557, 558, 560, 561, 563, 564, 566, 567, 569, 570, 572, 574, 575, 
	577, 578, 580, 581, 583, 585, 586, 588, 589, 591, 593, 594, 596, 598, 
	599, 601, 603, 604, 606, 608, 609, 611, 613, 614, 616, 618, 620, 621, 
	623, 625, 627, 628, 630, 632, 634, 636, 638, 639, 641, 643, 645, 647, 
	649, 651, 653, 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, 674, 
	676, 678, 680, 683, 685, 687, 689, 691, 693, 695, 697, 700, 702, 704, 
	706, 708, 711, 713, 715, 718, 720, 722, 725, 727, 729, 732, 734, 737, 
	739, 741, 744, 746, 749, 752, 754, 757, 759, 762, 764, 767, 770, 773, 
	775, 778, 781, 784, 786, 789, 792, 795, 798, 801, 804, 807, 810, 813, 
	816, 819, 822, 825, 829, 832, 835, 838, 842, 845, 848, 852, 855, 859, 
	862, 866, 869, 873, 877, 881, 884, 888, 892, 896, 900, 904, 908, 912, 
	916, 920, 925, 929, 933, 938, 942, 947, 952, 956, 961, 966, 971, 976, 
	981, 986, 991, 997, 1002, 1007, 1013, 1019, 1024, 1030, 1036, 1042, 
	1049, 1055, 1061, 1068, 1075, 1082, 1088, 1096, 1103, 1110, 1118, 1126, 
	1134, 1142, 1150, 1159, 1168, 1177, 1186, 1196, 1206, 1216, 1226, 1237, 
	1248, 1260, 1272, 1284, 1297, 1310, 1324, 1338, 1353, 1369, 1385, 1402, 
	1420, 1439, 1459, 1480, 1502
];


var arduino = require('duino');
var board = new arduino.Board({
    device: 'COM7',
    debug: false //true
});



board.on('ready', function () {
    console.log("arduino board is ready to serve.");
    board.pinMode(pinName, 'in');
    
    setInterval(function () {
        console.log('request to get an analog value from ' + pinName);
        board.analogRead(pinName);
    }, 1000);
});

board.on('data', function (message) {
    // message looks like {pin}::{data}. so it will be disassembled properly.
    var m = message.slice(0, -1).split('::'),
        err = null,
        pin, data;
    
    if (!m.length) {
        return;
    }
    
    pin = m[0];
    data = m.length === 2 ? m[1] : null;

    console.log('reading value from pin' + pin + ': ' + data );
    if (pin === pinName) {        
        var converted = temps[parseInt(data) - 238] / 10.0;
        console.log('current temperature is ' + converted + ' degree of celsius');
    }
});


C:\tests>node temp.js
arduino board is ready to serve.
request to get an analog value from 00
reading value from pin00: 489
current temperature is 23.5 degree of celsius
request to get an analog value from 00
reading value from pin00: 489
current temperature is 23.5 degree of celsius
request to get an analog value from 00
reading value from pin00: 489
current temperature is 23.5 degree of celsius
^C
C:\tests>


단순히 보면 위의 코드가 앞서 arduino 펌웨어의 코드보다 더 간략해 보이지 않지만, 

이 코드는 세번 째 강연으로 진행했던 사물 간의 연결을 위한 Open API에서
다루었던 serialport 모듈의 기능을 포함하고 있습니다.

(즉 비슷한 코딩 량으로 두 가지 일을 한번에 한 것입니다.)


이외에도 앞서 문제로 제기했던 것들의 해결책으로써 

호스트에서 arduino 원격 제어와 펌웨어 업데이트 없이 추가 기능 구현이 가능해 졌습니다. 


더 나아가 이를 RESTful Web API와 JavaScript API 형태인 Open API로 재 설계한다면
웹을 통해서 아두이노를 원격 제어하는 게 가능해 집니다.


마지막으로 사족을 붙여 보겠습니다.


아래 포스팅을 통해 사물과 사물 간의 대화를 위해서는 수 많은 기술적 제약들이 현재 존재함을 말씀드린 바 있습니다.


- 사물 인터넷을 지탱하는 것 

- 사물 인터넷은 어떻게 생각하게 될까?


저는 이 장벽을 푸는 첫 번째 기술적 열쇠로 자바스크립트 언어를 바라보고 있습니다. 

이 언어를 사용하는 많은 개발자들이 존재하면서도 지적 재산권(IP) 문제에 자유롭고 계속적으로 기능이 향상되고 있기 때문입니다.


최근 뉴스에 등장한 오라클과 구글의 안드로이드에서의 자바 언어 사용 관련 특허 분쟁은 사물인터넷 시대를 맞이 할 우리에게 시사하는 점이 많습니다.

처음 기술을 개발한 세력이 개방과 공유를 빙자해 전파하더라도 나중에 가서는 그것을 사유화하려고 할 것이기 때문입니다. 


그러나 우리는 지난 사반세기 동안 이런 사유화를 막고 지구적 공동체를 만들어낸 훌륭한 사례를 본 적이 있습니다. 

따라서 웹과 arduino가 그러했듯이 오픈 소스 소프트웨어오픈소스 하드웨어가 초연결 사회로 나아가는 축으로 자리 잡길 기대합니다.


감사합니다.  


안녕하세요,

"생각의 웹"입니다.


AllJoyn Framework (이하 올조인)은 퀄컴에서 개발한 P2P 기술을 오픈 소스로 공개 후 AllSeen Alliance (이하 올신) 주관으로 리눅스 재단의 프로젝트로 진행하는 만물 인터넷 (사물 인터넷보다 한단계 더 나아간 개념입니다만 저는 아직까지는 동의어 혹은 파생어로 봅니다.  ) 프레임 워크입니다.


이 기술을 공개된 지도 일 년이 지난 것으로 기억하는데 가장 최근인 올 해 7월 IFA 2014에서 공개한 데모에 대해 정리한 포스팅이 있어 올조인에 대해 아직 문외한인 분들은 읽어 보면 좋을 것 같아 링크 공유합니다.


퀄컴 올조인으로 물꼬튼 올신의 현재 (칫솔 - 초이의 IT 휴게실)  



올조인의 가장 긍정적인 면은 처음부터 누구나 소스 코드를 사용할 수 있도록 공개하고도 더불어 다양한 플랫폼 개발자들을 위해 여러 프로그래밍 언어의 API 문서와 프로그래밍 가이드를 잘 정리해 두었다는 점입니다.


튜토리얼: https://allseenalliance.org/alljoyn-framework-tutorial



오픈소스의 영향으로 인지는 모르겠지만 간단한 검색어를 통한 구글링으로도 꽤 많은 관련 포스팅이 눈에 띄는데 아래 '바쁜척쟁이 개발자의 블로그'에 기능 별로 잘 정리되어 있는 것 같아 살펴 보시길 추천합니다.


http://busydeveloper.tistory.com/category/Alljoyn



개인적으로 아쉬운 점이자 이 포스팅을 쓰게 된 동기는  official site의 가이드에는 JavaScript API가 준비되지 않았다는 점입니다.

개발 이력을 살펴 보니 NPAPI를 이용해 browser에서 사용 가능한 API를 만들려는 시도가 있었다가 실패한 듯 하고 (github에서 관련 프로젝트가 없어졌더군요.) 
대신 아래 경로처럼  node.js를 위한 npm 모듈이 존재하는 것을 확인했습니다.


https://github.com/octoblu/alljoyn


따라서, 현재 클라이언트의 주변에서는 올조인 기기들을 찾을 수 없겠지만 node.js를 탑재한 모바일 기기나 
클라이언트와 node.js 서버가 같은 네트워크 상에 있다는 가정 하에서는 Open API를 통해 기기 간 통신이 가능할 것으로 보입니다.


각론으로 들어가면 사실 올조인의 API는 P2P 개념이 부족한 분들에게는 조금 생소할 수도 있습니다.

하는 역할인 기기 간 통신에 비해 복잡해 보이기도 하고요. 

각 인터페이스들의 역할과 상호 작용의 개념을 명확히 이해하기 위해 먼저 위의 튜토리얼을 읽어 보실 것을 권합니다.

어느 정도 동작 방식에 대해 이해 하셨나요? 아래 코드는 위의 깃허브의 샘플 코드에서 유추해서 Web IDL 형태로 간단히 정리해 본 JavaScript API 입니다.

 


typedef DOMString AllJoynAppName; 

callback SignalMessageCallback = void (DOMString message, DOMString info);
[Constructor (DOMString appName)]
interface BusAttachment {

    void createInterface(AllJoynAppName name, InterfaceDescription description);

    void registerBusListener(BusListener listener);

    void start();

    void connect();

    void findAdvertisedName(AllJoynAppName name);

   void registerSignalHandler(BusObject bus, 
       SignalMessageCallback  smcb,
       InterfaceDescription description, 
       DOMString signalType);
};

[Constructor ()]
interface InterfaceDescription {

    void addSignal(DOMString target, 
        DOMString messageType,
        DOMString message);
};

callback FoundAdvertisedCallback = void (DOMString name);
callback LostAdvertisedCallback = void (DOMString name);
callback NameOwnerChangedCallback = void (DOMString name);

[Constructor (FoundAdvertisedCallback facb, 
    LostAdvertisedCallback lacb, 
    NameOwnerChangedCallback nocb)]
interface BusListener {
};

[Constructor (DOMString busName)]
interface BusObject {

    void addInterface(InterfaceDescription description);
};

callback AcceptSessionJoinerCallback = void (unsigned short port, AllJoynAppName joiner);
callback SessionJoinedCallback = void (unsigned short port, DOMString sessionId, AllJoynAppName joiner);

[Constructor (AcceptSessionJoinerCallback asjcb, SessionJoinedCallback sjcb)]
interface SessionPortListener {
};

문서화 수준과 지원하는 OS (유닉스 계열 - OS X, linux 만 지원)이 부족한 것으로 보아 아직 신뢰할 만한 수준이 아닌 것으로 보입니다.
즉 이 모듈을 사용할 때 각자가 해야 할 삽질이 정해져 있다는 것을 의미합니다. -_-;; 


어쨌든 올신에는 꽤 많은 기기 제작업체가 가입해 있고 슬슬 호환 기기들도 출시를 앞두고 있은 것 같아 기존 레거시 시스템들과 혹은 올신에 가입하지 않는 업체들의 기기와의 대화를 위해 인터프리터 역할을 할 노드가 필요하리라고 예측합니다.

추후 좀 더 구체화된 내용이 있으면 포스팅하도록 하겠습니다.


감사합니다.


행복한 하루 되시길! 

+ Recent posts