Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@luiscd7
Last active August 29, 2015 14:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luiscd7/c6280cbac4183f3bf7e2 to your computer and use it in GitHub Desktop.
Save luiscd7/c6280cbac4183f3bf7e2 to your computer and use it in GitHub Desktop.
DHT22, MQ-2 Spark Core
// This #include statement was automatically added by the Spark IDE.
#include "elapsedMillis/elapsedMillis.h"
#include "HttpClient/HttpClient.h"
#include "PietteTech_DHT.h" // From: https://github.com/piettetech/PietteTech_DHT
#include "math.h"
/* Function prototypes -------------------------------------------------------*/
void dht_wrapper(); // must be declared before the lib initialization
// Explicit Declaration of System Mode
SYSTEM_MODE(AUTOMATIC);
#define MODE_PRODUCTION
#define MODE_DEBUG
/* PRE-Processor Defined -----------------------------------------------------*/
#define DHTTYPE DHT22 // Sensor type DHT11/21/22/AM2301/AM2302
#define DHTPIN 4 // Digital pin for communications
#define DHT_SAMPLE_INTERVAL 10000 // Sample every ten seconds
#define ADC_RESOLUTION 4095
#define MQ_PIN (0) //define which analog input channel you are going to use
#define RL_VALUE (0.9) //define the load resistance on the board, in kilo ohms
#define RO_CLEAN_AIR_FACTOR (5) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
//which is derived from the chart in datasheet
/***********************Software Related Macros************************************/
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
//normal operation
/**********************Application Related Macros**********************************/
#define GAS_LPG (0)
#define GAS_CO (1)
#define GAS_SMOKE (2)
/*****************************Globals***********************************************/
float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.53), point2: (lg10000, -0.22)
float Ro = 10; //Ro is initialized to 10 kilo ohms
int smoke;
/* Constants -----------------------------------------------------------------*/
const char c_temp_var_id[] = "TEMP ºC";
const char c_humidity_var_id[] = "% HUM";
const char humo[] = "SMOKE";
/* Objects -------------------------------------------------------------------*/
PietteTech_DHT DHT(DHTPIN, DHTTYPE, dht_wrapper);
HttpClient http;
http_request_t request;
http_response_t response;
elapsedMillis timeElapsed;
/* Global Variables ----------------------------------------------------------*/
unsigned long ulDHTLastUpdate;
bool bDHTstarted; // flag to indicate we started acquisition
char message[180];
// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
// { "Content-Type", "application/json" },
// { "Accept" , "application/json" },
{ "Accept" , "*/*"},
{ NULL, NULL } // NOTE: Always terminate headers will NULL
};
/* Setup Function - Run One @ Startup ----------------------------------------*/
void setup()
{
Serial.begin(9600);
Spark.publish("FIRMWARE_VERSION", "0.0.1");
delay(500);
Spark.publish("DHTLIB_VERSION", DHTLIB_VERSION);
ulDHTLastUpdate = millis();
Serial.print("Calibrating...\n");
Ro = MQCalibration(MQ_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
//when you perform the calibration
Serial.print("Calibration is done...\n");
Serial.print("Ro=");
Serial.print(Ro);
Serial.print("kohm");
Serial.print("\n");
}
int sendReading(char *name, float value)
{
request.port = 80;
#if defined(MODE_PRODUCTION)
request.hostname = "luihost.webgatenetworks.com";
sprintf(message, "/stest.php?name=%s&value=%f&coreid=", name, value);
#else
request.hostname = "requestb.in";
sprintf(message, "/pbp7mtpb?end=stest.php&name=%s&value=%f&coreid=", name, value);
#endif
// Send out the data to a private HTTP server
request.path = String(message) + Spark.deviceID();
http.get(request, response, headers);
#if defined(MODE_DEBUG)
Serial.print("[DEBUG] GET Request to "); Serial.print(request.hostname); Serial.println(request.path);
Serial.print("[DEBUG] Status: "); Serial.println(response.status, DEC); Serial.print("\tBody: "); Serial.println(response.body);
request.path.toCharArray(message, 180);
message[179] = '\0';
Spark.publish("DEBUG:GET REQUEST URL", message);
#endif
// Send out the data as an event
sprintf(message, "%s,:%f", name, value);
Spark.publish("Monitoreo DH", message);
#if defined(MODE_DEBUG)
Serial.print("[DEBUG] Spark Event. Message = "); Serial.println(message);
#endif
timeElapsed = 0;
Serial.println("[DEBUG] Waiting for a second for things to process ");
while(timeElapsed < 1000)
{
Spark.process();
}
Serial.println("[DEBUG] Done waiting");
return response.status;
}
/* Loop Function - Run Indefinitely ----------------------------------------*/
void loop()
{
if(((millis() - ulDHTLastUpdate) > DHT_SAMPLE_INTERVAL) || (bDHTstarted))
{
// Start a new sample if we haven't yet
if (!bDHTstarted)
{
/*Serial.print("\n");
Serial.print(n);
Serial.print(": Retrieving information from sensor: ");*/
DHT.acquire();
bDHTstarted = true;
}
// Once we are done aquiring handle the result
if (!DHT.acquiring())
{
// get DHT status
int result = DHT.getStatus();
if(result != DHTLIB_OK)
{
sprintf(message, "{\"error\":\"%d\"}", result);
//Spark.publish("DHTLIB_ERROR", message);
Spark.publish("dhtlibError", message);
}
else
{
// Grab the readings we are interested in
float tempC = DHT.getCelsius();
double humidity = DHT.getHumidity();
float smoke = MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_SMOKE);
int res = 0;
// Send Temperature
res = sendReading("temp", tempC);
if(res != 200) Serial.print("[DEBUG] Failed to send the temp value. Response = "); Serial.println(res, DEC);
// Send Humidity
res = sendReading("humedad", humidity);
if(res != 200) Serial.print("[DEBUG] Failed to send the humidity value. Response = "); Serial.println(res, DEC);
// Send Humo
res = sendReading("humo", smoke);
if(res != 200) Serial.print("[DEBUG] Failed to send the smoke value. Response = "); Serial.println(res, DEC);
}
bDHTstarted = false; // reset the sample flag so we can take another
ulDHTLastUpdate = millis();
}
}
}
// This wrapper is in charge of calling
// mus be defined like this for the lib work
void dht_wrapper() {
DHT.isrCallback();
}
float MQResistanceCalculation(int raw_adc)
{
return ( ((float)RL_VALUE*(ADC_RESOLUTION-raw_adc)/raw_adc));
}
/***************************** MQCalibration *************************************/
float MQCalibration(int mq_pin)
{
int i;
float val=0;
for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) { //take multiple samples
val += MQResistanceCalculation(analogRead(mq_pin));
delay(CALIBRATION_SAMPLE_INTERVAL);
}
val = val/CALIBARAION_SAMPLE_TIMES; //calculate the average value
val = val/RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro
//according to the chart in the datasheet
return val;
}
/***************************** MQRead *********************************************/
float MQRead(int mq_pin)
{
int i;
float rs=0;
for (i=0;i<READ_SAMPLE_TIMES;i++) {
rs += MQResistanceCalculation(analogRead(mq_pin));
delay(READ_SAMPLE_INTERVAL);
}
rs = rs/READ_SAMPLE_TIMES;
return rs;
}
/***************************** MQGetGasPercentage **********************************/
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
{
if ( gas_id == GAS_LPG ) {
return MQGetPercentage(rs_ro_ratio,LPGCurve);
} else if ( gas_id == GAS_CO ) {
return MQGetPercentage(rs_ro_ratio,COCurve);
} else if ( gas_id == GAS_SMOKE ) {
return MQGetPercentage(rs_ro_ratio,SmokeCurve);
}
return 0;
}
/***************************** MQGetPercentage *******************************/
int MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}
/*
* FILE: PietteTech_DHT.cpp
* VERSION: 0.3
* PURPOSE: Spark Interrupt driven lib for DHT sensors
* LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
*
* S Piette (Piette Technologies) scott.piette@gmail.com
* January 2014 Original Spark Port
* October 2014 Added support for DHT21/22 sensors
* Improved timing, moved FP math out of ISR
*
* Based on adaptation by niesteszeck (github/niesteszeck)
* Based on original DHT11 library (http://playgroudn.adruino.cc/Main/DHT11Lib)
*
*
* This library supports the DHT sensor on the following pins
* D0, D1, D2, D3, D4, A0, A1, A3, A5, A6, A7
* http://docs.spark.io/firmware/#interrupts-attachinterrupt
*
*/
/*
Timing of DHT22 SDA signal line after MCU pulls low for 1ms
https://github.com/mtnscott/Spark_DHT/AM2302.pdf
- - - - ----- -- - - -- ------- - -
\ / \ / \ \ /
+ / + / + + /
\ / \ / \ \ /
------ ----- -- - --------
^ ^ ^ ^ ^
| Ts | Tr | Td | Te |
Ts : Start time from MCU changing SDA from Output High to Tri-State (Hi-Z)
Spec: 20-200us Tested: < 65us
Tr : DHT response to MCU controlling SDA and pulling Low and High to
start of first data bit
Spec: 150-170us Tested: 125 - 200us
Td : DHT data bit, falling edge to falling edge
Spec: '0' 70us - 85us Tested: 60 - 110us
Spec: '1' 116us - 130us Tested: 111 - 155us
Te : DHT releases SDA to Tri-State (Hi-Z)
Spec: 45-55us Not Tested
*/
#include "application.h"
#include "math.h"
#include "PietteTech_DHT.h"
// Thanks to Paul Kourany for this word type conversion function
uint16_t word(uint8_t high, uint8_t low) {
uint16_t ret_val = low;
ret_val += (high << 8);
return ret_val;
}
PietteTech_DHT::PietteTech_DHT(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper)()) {
begin(sigPin, dht_type, callback_wrapper);
_firstreading = true;
}
void PietteTech_DHT::begin(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper) ()) {
_sigPin = sigPin;
_type = dht_type;
isrCallback_wrapper = callback_wrapper;
pinMode(sigPin, OUTPUT);
digitalWrite(sigPin, HIGH);
_lastreadtime = 0;
_state = STOPPED;
_status = DHTLIB_ERROR_NOTSTARTED;
}
int PietteTech_DHT::acquire() {
// Check if sensor was read less than two seconds ago and return early
// to use last reading
unsigned long currenttime = millis();
if (currenttime < _lastreadtime) {
// there was a rollover
_lastreadtime = 0;
}
if (!_firstreading && ((currenttime - _lastreadtime) < 2000 )) {
// return last correct measurement, (this read time - last read time) < device limit
return DHTLIB_ACQUIRED;
}
if (_state == STOPPED || _state == ACQUIRED) {
/*
* Setup the initial state machine
*/
_firstreading = false;
_lastreadtime = currenttime;
_state = RESPONSE;
#if defined(DHT_DEBUG_TIMING)
/*
* Clear the debug timings array
*/
for (int i = 0; i < 41; i++) _edges[i] = 0;
_e = &_edges[0];
#endif
/*
* Set the initial values in the buffer and variables
*/
for (int i = 0; i < 5; i++) _bits[i] = 0;
_cnt = 7;
_idx = 0;
_hum = 0;
_temp = 0;
/*
* Toggle the digital output to trigger the DHT device
* to send us temperature and humidity data
*/
pinMode(_sigPin, OUTPUT);
digitalWrite(_sigPin, LOW);
if (_type == DHT11)
delay(18); // DHT11 Spec: 18ms min
else
delayMicroseconds(1500); // DHT22 Spec: 0.8-20ms, 1ms typ
pinMode(_sigPin, INPUT); // Note Hi-Z mode with pullup resistor
// will keep this high until the DHT responds.
/*
* Attach the interrupt handler to receive the data once the DHT
* starts to send us data
*/
_us = micros();
attachInterrupt(_sigPin, isrCallback_wrapper, FALLING);
return DHTLIB_ACQUIRING;
} else
return DHTLIB_ERROR_ACQUIRING;
}
int PietteTech_DHT::acquireAndWait() {
acquire();
while(acquiring()) ;
return getStatus();
}
void PietteTech_DHT::isrCallback() {
unsigned long newUs = micros();
unsigned long delta = (newUs - _us);
_us = newUs;
if (delta > 6000) {
_status = DHTLIB_ERROR_ISR_TIMEOUT;
_state = STOPPED;
detachInterrupt(_sigPin);
return;
}
switch(_state) {
case RESPONSE: // Spec: 80us LOW followed by 80us HIGH
if(delta < 65) { // Spec: 20-200us to first falling edge of response
_us -= delta;
break; //do nothing, it started the response signal
} if(125 < delta && delta < 200) {
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
_state = DATA;
} else {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
_state = STOPPED;
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
}
break;
case DATA: // Spec: 50us low followed by high of 26-28us = 0, 70us = 1
if(60 < delta && delta < 155) { //valid in timing
_bits[_idx] <<= 1; // shift the data
if(delta > 110) //is a one
_bits[_idx] |= 1;
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
if (_cnt == 0) { // we have completed the byte, go to next
_cnt = 7; // restart at MSB
if(++_idx == 5) { // go to next byte, if we have got 5 bytes stop.
detachInterrupt(_sigPin);
// Verify checksum
uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3];
if (_bits[4] != sum) {
_status = DHTLIB_ERROR_CHECKSUM;
_state = STOPPED;
} else {
_status = DHTLIB_OK;
_state = ACQUIRED;
_convert = true;
}
break;
}
} else _cnt--;
} else if(delta < 10) {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_DELTA;
_state = STOPPED;
} else {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_DATA_TIMEOUT;
_state = STOPPED;
}
break;
default:
break;
}
}
void PietteTech_DHT::convert() {
// Calculate the temperature and humidity based on the sensor type
switch (_type) {
case DHT11:
_hum = _bits[0];
_temp = _bits[2];
break;
case DHT22:
case DHT21:
_hum = word(_bits[0], _bits[1]) * 0.1;
_temp = (_bits[2] & 0x80 ?
-word(_bits[2] & 0x7F, _bits[3]) :
word(_bits[2], _bits[3])) * 0.1;
break;
}
_convert = false;
}
bool PietteTech_DHT::acquiring() {
if (_state != ACQUIRED && _state != STOPPED)
return true;
return false;
}
int PietteTech_DHT::getStatus() {
return _status;
}
float PietteTech_DHT::getCelsius() {
DHT_CHECK_STATE;
return _temp;
}
float PietteTech_DHT::getHumidity() {
DHT_CHECK_STATE;
return _hum;
}
float PietteTech_DHT::getFahrenheit() {
DHT_CHECK_STATE;
return _temp * 9 / 5 + 32;
}
float PietteTech_DHT::getKelvin() {
DHT_CHECK_STATE;
return _temp + 273.15;
}
/*
* Added methods for supporting Adafruit Unified Sensor framework
*/
float PietteTech_DHT::readTemperature() {
acquireAndWait();
return getCelsius();
}
float PietteTech_DHT::readHumidity() {
acquireAndWait();
return getHumidity();
}
// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double PietteTech_DHT::getDewPoint() {
DHT_CHECK_STATE;
double a = 17.271;
double b = 237.7;
double temp_ = (a * (double) _temp) / (b + (double) _temp) + log( (double) _hum/100);
double Td = (b * temp_) / (a - temp_);
return Td;
}
// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
double PietteTech_DHT::getDewPointSlow() {
DHT_CHECK_STATE;
double a0 = (double) 373.15 / (273.15 + (double) _temp);
double SUM = (double) -7.90298 * (a0-1.0);
SUM += 5.02808 * log10(a0);
SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/a0)))-1) ;
SUM += 8.1328e-3 * (pow(10,(-3.49149*(a0-1)))-1) ;
SUM += log10(1013.246);
double VP = pow(10, SUM-3) * (double) _hum;
double T = log(VP/0.61078); // temp var
return (241.88 * T) / (17.558-T);
}
/*
* FILE: PietteTech_DHT.h
* VERSION: 0.3
* PURPOSE: Spark Interrupt driven lib for DHT sensors
* LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
*
* S Piette (Piette Technologies) scott.piette@gmail.com
* January 2014 Original Spark Port
* October 2014 Added support for DHT21/22 sensors
* Improved timing, moved FP math out of ISR
*
* Based on adaptation by niesteszeck (github/niesteszeck)
* Based on original DHT11 library (http://playgroudn.adruino.cc/Main/DHT11Lib)
*
*
* With this library connect the DHT sensor to the following pins
* D0, D1, D2, D3, D4, A0, A1, A3, A5, A6, A7
* http://docs.spark.io/firmware/#interrupts-attachinterrupt
*
*/
#ifndef __PIETTETECH_DHT_H__
#define __PIETTETECH_DHT_H__
// There appears to be a overrun in memory on this class. For now please leave DHT_DEBUG_TIMING enabled
#define DHT_DEBUG_TIMING // Enable this for edge->edge timing collection
#include "application.h"
#define DHTLIB_VERSION "0.3"
// device types
#define DHT11 11
#define DHT21 21
#define AM2301 21
#define DHT22 22
#define AM2302 22
// state codes
#define DHTLIB_OK 0
#define DHTLIB_ACQUIRING 1
#define DHTLIB_ACQUIRED 2
#define DHTLIB_RESPONSE_OK 3
// error codes
#define DHTLIB_ERROR_CHECKSUM -1
#define DHTLIB_ERROR_ISR_TIMEOUT -2
#define DHTLIB_ERROR_RESPONSE_TIMEOUT -3
#define DHTLIB_ERROR_DATA_TIMEOUT -4
#define DHTLIB_ERROR_ACQUIRING -5
#define DHTLIB_ERROR_DELTA -6
#define DHTLIB_ERROR_NOTSTARTED -7
#define DHT_CHECK_STATE \
if(_state == STOPPED) \
return _status; \
else if(_state != ACQUIRED) \
return DHTLIB_ERROR_ACQUIRING; \
if(_convert) convert();
class PietteTech_DHT
{
public:
PietteTech_DHT(uint8_t sigPin, uint8_t dht_type, void (*isrCallback_wrapper)());
void begin(uint8_t sigPin, uint8_t dht_type, void (*isrCallback_wrapper)());
void isrCallback();
int acquire();
int acquireAndWait();
float getCelsius();
float getFahrenheit();
float getKelvin();
double getDewPoint();
double getDewPointSlow();
float getHumidity();
bool acquiring();
int getStatus();
float readTemperature();
float readHumidity();
#if defined(DHT_DEBUG_TIMING)
volatile uint8_t _edges[41];
#endif
private:
void (*isrCallback_wrapper)(void);
void convert();
enum states{RESPONSE=0,DATA=1,ACQUIRED=2,STOPPED=3,ACQUIRING=4};
volatile states _state;
volatile int _status;
volatile uint8_t _bits[5];
volatile uint8_t _cnt;
volatile uint8_t _idx;
volatile unsigned long _us;
volatile bool _convert;
#if defined(DHT_DEBUG_TIMING)
volatile uint8_t *_e;
#endif
int _sigPin;
int _type;
unsigned long _lastreadtime;
bool _firstreading;
float _hum;
float _temp;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment