Monday, June 9, 2014

Log Data Upload - Humidity & Temperature Web Logger

I have purchased DHT11 Humidity & Temperature Sensor from the following site.
http://www.dfrobot.com/index.php?route=product/product&product_id=174#.U4lzu3J_uSq

They deliver only the sensor.  It has Connector and Wire; however, there is no PCB.



BUT, it doesn't have cable to connect to Arduino.
So I had to purchase the Arduino jumper wire set, which I thought was useless. :(
http://www.eleparts.co.kr/EPXCTKGY ( the following site is Korean site. You might have to search for other site in your own country if you need to purchase one. )



Using the correct colors ( it's not a must ), connect it to Arduino.  I attached it to Connector on RTC Shield.

Red cable: +5V Power.  Top left connector, fifth pin from the top.
Black cable: GND.  Bottom left connector, first pin from the top.
Green cable: A0.  Top right connector, fourth pin from the top.

Download library and import it.


If you upload the dht.ino included in the zip file,



  1. Temperature: It was very hot today; however, it looks somewhat correct.  When I get an actual thermometer I will re-check.
  2. Humidity: Humidity calculation is based on Temperature, thus if the temperature is not correct humidity cannot be correct.
  3. Although there is a decimal point, the decimal value is always 0.  If we change to better sensor I assume it will give us the decimal values so I'm going to stick with the float.  Accuracy of sensor is not the point in this posting so I'm going to move on.

In dht.ino change #define DHT11_PIN 4 to #define DHT11_PIN A0, and 
chk = DHT.read11(DHT11_PIN); to int chk = DHT.read11(DHT11_PIN);.


Protocol

I have modified Get Data Block "GETn".
D = <time stamp> + <Temperature> + <Humidity>
We are going to send time stamp, temperature, and humidity all at the same time.



Arduino Code

Following is excerpts from the code.  The entire code can be found in the link at the very bottom.  I modified WSAdam5.ino to create the following code.
#include <dht.h>
... OMIT ...
#define LOG_BLOCK_SIZE 96
... OMIT ...
//-------------------------------------DHT-11
#define DHT11_PIN A0
//#define SAMPLING_INTERVAL (3*1000)

// If you set it to this, it will read sensor value every minute.
// It takes forever to debug if you set it to 10 minutes.
// Arduino default is 16 bit int. If you don't do (uint32_t)
// it becomes -5536
#define SAMPLING_INTERVAL (uint32_t)60*1000
#define MAX_REC_SIZE  42 // 512/12 = 42.666...

dht DHT;
float humidity;
float temperature;
void DHTPoll();
... OMIT ...
void loop() {
 wsServer.listen();
 
 if(sdStatus) {
  if((millis() - lastPollTime) >= SAMPLING_INTERVAL) {
   lastPollTime = millis();
   DHTPoll();
  }
 }
}

/*
  ----------------------------------------------------------------
   D H T - 1 1   h a n d l e r
  ----------------------------------------------------------------
*/
void DHTPoll() {
 if(DHT.read11(DHT11_PIN) == DHTLIB_OK) {
  humidity = DHT.humidity;
  temperature = DHT.temperature;

  if(sdStatus) makeLogBlock();
 }
}
... OMIT ...
void SDbegin(void) {
... OMIT ...
 //load last block
 sdCard.readBlock(currBlock, sdBuffer);
 pB = sdBuffer;

 if(*((uint32_t*)pB) != USED_MARK) { // New data block
  *((uint32_t*)pB) = USED_MARK; // Used Flag
  *((uint32_t*)(pB + 4)) = 0; // for this Logging Block
                              // set the record to 0 and
                              // add 3 bytes padding
 }

 LogBlockSize = sdBuffer[4]; // Used data block
 sdStatus++;  
 printCurrBlock(); //debug purpose
}
... OMIT ...
void makeLogBlock(void) {
... OMIT ...
 //------------------------- push Data into Buffer
 pB = sdBuffer + 8 + (LogBlockSize * 12);
 now = rtc.now();

 *((uint32_t*)pB) = now.unixtime(); // Time-stamp 
 *((float*)(pB + 4)) = temperature; // Temperature
 *((float*)(pB + 8)) = humidity; // Humidity
... OMIT ...
 //------------------------- write to SD card everytime
 LogBlockSize++;
 sdBuffer[4] = LogBlockSize;
 sdCard.writeBlock(currBlock, sdBuffer);

 //------------------------- If the Data Block is complete, 
 //           fix the Free block location and reset Buffer
 if(LogBlockSize >= MAX_REC_SIZE) {
  currBlock++;
  update_currBlock();

  pB = sdBuffer;
  *((uint32_t*)pB) = USED_MARK; // Used Flag
  *((uint32_t*)(pB + 4)) = 0; // Set this logging Block's record
                              // to 0 and add 3 bytes padding
  LogBlockSize = 0;
 }  
... OMIT ...
void upload_DataBlock(uint32_t reqBlock) {
... OMIT ...
 cnt = *pS;
 pS += 4;
 printLn[0] = 'D';

 while(cnt--) {
  // time stamp (seconds)
  ltoa(*((uint32_t*)pS), printLn + 2, 10);
  pC = printLn + strlen(printLn);
  *pC++ = '=';
  pS += 4;
  
  // Temperature
  dtostrf(*((float*)pS), 6, 2, pC); // -12.34C
  pC = printLn + strlen(printLn);
  *pC++ = '=';
  pS += 4;

  // Humidity
  dtostrf(*((float*)pS), 6, 2, pC); // 12.34%
  pS += 4;
  WSsend(printLn, strlen(printLn));
 }

 printLn[2] = '0'; //timestamp == 0, end-of-data
 WSsend(printLn, 3);
... OMIT ... 


HTML / JS Code

This code shows how to upload data using Web Socket, and how to create Web DB using the uploaded data.  Codes below are only part of the code.  If you want to see the entire code look at the link at the very bottom.
This code is modified from WSAdam6_5.html.

Clicking [GetDataBlock] button will display the Temperature & Humidity Data in DB.



... OMIT ...
      var db = openDatabase('WebLogger10', '1.0', 'Web Logger', 512*1024);

      $(document).ready(function() {
        WebSocketConnect();
        db.transaction(function (tx) {
          tx.executeSql('CREATE TABLE IF NOT EXISTS LogIndex(block, timeStamp)');
          tx.executeSql('CREATE TABLE IF NOT EXISTS LogData(block, timeStamp, temperature, humidity)');
        });
      });
... OMIT ...
      function WebSocketConnect() {
... OMIT ...
            // receive Data Block
            if(ar[0] == 'D'){
              data[rcvCnt++] = ar[1];
              data[rcvCnt++] = ar[2];
              data[rcvCnt++] = ar[3];
              if(ar[1] == '0'){
                $("#recordCntPara").empty();  
                $("#recordCntPara").append('Received:' + rcvCnt);
                if(blockNo != 0){
                  db.transaction(function (tx) {                  
                    if(rcvCnt>126) rcvCnt = 126;
                    rcvCnt /= 3;
                    $("#recordCntPara").append(',Record Count:' + rcvCnt);
                    for(i=0;i<rcvCnt;i++){
                      tx.executeSql("INSERT INTO LogData VALUES(?, ?, ?, ?)", [blockNo, data[i*3], data[i*3+1], data[i*3+2]]);
                    } 
                  });
                  db.transaction(function (tx) {
                    tx.executeSql("INSERT INTO LogIndex VALUES(?, ?)", [blockNo, data[0]]);
                  });
... OMIT ...
      function viewData() {
... OMIT ...
            for(i=0;i<len;i++){
              timeStamp = results.rows.item(i).timeStamp;
              tod.setTime((timeStamp - (9*3600)) * 1000);
              $("#dumpPara").append('<p>' + tod.toLocaleString() + '  ' + results.rows.item(i).temperature + 'C ' + results.rows.item(i).humidity + '%<p>');
            }
... OMIT ...



Full codes can be found in following links