Humidex Calculator using Arduino

Given the high cost of running air conditioners, was kicking around the idea of being able to automatically determine when is the right time to use a desert cooler (aka evaporative cooler or swamp cooler) vs an air conditioner. Can across some papers on Humidex / Heat Index which could be used to determine the same, therefore decided to implement a Humidex Calculator using Arduino.

First some theory about Humidex :-

The humidex is an index number used to describe how hot the weather feels to the average person, by combining the effect of heat and humidity. The humidex is a unit-less number based on the dew point, but it is equivalent to dry temperature in degrees Celsius. For example, if the temperature is 30 °C (86 °F), and the calculated humidex is 40, then it indicates the humid heat feels approximately like a dry temperature of 40 °C (104 °F).

According to the Meteorological Service of Canada, a humidex of at least 30 causes “some discomfort”, at least 40 causes “great discomfort” and above 45 is “dangerous”.

More details are at

 

Humidex is calculated as air temperature + h

where :-

  • h = (0.5555)*(e – 10.0);
  • e = 6.11 * exp(5417.7530 * ((1/273.16) – (1/dewpoint)))

Now the code based on DH11 humidity sensor and the BMP085 temperature sensor. The key value pair are output to the serial port where a java program parses and submits them to a Mango M2M datalogger running on the local machine.

Arduino Code: -

Given the high cost of running air conditioners, was kicking around the idea of being able to automatically determine when is the right time to use a desert cooler (aka evaporative cooler or swamp cooler) vs an air conditioner. Can across some papers on Humidex / Heat Index which could be used to determine the same, therefore decided to implement the same using Arduino.

First some theory about Humidex :-

The humidex is an index number used to describe how hot the weather feels to the average person, by combining the effect of heat and humidity. The humidex is a unit-less number based on the dew point, but it is equivalent to dry temperature in degrees Celsius. For example, if the temperature is 30 °C (86 °F), and the calculated humidex is 40, then it indicates the humid heat feels approximately like a dry temperature of 40 °C (104 °F).

According to the Meteorological Service of Canada, a humidex of at least 30 causes "some discomfort", at least 40 causes "great discomfort" and above 45 is "dangerous".

More details are at

http://www.physlink.com/reference/weather.cfm


http://en.wikipedia.org/wiki/Humidex

Humidex is calculated as air temperature + h

where :-

h = (0.5555)*(e - 10.0);
e = 6.11 * exp(5417.7530 * ((1/273.16) - (1/dewpoint)))
Now the code based on DH11 humidity sensor and the BMP085 temperature sensor. The key value pair are output to the serial port where a java program parses and submits them to a Mango M2M datalogger running on the local machine.

Arduino Code: -

#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <SPI.h>
#include <util.h>
#include <DHT11.h>
#include <math.h>

// BM035 Connections
// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here

//DH11 Connections

//LM035 Connections

//Dex point and humidex calculator
//Humidex = (air temperature) + h
// h = (0.5555)*(e - 10.0);
// e = 6.11 * exp(5417.7530 * ((1/273.16) - (1/dewpoint)))

// http://www.physlink.com/reference/weather.cfm

// heat index (HI) or humiture
// http://en.wikipedia.org/wiki/Heat_index
// http://www.nws.noaa.gov/os/heat/index.shtml#heatindex
//HI = -42.379 + 2.04901523T + 10.14333127R - 0.22475541TR - 6.83783x10
//    -3T2 - 5.481717x10 - 2R2 + 1.22874x10 -3T2R + 8.5282x10
// -4TR2 - 1.99x10-6T2R2
// where T = ambient dry bulb temperature (°F)
// R = relative humidity (integer percentage).
// http://www.4wx.com/wxcalc/formulas/heatIndex.php

//Heat Index = -42.379 + (2.04901523 x T) + (10.14333127 x R) - (0.22475541 x T x R) - (6.83783x10-3 x T2) - (5.481717x10-2 x R2) + (1.22874x10-3 x T2 x R) + (8.5282x10-4 x T x R2) - (1.99x10-6 x T2 x R2)
// Where,
//T = Temperature in ?F
// R = Relative Humidity in %
// Heat index is utilized only in warm weather  &gt;=70° F
// http://www.gorhamschaffler.com/humidity_formulas.htm

Adafruit_BMP085 bmp;
dht11 DHT11;

#define DHTTYPE DHT11   // DHT 11
#define DHT11PIN 2    // what pin we're connected to
#define aref_voltage 1.1  // reference voltage given to LM35, Using basic config of LM35 this is for 2-150 C @ 0mv + 10mv per degree centigrade

