SparkFun_Photon_Weather_Shield_Library.cpp
/*
SparkFun Photon Weather Shield Particle Library
Compiled and Updated for Particle By: Joel Bartlett
SparkFun Electronics
Date: August 05, 2015
This library combines multiple libraries together to make development on the SparkFun
Photon Weather Shield easier. There are two versions of the Weather Shield, one containing
the HTU21D Temp and Humidity sensor and one containing the Si7021-A10. Shortages of the HTU21D
IC combined with contractual obligations led to the two versions existing. Thus, to make it
easier on you, the end user, we have written this library to automatically detect which version
you have without the need for you to have to figure it out and pick a corresponding library.
The MPL3115A2 library was added to avoid the need to import two separate libraries for
the shield.
This library is based on the following libraries:
MPL3115A2 Barometric Pressure Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 24th, 2013
https://github.com/sparkfun/MPL3115A2_Breakout
Spark Core HTU21D Temperature / Humidity Sensor Library
By: Romain MP
https://github.com/romainmp/HTU21D
Arduino Si7010 relative humidity + temperature sensor
By: Jakub Kaminski, 2014
https://github.com/teoqba/ADDRESS
This Library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For a copy of the GNU General Public License, see
<http://www.gnu.org/licenses/>.
*/
#include "SparkFun_Photon_Weather_Shield_Library.h"
//Initialize
Weather::Weather(){}
void Weather::begin(void)
{
Wire.begin();
uint8_t ID_Barro = IIC_Read(WHO_AM_I );
uint8_t ID_Temp_Hum = checkID();
int x,y = 0;
if (ID_Barro == 0xC4)//Ping WhoAmI register
x = 1;
else
x = 0;
if(ID_Temp_Hum == 0x15)//Ping CheckID register
y = 1;
else if(ID_Temp_Hum == 0x32)
y = 2;
else
y = 0;
if(x == 1 && y == 1)
{
Serial.println("MPL3115A2 Found");
Serial.println("Si7021 Found");
}
else if(x == 1 && y == 2)
{
Serial.println("MPL3115A2 Found");
Serial.println("HTU21D Found");
}
else if(x == 0 && y == 1)
{
Serial.println("MPL3115A2 NOT Found");
Serial.println("Si7021 Found");
}
else if(x == 0 && y == 2)
{
Serial.println("MPL3115A2 NOT Found");
Serial.println("HTU21D Found");
}
else if(x == 1 && y == 0)
{
Serial.println("MPL3115A2 Found");
Serial.println("No Temp/Humidity Device Detected");
}
else
Serial.println("No Devices Detected");
}
/****************Si7021 & HTU21D Functions**************************************/
float Weather::getRH()
{
// Measure the relative humidity
uint16_t RH_Code = makeMeasurment(HUMD_MEASURE_NOHOLD);
float result = (125.0*RH_Code/65536)-6;
return result;
}
float Weather::readTemp()
{
// Read temperature from previous RH measurement.
uint16_t temp_Code = makeMeasurment(TEMP_PREV);
float result = (175.25*temp_Code/65536)-46.85;
return result;
}
float Weather::getTemp()
{
// Measure temperature
uint16_t temp_Code = makeMeasurment(TEMP_MEASURE_NOHOLD);
float result = (175.25*temp_Code/65536)-46.85;
return result;
}
//Give me temperature in fahrenheit!
float Weather::readTempF()
{
return((readTemp() * 1.8) + 32.0); // Convert celsius to fahrenheit
}
float Weather::getTempF()
{
return((getTemp() * 1.8) + 32.0); // Convert celsius to fahrenheit
}
void Weather::heaterOn()
{
// Turns on the ADDRESS heater
uint8_t regVal = readReg();
regVal |= _BV(HTRE);
//turn on the heater
writeReg(regVal);
}
void Weather::heaterOff()
{
// Turns off the ADDRESS heater
uint8_t regVal = readReg();
regVal &= ~_BV(HTRE);
writeReg(regVal);
}
void Weather::changeResolution(uint8_t i)
{
// Changes to resolution of ADDRESS measurements.
// Set i to:
// RH Temp
// 0: 12 bit 14 bit (default)
// 1: 8 bit 12 bit
// 2: 10 bit 13 bit
// 3: 11 bit 11 bit
uint8_t regVal = readReg();
// zero resolution bits
regVal &= 0b011111110;
switch (i) {
case 1:
regVal |= 0b00000001;
break;
case 2:
regVal |= 0b10000000;
break;
case 3:
regVal |= 0b10000001;
default:
regVal |= 0b00000000;
break;
}
// write new resolution settings to the register
writeReg(regVal);
}
void Weather::reset()
{
//Reset user resister
writeReg(SOFT_RESET);
}
uint8_t Weather::checkID()
{
uint8_t ID_1;
// Check device ID
Wire.beginTransmission(ADDRESS);
Wire.write(0xFC);
Wire.write(0xC9);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
ID_1 = Wire.read();
return(ID_1);
}
uint16_t Weather::makeMeasurment(uint8_t command)
{
// Take one ADDRESS measurement given by command.
// It can be either temperature or relative humidity
// TODO: implement checksum checking
uint16_t nBytes = 3;
// if we are only reading old temperature, read olny msb and lsb
if (command == 0xE0) nBytes = 2;
Wire.beginTransmission(ADDRESS);
Wire.write(command);
Wire.endTransmission();
// When not using clock stretching (*_NOHOLD commands) delay here
// is needed to wait for the measurement.
// According to datasheet the max. conversion time is ~22ms
delay(100);
Wire.requestFrom(ADDRESS,nBytes);
//Wait for data
int counter = 0;
while (Wire.available() < nBytes){
delay(1);
counter ++;
if (counter >100){
// Timeout: Sensor did not return any data
return 100;
}
}
unsigned int msb = Wire.read();
unsigned int lsb = Wire.read();
// Clear the last to bits of LSB to 00.
// According to datasheet LSB of RH is always xxxxxx10
lsb &= 0xFC;
unsigned int mesurment = msb << 8 | lsb;
return mesurment;
}
void Weather::writeReg(uint8_t value)
{
// Write to user register on ADDRESS
Wire.beginTransmission(ADDRESS);
Wire.write(WRITE_USER_REG);
Wire.write(value);
Wire.endTransmission();
}
uint8_t Weather::readReg()
{
// Read from user register on ADDRESS
Wire.beginTransmission(ADDRESS);
Wire.write(READ_USER_REG);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
uint8_t regVal = Wire.read();
return regVal;
}
/****************MPL3115A2 Functions**************************************/
//Returns the number of meters above sea level
//Returns -1 if no new data is available
float Weather::readAltitude()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
if (Wire.requestFrom(MPL3115A2_ADDRESS, 3) != 3) { // Request three bytes
return -999;
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float tempcsb = (lsb>>4)/16.0;
float altitude = (float)( (msb << 8) | csb) + tempcsb;
return(altitude);
}
//Returns the number of feet above sea level
float Weather::readAltitudeFt()
{
return(readAltitude() * 3.28084);
}
//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
//Returns -1 if no new data is available
float Weather::readPressure()
{
//Check PDR bit, if it's not set then toggle OST
if(IIC_Read(STATUS) & (1<<2) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while(IIC_Read(STATUS) & (1<<2) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
if (Wire.requestFrom(MPL3115A2_ADDRESS, 3) != 3) { // Request three bytes
return -999;
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
// Pressure comes back as a left shifted 20 bit number
long pressure_whole = (long)msb<<16 | (long)csb<<8 | (long)lsb;
pressure_whole >>= 6; //Pressure is an 18 bit number with 2 bits of decimal. Get rid of decimal portion.
lsb &= 0b00110000; //Bits 5/4 represent the fractional component
lsb >>= 4; //Get it right aligned
float pressure_decimal = (float)lsb/4.0; //Turn it into fraction
float pressure = (float)pressure_whole + pressure_decimal;
return(pressure);
}
float Weather::readBaroTemp()
{
if(IIC_Read(STATUS) & (1<<1) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for TDR bit, indicates we have new temp data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read temperature registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_T_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
if (Wire.requestFrom(MPL3115A2_ADDRESS, 2) != 2) { // Request two bytes
return -999;
}
byte msb, lsb;
msb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Negative temperature fix by D.D.G.
uint16_t foo = 0;
bool negSign = false;
//Check for 2s compliment
if(msb > 0x7F)
{
foo = ~((msb << 8) + lsb) + 1; //2’s complement
msb = foo >> 8;
lsb = foo & 0x00F0;
negSign = true;
}
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float templsb = (lsb>>4)/16.0; //temp, fraction of a degree
float temperature = (float)(msb + templsb);
if (negSign) temperature = 0 - temperature;
return(temperature);
}
//Give me temperature in fahrenheit!
float Weather::readBaroTempF()
{
return((readBaroTemp() * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
}
//Sets the mode to Barometer
//CTRL_REG1, ALT bit
void Weather::setModeBarometer()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<7); //Clear ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Sets the mode to Altimeter
//CTRL_REG1, ALT bit
void Weather::setModeAltimeter()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<7); //Set ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
void Weather::setModeStandby()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<0); //Clear SBYB bit for Standby mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
void Weather::setModeActive()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<0); //Set SBYB bit for Active mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
void Weather::setOversampleRate(byte sampleRate)
{
if(sampleRate > 7) sampleRate = 7; //OS cannot be larger than 0b.0111
sampleRate <<= 3; //Align it for the CTRL_REG1 register
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= 0b11000111; //Clear out old OS bits
tempSetting |= sampleRate; //Mask in new OS bits
IIC_Write(CTRL_REG1, tempSetting);
}
//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
void Weather::enableEventFlags()
{
IIC_Write(PT_DATA_CFG, 0x07); // Enable all three pressure and temp event flags
}
//Clears then sets the OST bit which causes the sensor to immediately take another reading
//Needed to sample faster than 1Hz
void Weather::toggleOneShot(void)
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<1); //Clear OST bit
IIC_Write(CTRL_REG1, tempSetting);
tempSetting = IIC_Read(CTRL_REG1); //Read current settings to be safe
tempSetting |= (1<<1); //Set OST bit
IIC_Write(CTRL_REG1, tempSetting);
}
// These are the two I2C functions in this sketch.
byte Weather::IIC_Read(byte regAddr)
{
// This function reads one byte over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr); // Address of CTRL_REG1
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 1); // Request the data...
return Wire.read();
}
void Weather::IIC_Write(byte regAddr, byte value)
{
// This function writes one byte over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr);
Wire.write(value);
Wire.endTransmission(true);
}
SparkFun_Photon_Weather_Shield_Library.h
/*
SparkFun Photon Weather Shield Particle Library
Compiled and Updated for Particle By: Joel Bartlett
SparkFun Electronics
Date: August 05, 2015
This library combines multiple libraries together to make development on the SparkFun
Photon Weather Shield easier. There are two versions of the Weather Shield, one containing
the HTU21D Temp and Humidity sensor and one containing the Si7021-A10. Shortages of the HTU21D
IC combined with contractual obligations led to the two versions existing. Thus, to make it
easier on you, the end user, we have written this library to automatically detect which version
you have without the need for you to have to figure it out and pick a corresponding library.
The MPL3115A2 library was added to avoid the need to import two separate libraries for
the shield.
This library is based on the following libraries:
MPL3115A2 Barometric Pressure Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 24th, 2013
https://github.com/sparkfun/MPL3115A2_Breakout
Spark Core HTU21D Temperature / Humidity Sensor Library
By: Romain MP
https://github.com/romainmp/HTU21D
Arduino Si7010 relative humidity + temperature sensor
Jakub Kaminski, 2014
https://github.com/teoqba/Si7020
This Library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For a copy of the GNU General Public License, see
<http://www.gnu.org/licenses/>.
*/
#include "application.h"//needed for all Particle libraries
#ifndef SparkFun_Photon_Weather_Shield_Library_h
#define SparkFun_Photon_Weather_Shield_Library_h
/****************Si7021 & HTU21D Definitions***************************/
#define ADDRESS 0x40
#define TEMP_MEASURE_HOLD 0xE3
#define HUMD_MEASURE_HOLD 0xE5
#define TEMP_MEASURE_NOHOLD 0xF3
#define HUMD_MEASURE_NOHOLD 0xF5
#define TEMP_PREV 0xE0
#define WRITE_USER_REG 0xE6
#define READ_USER_REG 0xE7
#define SOFT_RESET 0xFE
#define HTRE 0x02
#define _BV(bit) (1 << (bit))
#define CRC_POLY 0x988000 // Shifted Polynomial for CRC check
// Error codes
#define I2C_TIMEOUT 998
#define BAD_CRC 999
/****************MPL3115A2 Definitions************************************/
#define MPL3115A2_ADDRESS 0x60 // Unshifted 7-bit I2C address for sensor
#define STATUS 0x00
#define OUT_P_MSB 0x01
#define OUT_P_CSB 0x02
#define OUT_P_LSB 0x03
#define OUT_T_MSB 0x04
#define OUT_T_LSB 0x05
#define DR_STATUS 0x06
#define OUT_P_DELTA_MSB 0x07
#define OUT_P_DELTA_CSB 0x08
#define OUT_P_DELTA_LSB 0x09
#define OUT_T_DELTA_MSB 0x0A
#define OUT_T_DELTA_LSB 0x0B
#define WHO_AM_I 0x0C
#define F_STATUS 0x0D
#define F_DATA 0x0E
#define F_SETUP 0x0F
#define TIME_DLY 0x10
#define SYSMOD 0x11
#define INT_SOURCE 0x12
#define PT_DATA_CFG 0x13
#define BAR_IN_MSB 0x14
#define BAR_IN_LSB 0x15
#define P_TGT_MSB 0x16
#define P_TGT_LSB 0x17
#define T_TGT 0x18
#define P_WND_MSB 0x19
#define P_WND_LSB 0x1A
#define T_WND 0x1B
#define P_MIN_MSB 0x1C
#define P_MIN_CSB 0x1D
#define P_MIN_LSB 0x1E
#define T_MIN_MSB 0x1F
#define T_MIN_LSB 0x20
#define P_MAX_MSB 0x21
#define P_MAX_CSB 0x22
#define P_MAX_LSB 0x23
#define T_MAX_MSB 0x24
#define T_MAX_LSB 0x25
#define CTRL_REG1 0x26
#define CTRL_REG2 0x27
#define CTRL_REG3 0x28
#define CTRL_REG4 0x29
#define CTRL_REG5 0x2A
#define OFF_P 0x2B
#define OFF_T 0x2C
#define OFF_H 0x2D
/****************Si7021 & HTU21D Class**************************************/
class Weather
{
public:
// Constructor
Weather();
void begin();
// Si7021 & HTU21D Public Functions
float getRH();
float readTemp();
float getTemp();
float readTempF();
float getTempF();
void heaterOn();
void heaterOff();
void changeResolution(uint8_t i);
void reset();
uint8_t checkID();
//MPL3115A2 Public Functions
float readAltitude(); // Returns float with meters above sealevel. Ex: 1638.94
float readAltitudeFt(); // Returns float with feet above sealevel. Ex: 5376.68
float readPressure(); // Returns float with barometric pressure in Pa. Ex: 83351.25
float readBaroTemp(); // Returns float with current temperature in Celsius. Ex: 23.37
float readBaroTempF(); // Returns float with current temperature in Fahrenheit. Ex: 73.96
void setModeBarometer(); // Puts the sensor into Pascal measurement mode.
void setModeAltimeter(); // Puts the sensor into altimetery mode.
void setModeStandby(); // Puts the sensor into Standby mode. Required when changing CTRL1 register.
void setModeActive(); // Start taking measurements!
void setOversampleRate(byte); // Sets the # of samples from 1 to 128. See datasheet.
void enableEventFlags(); // Sets the fundamental event flags. Required during setup.
private:
//Si7021 & HTU21D Private Functions
uint16_t makeMeasurment(uint8_t command);
void writeReg(uint8_t value);
uint8_t readReg();
//MPL3115A2 Private Functions
void toggleOneShot();
byte IIC_Read(byte regAddr);
void IIC_Write(byte regAddr, byte value);
};
#endif
Weathershield.ino
/******************************************************************************
SparkFun_Photon_Weather_Wunderground.ino
SparkFun Photon Weather Shield basic example
Joel Bartlett @ SparkFun Electronics
Original Creation Date: May 18, 2015
Updated August 21, 2015
This sketch prints the temperature, humidity, and barometric pressure OR
altitude to the Serial port.
The library used in this example can be found here:
https://github.com/sparkfun/SparkFun_Photon_Weather_Shield_Particle_Library
Hardware Connections:
This sketch was written specifically for the Photon Weather Shield,
which connects the HTU21D and MPL3115A2 to the I2C bus by default.
If you have an HTU21D and/or an MPL3115A2 breakout, use the following
hardware setup:
HTU21D ------------- Photon
(-) ------------------- GND
(+) ------------------- 3.3V (VCC)
CL ------------------- D1/SCL
DA ------------------- D0/SDA
MPL3115A2 ------------- Photon
GND ------------------- GND
VCC ------------------- 3.3V (VCC)
SCL ------------------ D1/SCL
SDA ------------------ D0/SDA
Development environment specifics:
IDE: Particle Dev
Hardware Platform: Particle Photon
Particle Core
This code is beerware; if you see me (or any other SparkFun
employee) at the local, and you've found our code helpful,
please buy us a round!
Distributed as-is; no warranty is given.
//---------------------------------------------------------------
Weather Underground Upload sections: Dan Fein @ Weather Underground
Weather Underground Upload Protocol:
http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol
Sign up at http://www.wunderground.com/personal-weather-station/signup.asp
*******************************************************************************/
#include "SparkFun_Photon_Weather_Shield_Library.h"
#include "math.h" //For Dew Point Calculation
float humidity = 0;
float humTempF = 0; //humidity sensor temp reading, fahrenheit
float humTempC = 0; //humidity sensor temp reading, celsius
float baroTempF = 0; //barometer sensor temp reading, fahrenheit
float baroTempC = 0; //barometer sensor temp reading, celsius
float tempF = 0; //Average of the sensors temperature readings, fahrenheit
float tempC = 0; //Average of the sensors temperature readings, celsius
float dewptF = 0;
float dewptC = 0;
float pascals = 0;
float inches = 0;
//Wunderground Vars
//char SERVER[] = "rtupdate.wunderground.com"; //Rapidfire update server - for multiple sends per minute
char SERVER [] = "weatherstation.wunderground.com"; //Standard server - for sends once per minute or less
char WEBPAGE [] = "GET /weatherstation/updateweatherstation.php?";
//Station Identification
char ID [] = "KCAAUBUR39"; //Your station ID here
char PASSWORD [] = "Rv9530319"; //your Weather Underground password here
TCPClient client;
//Create Instance of HTU21D or SI7021 temp and humidity sensor and MPL3115A2 barometric sensor
Weather sensor;
//---------------------------------------------------------------
void setup()
{
Serial.begin(9600); // open serial over USB at 9600 baud
//Initialize the I2C sensors and ping them
sensor.begin();
/*You can only receive acurate barrometric readings or acurate altitiude
readings at a given time, not both at the same time. The following two lines
tell the sensor what mode to use. You could easily write a function that
takes a reading in one made and then switches to the other mode to grab that
reading, resulting in data that contains both acurate altitude and barrometric
readings. For this example, we will only be using the barometer mode. Be sure
to only uncomment one line at a time. */
sensor.setModeBarometer();//Set to Barometer Mode
//baro.setModeAltimeter();//Set to altimeter Mode
//These are additional MPL3115A2 functions the MUST be called for the sensor to work.
sensor.setOversampleRate(7); // Set Oversample rate
//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
sensor.enableEventFlags(); //Necessary register calls to enble temp, baro ansd alt
}
//---------------------------------------------------------------
void loop()
{
//Get readings from all sensors
getWeather();
//Print to console
printInfo();
//Send data to Weather Underground
sendToWU();
//Power down between sends to save power, measured in seconds.
System.sleep(SLEEP_MODE_DEEP,300); //for Particle Photon
//Spark.sleep(SLEEP_MODE_DEEP,300); //for Spark Core
}
//---------------------------------------------------------------
void printInfo()
{
//This function prints the weather data out to the default Serial Port
Serial.print("Temp:");
Serial.print(tempF);
Serial.print("F, ");
Serial.print("Humidity:");
Serial.print(humidity);
Serial.print("%, ");
Serial.print("Baro_Temp:");
Serial.print(baroTempF);
Serial.print("F, ");
Serial.print("Humid_Temp:");
Serial.print(humTempF);
Serial.print("F, ");
Serial.print("Pressure:");
Serial.print(pascals/100);
Serial.print("hPa, ");
Serial.print(inches);
Serial.println("in.Hg");
//The MPL3115A2 outputs the pressure in Pascals. However, most weather stations
//report pressure in hectopascals or millibars. Divide by 100 to get a reading
//more closely resembling what online weather reports may say in hPa or mb.
//Another common unit for pressure is Inches of Mercury (in.Hg). To convert
//from mb to in.Hg, use the following formula. P(inHg) = 0.0295300 * P(mb)
//More info on conversion can be found here:
//www.srh.noaa.gov/images/epz/wxcalc/pressureConversion.pdf
//If in altitude mode, print with these lines
//Serial.print("Altitude:");
//Serial.print(altf);
//Serial.println("ft.");
}
//---------------------------------------------------------------
void sendToWU()
{
Serial.println("connecting...");
if (client.connect(SERVER, 80)) {
Serial.println("Connected");
client.print(WEBPAGE);
client.print("ID=");
client.print(ID);
client.print("&PASSWORD=");
client.print(PASSWORD);
client.print("&dateutc=now"); //can use 'now' instead of time if sending in real time
client.print("&tempf=");
client.print(tempF);
client.print("&dewptf=");
client.print(dewptF);
client.print("&humidity=");
client.print(humidity);
client.print("&baromin=");
client.print(inches);
client.print("&action=updateraw"); //Standard update rate - for sending once a minute or less
//client.print("&softwaretype=Particle-Photon&action=updateraw&realtime=1&rtfreq=30"); //Rapid Fire update rate - for sending multiple times per minute, specify frequency in seconds
client.println();
Serial.println("Upload complete");
delay(300); //Without the delay it goes to sleep too fast and the send is unreliable
}else{
Serial.println(F("Connection failed"));
return;
}
}
//---------------------------------------------------------------
void getWeather()
{
// Measure Relative Humidity from the HTU21D or Si7021
humidity = sensor.getRH();
// Measure Temperature from the HTU21D or Si7021
humTempC = sensor.getTemp();
humTempF = (humTempC * 9)/5 + 32;
// Temperature is measured every time RH is requested.
// It is faster, therefore, to read it from previous RH
// measurement with getTemp() instead with readTemp()
//Measure the Barometer temperature in F from the MPL3115A2
baroTempC = sensor.readBaroTemp();
baroTempF = (baroTempC * 9)/5 + 32; //convert the temperature to F
//Measure Pressure from the MPL3115A2
pascals = sensor.readPressure();
inches = pascals * 0.0002953; // Calc for converting Pa to inHg (Wunderground expects inHg)
//If in altitude mode, you can get a reading in feet with this line:
//float altf = sensor.readAltitudeFt();
//Average the temperature reading from both sensors
tempC=((humTempC+baroTempC)/2);
tempF=((humTempF+baroTempF)/2);
//Calculate Dew Point
dewptC = dewPoint(tempC, humidity);
dewptF = (dewptC * 9.0)/ 5.0 + 32.0;
}
//---------------------------------------------------------------
// dewPoint function from NOAA
// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm
// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm
//---------------------------------------------------------------
double dewPoint(double celsius, double humidity)
{
// (1) Saturation Vapor Pressure = ESGG(T)
double RATIO = 373.15 / (273.15 + celsius);
double RHS = -7.90298 * (RATIO - 1);
RHS += 5.02808 * log10(RATIO);
RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
RHS += log10(1013.246);
// factor -3 is to adjust units - Vapor Pressure SVP * humidity
double VP = pow(10, RHS - 3) * humidity;
// (2) DEWPOINT = F(Vapor Pressure)
double T = log(VP/0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}
//---------------------------------------------------------------