본문 바로가기

OpenSource HW/포고플러그(PogoPlug)

포고플러그로 집안온도 모니터링하기.

포고플러그는 참으로 활용도가 높은 기기입니다.

포고플러그에 방안 온도측정 기능을 추가해 보겠습니다.

(* 포고플러그는 ArchLinux설치가 되어있는 상태입니다.)



먼저, 포고플러그는 온도센서가 없습니다.

그러니 온도를 측정할수 있는 것이 필요합니다.

손쉽게 센서를 물려서 사용하기 편한 아두이노(ARDUINO)가 필요합니다.

(사진의 아두이노는 아두이노Pro 입니다. 어떤 버전의 아두이노든 상관없습니다.)

아두이노 에서 온도를 측정하고, 시리얼을 통해(USB) 온도측정값을 포고플러그에 전달해주는 것이지요.

포고플러그에서는 시리얼로 전달된 온도값을 사용하여 사용자에게 인터넷으로 알려주거나,

또다른 방법으로 사용할수 있습니다.

저의경우는, 제가 사용하는 웹호스팅 MySql 데이터베이스에 기록을 하였습니다.

그렇게 쌓인 데이터를 가지고 온도 그래프를 보여주는 간단한 웹페이지를 만들어 보았습니다.



이렇게 하면, 집 밖에서도 스마트폰으로 집안 온도를 볼수가 있습니다.

아두이노에 컨트롤 센서등을 추가하게되면 집밖에서 직접 보일러를 컨트롤하는 것도 만들수가 있겠죠.


우선, 간단하게 집안 온도측정만 해보도록 하겠습니다.

아두이노와 온도센서가 필요합니다.

온도센서는 종류가 아주 많으니 각자 마음에 드는 것으로 선택합니다.



저의경우는, DS18S20 센서를 사용하였습니다.

온도센서의 전선을 길게 뺏는데 아무래도 디지털방식이 긴 거리에 좀더 나을거 같아서 입니다.


아두이노에서 SD18S20 센서를 사용하는 방법은

http://bildr.org/2011/07/ds18b20-arduino/

를 참고하시기 바랍니다.


아두이노에서는 간단하게 온도를 측정해서 시리얼로 온도값을 보내주도록 프로그래밍 합니다.

이부분은 자신이 어떻게 만드느냐에 따라 달라질수 있겠습니다.

5분마다 주기적으로 시리얼로 온도를 보낼수도 있을것이고,

1분마다 보내게 할수도 있습니다.


이런식으로 연결하면 됩니다.



#include <OneWire.h>
#include <SoftwareSerial.h>
#define RxD 11
#define TxD 12


byte sensor[8] = {0x10, 0xB3, 0x90, 0x8A, 0x02, 0x08, 0x00, 0xE9}; //온도센서 주소값

OneWire  ow(2);    // 2번핀(Digital)에 온도센서 신호선 연결


void setup(void) {
  pinMode(RxD, INPUT);
  pinMode(TxD, OUTPUT);
  Serial.begin(9600);
  lookUpSensors();
}


void writeTimeToScratchpad(byte* address){
  //reset the bus
  ow.reset();
  //select our sensor
  ow.select(address);
  //CONVERT T function call (44h) which puts the temperature into the scratchpad
  ow.write(0x44,1);
  //sleep a second for the write to take place
  delay(1000);
}
 
void readTimeFromScratchpad(byte* address, byte* data){
  //reset the bus
  ow.reset();
  //select our sensor
  ow.select(address);
  //read the scratchpad (BEh)
  ow.write(0xBE);
  for (byte i=0;i<9;i++){
    data[i] = ow.read();
  }
}
 
float getTemperature(byte* address){
  int tr;
  byte data[12];
 
  writeTimeToScratchpad(address);
 
  readTimeFromScratchpad(address,data);
 
  //put in temp all the 8 bits of LSB (least significant byte)
  tr = data[0];
 
  //check for negative temperature
  if (data[1] > 0x80){
    tr = !tr + 1; //two's complement adjustment
    tr = tr * -1; //flip value negative.
  }
 
  //COUNT PER Celsius degree (10h)
  int cpc = data[7];
  //COUNT REMAIN (0Ch)
  int cr = data[6];
 
  //drop bit 0
  tr = tr >> 1;
 
  //calculate the temperature based on this formula :
  //TEMPERATURE = TEMP READ - 0.25 + (COUNT PER Celsius Degree - COUNT REMAIN)/ (COUNT PER Celsius Degree)
 
  return tr - (float)0.25 + (cpc - cr)/(float)cpc;
}
 
//fahrenheit to celsius conversion
float f2c(float val){
  float aux = val - 32;
  return (aux * 5 / 9);
}
 
//celsius to fahrenheit conversion
float c2f(float val){
  float aux = (val * 9 / 5);
  return (aux + 32);
}

void lookUpSensors(){
  //byte address[8];
  int i=0;
  byte ok = 0, tmp = 0;
  //start the search
  //Serial.println("--Search started--");
  while (ow.search(sensor)){
    tmp = 0;
    //0x10 = DS18S20
    if (sensor[0] == 0x10){
      //Serial.print("Device is a DS18S20 : ");
      tmp = 1;
    } else {
      //0x28 = DS18B20
      if (sensor[0] == 0x28){
        //Serial.print("Device is a DS18B20 : ");
        tmp = 1;
      }
    }
    //display the address, if tmp is ok
    if (tmp == 1){
      if (OneWire::crc8(sensor, 7) != sensor[7]){
        //Serial.println("but it doesn't have a valid CRC!");
      } else {
        ok = 1;
      }
    }//end if tmp
  }//end while
  if (ok == 0){
    //Serial.println("No devices were found");
  }
  //Serial.println("--Search ended--");
}