double a = 17.271;
double b = 237.7;

double bmp_temperature;
double bmp_pressure;
double DH11_temperature;
double DH11_humidity;
double LM35_temperature;

void setup() {
  analogReference(INTERNAL); // sets ref voltage for conversion to 1.1 vs the default 5 V

  Serial.begin(9600);
  bmp.begin();

}

void loop() {

  DH11_temperature = readDH11Temperature();
  printSensorReadingToSerial("DH11Temp", DH11_temperature);

  bmp_temperature = readBMPTemperature();
  printSensorReadingToSerial("BMPTemp", bmp_temperature );

  bmp_pressure = readBMPPressure();
  printSensorReadingToSerial("BMPPressure", bmp_pressure);

  LM35_temperature = readLM35Temperature();
  printSensorReadingToSerial("LM35Temp", LM35_temperature);

  delay(1000);
  DH11_humidity = readDH11Humidity();
  printSensorReadingToSerial("DH11Humidity", DH11_humidity);

  double dewpoint = calculatDEWpoint(bmp_temperature,DH11_humidity );
  printSensorReadingToSerial("DewPoint", dewpoint);

  double humidex = calculateHumidexValue(bmp_temperature, dewpoint);
  printSensorReadingToSerial("Humidex", humidex);

  delay(59000);
}

double readBMPTemperature() {
  return bmp.readTemperature();
}

double readBMPPressure() {
  return bmp.readPressure();

  // Calculate altitude assuming 'standard' barometric
  // pressure of 1013.25 millibar = 101325 Pascal
  //Serial.print("Altitude = ");
  //Serial.print(bmp.readAltitude());
  //Serial.println(" meters");

  // you can get a more precise measurement of altitude
  // if you know the current sea level pressure which will
  // vary with weather and such. If it is 1015 millibars
  // that is equal to 101500 Pascals.
  //Serial.print("Real altitude = ");
  //Serial.print(bmp.readAltitude(101500));
  //Serial.println(" meters");

  //Serial.println();

}

double readDH11Temperature() {

  int chk = DHT11.read(DHT11PIN);

  //Serial.print("Read sensor: ");
  switch (chk) {
    //case 0: Serial.println("OK"); break;
  case 0:
    break;
  case -1:
    Serial.println("Checksum error");
    break;
  case -2:
    Serial.println("Time out error");
    break;
  default:
    Serial.println("Unknown error");
    break;
  }

  //  Serial.print("Humidity (%): ");
  //Serial.print((float) DHT11.humidity, 2);

  //Serial.print("  ");

  //  Serial.print("Temperature (oC): ");
  return DHT11.temperature;
}

double readDH11Humidity() {
  int chk = DHT11.read(DHT11PIN);

  switch (chk) {
    //case 0: Serial.println("OK"); break;
  case 0:
    break;
  case -1:
    Serial.println("Checksum error");
    break;
  case -2:
    Serial.println("Time out error");
    break;
  default:
    Serial.println("Unknown error");
    break;
  }

  return DHT11.humidity;

}
double readLM35Temperature() {

  int tempPin = 0; // Analog pin used for measusing LM35 output
  float tempC;
  float voltage;
  int sensorReading = analogRead(tempPin); //read the value from the sensor i.e. 0-1023 after a ADC conversion

    //  Serial.print("Sensor Reading = ");
  //  Serial.println (sensorReading);

  voltage = (sensorReading * aref_voltage * 1000) / 1024.0; // Convert sensor

  // print out the voltage
  ///  Serial.print(" Voltage from sensor :  ");
  //  Serial.print(voltage);
  //  Serial.println(" milli volts");

  tempC = (voltage * 100.0) /1000; //convert the analog data to temperature

  return tempC;

}

double calculatDEWpoint(double temp, double RH)
{
  // for dewpoint see: http://en.wikipedia.org/wiki/Dew_point

  double gammavalue = calculateDewPointGammaValue(temp, RH);

  double dewpoint = (b * gammavalue) / (a - gammavalue);
//  Serial.print("Dewpoint = ");
//  Serial.println(dewpoint);
  return dewpoint;

}

double calculateDewPointGammaValue (double temp, double RH)
{
  double gamma = ((a*temp)/(b+temp)) + log (RH/100);
  return gamma;
}

double calculateHumidexValue (double temp, double DewPoint)
{

  double h = temp + 0.5555 * ( 6.11 *  exp ( calculateHumidexEValue(DewPoint)) - 10);
//  Serial.print("Humidex = ");
//  Serial.println(h);
  return h;
}

double calculateHumidexEValue (double DewPoint)
{

  double e = 5417.7530*((1/273.16)-(1/(273.16 + DewPoint)));
//  Serial.print("evalue = ");
//  Serial.println(e);
  return e;
}

void printSensorReadingToSerial(String key, double value) {
  Serial.print(key);
  Serial.print("=");
  Serial.println(value);

}

Java Code for the serial port listener and posting to a Mango M2M server

public class ArduinoBMP085Logger {

    /**
     * @param args
     */

    public static void main(String[] args) {
// TODO Auto-generated method stub

SerialReader main = new SerialReader();
main.initialize();

//mangoPOST mp = new mangoPOST();

System.out.println("Started");
//mp.sendValue();

    }

}

import java.io.IOException;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;

public class mangoPOST {

  public static void sendValue(String key, String value) {

      HttpClient client = new HttpClient();

      PostMethod method = new PostMethod("http://127.0.0.1:8080/mango/httpds");
      method.addParameter(key, value);

      try {
          client.executeMethod(method);

          if (method.getStatusCode() == HttpStatus.SC_OK) {
              String response = method.getResponseBodyAsString();
              System.out.println("Response = " + response);
          }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          method.releaseConnection();
      }

  }
}

import java.io.InputStream;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier; 
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent; 
import gnu.io.SerialPortEventListener; 
import java.util.Enumeration;

public class SerialReader implements SerialPortEventListener {
SerialPort serialPort;

private static mangoPOST postclient;

private static final String PORT_NAMES[] = { 
"COM21" // Windows
};

/** Buffered input stream from the port */
private InputStream input;
/** The output stream to the port */
private OutputStream output;
/** Milliseconds to block while waiting for port open */
private static final int TIME_OUT = 2000;
/** Default bits per second for COM port. */
private static final int DATA_RATE = 9600;

public void initialize() {

  // nimbitClient = new NimbitsDataUpload();
   postclient = new mangoPOST ();
CommPortIdentifier portId = null;
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

// iterate through, looking for the port
while (portEnum.hasMoreElements()) {
CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
for (String portName : PORT_NAMES) {
if (currPortId.getName().equals(portName)) {
portId = currPortId;
break;
}
}
}

if (portId == null) {
System.out.println("Could not find COM port.");
return;
}

try {
// open serial port, and use class name for the appName.
serialPort = (SerialPort) portId.open(this.getClass().getName(),
TIME_OUT);

// set port parameters
serialPort.setSerialPortParams(DATA_RATE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);

// open the streams
input = serialPort.getInputStream();
output = serialPort.getOutputStream();

// add event listeners
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
} catch (Exception e) {
System.err.println(e.toString());
}
}

/**
* This should be called when you stop using the port.
* This will prevent port locking on platforms like Linux.
*/
public synchronized void close() {
if (serialPort != null) {
serialPort.removeEventListener();
serialPort.close();
}
}

/**
* Handle an event on the serial port. Read the data and print it.
*/
public synchronized void serialEvent(SerialPortEvent oEvent) {

int data ;
        byte[] buffer = new byte[1024];

   if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
//int available = input.available();
//byte chunk[] = new byte[available];

//input.read(chunk, 0, available);

//----------

               int len = 0;
               while ( ( data = input.read()) != '\n' )
               {
                   //if ( data == '\n' ) {
                     //  break;
                   //}
                   if (data > 0)
                   buffer[len++] = (byte) data;
               }
               System.out.println(new String(buffer,0,len));

//----------
// Displayed results are codepage dependent
//System.out.print(new String(chunk));

//
//String Serialinput = new String(chunk);
//String[] values = Serialinput.split(",");

String valueStr = new String(buffer,0,len);
String[] values = valueStr.split("=");
System.out.println(values[0]);
System.out.println(values[1]);

if (len > 2){
   //postclient.sendValue();
   mangoPOST.sendValue(values[0],values[1] );
   //mangoPOST.sendValue("pressure",);

   //nimbitClient.recordvalue("Home_Temp", Double.parseDouble(values[0]));
   Thread.sleep(2000);
   //nimbitClient.recordvalue("Home_Pressure", Double.parseDouble(values[1]));

}

//
} catch (Exception e) {
System.err.println(e.toString());
}
}
// Ignore all the other eventTypes, but you should consider the other ones.
}

public static void main(String[] args) throws Exception {

}
}

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="">