void loop(void) {
  float temp;
  float tmp2;
  float a;
  char junk = ' ';
if (Serial.available() )   // Wait here until input buffer has a character
  {
    junk = Serial.read() ;
    if (junk == 't')        //PogoPlug에서 온도를 보내라는 명령어
    { 
      tmp2 = getTemperature(sensor);
      char data[20];
      char flaottemp[7];
      dtostrf(tmp2, 6, 4, flaottemp);
      flaottemp[6] = 0;
      sprintf(data,"%s",flaottemp);
      Serial.println(data);     
    }
   
  }

소스에 온도센서 주소값이 기입되어있지만, lookUpSensors(); 함수가 온도센서의 주소값을 읽는 동작을 하기때문에 자신의 온도센서값으로 바뀝니다.


저는, 포고플러그에서 신호를 보낼때(시리얼)마다 아두이노가 온도값을 보내도록 하였습니다.

그럼 온도측정 간격을 유동적으로 바꿀수 있기 때문입니다.


포고플러그는 아두이노를 USB 로 연결하면 자동으로 인식을 합니다.

mount -l 

또는

dmesg | tail

해서 보면 ttyUSB0 이라는것이 아두이노가 연결된 포트입니다.

이제 포고플러그에서 시리얼 통신을 위한 라이브러리가 필요합니다.

libSerial 이란 C++ 라이브러리를 사용합니다.

다운로드 받아서 빌드를 해야합니다.

tar -zxvf libserial-0.5.2.tar.gz

./configure

make

make install

빌드전에 gcc는 최신으로 업데이트 해주셔야하고,

빌드중 에러가 날경우, 에러가 나는 파일에

#include <string>

헤더를 추가해주시면 됩니다.(대부분....)

빌드가 끝나면 /usr/local/lib 경로에 libserial.a 파일이 생성됩니다.


이제, 포고플러그에서 아두이노의 온도값을 읽는 프로그램을 작성해봅니다.

main.cpp

#include <SerialStream.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORT "/dev/ttyUSB0" //아두이노가 연결된 포트입니다. 직접 확인하셔서 연결된 포트명으로 수정해야합니다.

using namespace std;
using namespace LibSerial;

SerialStream ardu;


void open(){
    /*The arduino must be setup to use the same baud rate*/
    cout << "init" <<endl;
    ardu.Open(PORT);
    if ( ! ardu.good() )
    {
        std::cerr << "Error: Could not opem Serial Device." <<
        std::endl ;
        //exit(1) ;
    }
    ardu.SetBaudRate(SerialStreamBuf::BAUD_9600);
    ardu.SetCharSize(SerialStreamBuf::CHAR_SIZE_8);
    cout << "init end"<< endl;
}
#define SOME_BIG_SIZE 256

int get(char out){   
    int res;
    char str[SOME_BIG_SIZE];
    ardu << out;
    ardu >> str;
    sscanf(str,"%d",&res);
    return res;
}

void main()
{
    open();
    while(true)
    {
        int value = get('t'); //PogoPlug에 온도를 요청합니다.
        sleep(10);  //10초간 딜레이
    }
}


저의 경우, 이미 많은 기능이 추가되어서 기본적인 부분만 간추려보았습니다. 빌드에러가 날수도 있는데

아마 그리 어려운 부분은 아닐겁니다. 수정해주시면 됩니다.


이제 이 프로그램을 실행가능한 파일로 빌드해 보겠습니다.

g++ -o serial main.cpp -lserial


혹시 링크 에러가 나면, 그냥 /usr/local/libserial.a 파일을 복사해서 main.cpp파일이 있는 경로로 가져오시는게 쉽습니다.

그럼 serial 이란 실행파일이 생성됩니다.

이걸 실행하면 ( ./serial )

10초마다 아두이노에게 시리얼로 't' 라는 문자를 보내고,

아두이노에서는 't'문자를 받을때, 현재 온도를 센서에서 읽어서 시리일로 전송하는

프로그램이 완성되었습니다.

int value 값을 가지고 이제 원하는 작업을 하면 됩니다.

핵심은, PogoPlug <-> Arduino 시리얼 통신입니다.


저같은 경우는, 이 값을 웹으로 전송하여, 브라우저로 확인가능하도록 하였습니다.

이경우, CUrl 이란 http 라이브러리를 사용하였습니다.

이 라이브러리는 조금은 복잡하니 사용방법을 찾아보셔야 합니다.

그럼, 아두이노의 이더넷 모듈같은건 사용하지 않고 인터넷통신이 가능합니다.




나중에 시간이 되면 이 부분도 포스팅하도록 하겠습니다.

지금 저는 여기에 지그비를 붙여서 아두이노 2대로 2개방의 온도를 무선으로 측정하도록 확장하고 있습니다.

포고플러그는 단순히 인터넷연결기능만 하는 역할이긴 하지만,

포고플러그+아두이노 조합은 꽤 활용도가 높은 기기입니다.