/*
* WiFi Weather station with ESP-07 / ESP-12E and various sensor types
*
* 7.6.2017
* Copyleft Lumir Vanek
*/
#include <ESP8266WiFi.h>
#include <OneWire.h>
// WiFi AP definitions
const char AP_SSID[] = "SSID"; // Case sensitive !
const char AP_PASSWORD[] = "secret";
// IOT service site information
const char http_ip[] = "10.5.73.x";
const int http_port = 8080;
/**
* Allow turn some functionality ON/OFF - uncoment only one section with regards of which device programed !!!
*/
//************* Gargenhouse **************************
/*const char sensorCode_DallasTemp1[] = "LV_TEMP_01";
const char sensorCode_RSSI[] = "LV_RSSI_01";
#define _USE_DS18B20
#define ONE_WIRE_BUS 13 // DS18B20 pin*/
//****************************************************
//************* Workroom ******************************
/*
//const char sensorCode_DallasTemp1[] = "LV_TEMP_02";
const char sensorCode_Si7021Hum[] = "LV_HUM_03";
const char sensorCode_Si7021Temp[] = "LV_TEMP_12";
const char sensorCode_RSSI[] = "LV_RSSI_07";
//#define _USE_DS18B20
//#define ONE_WIRE_BUS 12 // DS18B20 pin
#define _USE_Si7021 // I2C Si7021 Humidity and Temperature sensor */
//****************************************************
//************* Greenhouse 1 *************************
/*const char sensorCode_DallasTemp1[] = "LV_TEMP_03";
const char sensorCode_BMP180Temp[] = "LV_TEMP_07";
const char sensorCode_BMP180Pres[] = "LV_PRES_02";
const char sensorCode_BMP180Atm[] = "LV_ATM_02";
const char sensorCode_BH1750Light[] = "LV_LIGH_01";
const char sensorCode_RSSI[] = "LV_RSSI_03";
#define _USE_DS18B20
#define ONE_WIRE_BUS 12 // DS18B20 pin
#define I2C_SDA 13
#define I2C_SCL 14
#define _USE_BH1750 // I2C Digital light sensor
#define _USE_BMP180 // I2C Digital pressure sensor*/
//****************************************************
//************* Greenhouse 2 *************************
/*const char sensorCode_Si7021Hum[] = "LV_HUM_02";
const char sensorCode_Si7021Temp[] = "LV_TEMP_10";
const char sensorCode_RSSI[] = "LV_RSSI_04";
#define I2C_SDA 12
#define I2C_SCL 13
#define _USE_Si7021 // I2C Si7021 Humidity and Temperature sensor*/
//************* Basen ********************************
/*const char sensorCode_DallasTemp1[] = "LV_TEMP_11"; // Solar panel
const char sensorCode_DallasTemp2[] = "LV_TEMP_08"; // Water
const char sensorCode_DallasTemp3[] = "LV_TEMP_04"; // Air
const char sensorCode_RSSI[] = "LV_RSSI_05";
#define ONE_WIRE_BUS 13 // DS18B20 pin
#define _USE_DS18B20
#define SECND_DS18B20_PRESENT
#define THIRD_DS18B20_PRESENT*/
//****************************************************
//************* Air quality **************************
/*#define I2C_SDA 12
#define I2C_SCL 13
//#define _USE_CCS811 // I2C CCS811 Air Quality sensor - Not works with ESP8266 for me */
//****************************************************
//************* Testboard ****************************
const char sensorCode_DallasTemp1[] = "LV_TEMP_06";
const char sensorCode_BMP180Temp[] = "LV_TEMP_05";
const char sensorCode_BMP180Pres[] = "LV_PRES_01";
const char sensorCode_BMP180Atm[] = "LV_ATM_01";
const char sensorCode_RSSI[] = "LV_RSSI_06";
#define _USE_DS18B20
#define ONE_WIRE_BUS 13 // DS18B20 pin
#define I2C_SDA 12
#define I2C_SCL 14
#define _USE_BMP180 // I2C Digital pressure sensor
//#define _USE_ADC // Read and send value from ADC
//****************************************************
#if defined(_USE_BMP180) || defined(_USE_BH1750) || defined(_USE_Si7021) || defined(_USE_CCS811)
#include <Wire.h> // I2C
#endif
#ifdef _USE_BMP180
#include <Adafruit_BMP085_U.h>
#define I2C_BMP180 0x77 // GY-68, Digital pressure sensor (0xEE >> 1)
#define SEA_LEVEL_PRESSURE 10100 // LKMT - Ostrava Mosnov airport QNH http://meteo.rlp.cz/LKMT_meteo.htm
//#define ALTITUDE 360 // Zasova - sklenik
#define ALTITUDE 366 // Zasova - doma
//#define ALTITUDE 322 // Valmez
#endif
#ifdef _USE_BH1750
#define I2C_BH1750 0x23 // GY-30, BH1750FVI 16-bit Light sensor. ADDR -> GND: Measurement with H-Resolution Mode2
#endif
#ifdef _USE_Si7021
#include "SparkFun_Si7021_Breakout_Library.h"
#endif
#ifdef _USE_CCS811
#include <SparkFunCCS811.h>
#endif
#define REPORT_INTERVAL 300 // in seconds
/**
* Global variables
*/
#ifdef _USE_DS18B20
#include <DallasTemperature.h>
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
#define TEMPERATURE_PRECISION 12
#endif
#ifdef _USE_BH1750
// Buffer for reading 16-bit value from BH1750 Light sensor
byte buff[2];
uint16_t old_valBH1750 = 0;
#endif
#ifdef _USE_BMP180
Adafruit_BMP085_Unified bmp085 = Adafruit_BMP085_Unified(10085);
#endif
#ifdef _USE_Si7021
// The Si7021 has a default I2C address of 0x40 and cannot be changed!
Weather si7021; //Create Instance of HTU21D or SI7021 temp and humidity sensor and MPL3115A2 barrometric sensor
#endif
#ifdef _USE_CCS811
#define I2C_CCS811 0x5B //Default I2C Address
CCS811 ccs811(I2C_CCS811);
#endif
long rssi = 0;
/**
* Connect to WiFi AP
* @return true if success, otherwise false
*/
boolean wifiConnect()
{
Serial.print("Connecting to AP");
// Set WiFi mode to station (client)
WiFi.mode(WIFI_STA);
// Initiate connection with SSID and PSK
WiFi.begin(AP_SSID, AP_PASSWORD);
int numberOfTries = 12;
while (WiFi.status() != WL_CONNECTED)
{
if(numberOfTries == 6)
{
WiFi.forceSleepWake();
WiFi.begin(AP_SSID, AP_PASSWORD);
Serial.print("x");
}
if(numberOfTries-- <= 0)
{
Serial.println("WiFi connect failed !");
return false;
}
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
rssi = WiFi.RSSI();
Serial.print("RSSI:");
Serial.println(rssi);
return true;
}
/**
* Send value to IOT service
*/
void sendValue(const char * sensorCode, float value)
{
WiFiClient client;
int numberOfTries = 5;
while(!client.connect(http_ip, http_port))
{
Serial.println("Connection to IOT service failed !");
if(numberOfTries-- <=0) return;
wifiConnect();
}
Serial.println("Connected");
String url = "/IotService/rest/insert-value/" + String(sensorCode) + "/" + String(value);
Serial.print("GET data to URL: ");
Serial.println(url);
// Make an HTTP GET request
client.print( "GET " + url + " HTTP/1.1\r\n");
client.print("Host: " + String(http_ip) + "\r\n");
client.print("Connection: close\r\n");
client.println();
delay(100);
while(client.available())
{
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("Connection closed");
}
void setup()
{
Serial.begin(115200);
delay(10);
Serial.println("Initializing ESP8266 module");
#ifdef _USE_DS18B20
DS18B20.begin();
#endif
#if defined(_USE_BMP180) || defined(_USE_BH1750) || defined(_USE_Si7021) || defined(_USE_CCS811)
Serial.println("Initializing I2C bus");
Wire.pins(I2C_SDA, I2C_SCL);
Wire.begin(); // join I2C bus
Wire.pins(I2C_SDA, I2C_SCL);
#endif
#ifdef _USE_BH1750
/*
* Init GY-30, BH1750FVI I2C 16 bit Light sensor.
*/
bh1750Init(I2C_BH1750);
#endif
#ifdef _USE_BMP180
/*
* Init GY-68, BMP180 I2C Digital pressure sensor support.
*/
if (!bmp085.begin())
{
Serial.print("Ooops, no BMP180 detected ... Check your wiring or I2C ADDR!");
while (1);
}
else
{
Serial.println("BMP180 ready.");
}
#endif
#ifdef _USE_Si7021
/*
* Init Si7021 I2C temp and humidity sensor
*/
si7021.begin();
#endif
#ifdef _USE_CCS811
/*
* Init CCS811 I2C Air Quality sensor
*/
delay(1000);
//This begins the CCS811 sensor and prints error status of .begin()
CCS811Core::status returnCode = ccs811.begin();
Serial.print("CCS811 begin exited with: ");
//Pass the error code to a function to print the results
printCCS811DriverError(returnCode);
Serial.println();
#endif
pinMode(A0, INPUT);
}
void loop()
{
float temperature;
#ifdef _USE_DS18B20
/*
* Temperarure from Dallas DS18B20 chip's
*/
do
{
DS18B20.setResolution(TEMPERATURE_PRECISION);
DS18B20.requestTemperatures();
temperature = DS18B20.getTempCByIndex(0);
Serial.print("Temperature 1: ");
Serial.print(temperature);
Serial.println(" deg C");
} while (temperature == 85.0 || temperature == (-127.0));
if (wifiConnect() == false)
{
goDeepSleep();
return;
}
sendValue(sensorCode_DallasTemp1, temperature);
#endif
#ifdef SECND_DS18B20_PRESENT
do
{
temperature = DS18B20.getTempCByIndex(1);
Serial.print("Temperature 2: ");
Serial.print(temperature);
Serial.println(" deg C");
} while (temperature == 85.0 || temperature == (-127.0));
sendValue(sensorCode_DallasTemp2, temperature);
#endif
#ifdef THIRD_DS18B20_PRESENT
do
{
temperature = DS18B20.getTempCByIndex(2);
Serial.print("Temperature 3: ");
Serial.print(temperature);
Serial.println(" deg C");
} while (temperature == 85.0 || temperature == (-127.0));
sendValue(sensorCode_DallasTemp3, temperature);
#endif
delay(200);
#ifndef _USE_DS18B20 // If Dallas chpis not used, we're not connnected yet
if (wifiConnect() == false)
{
goDeepSleep();
return;
}
#endif
#ifdef _USE_BMP180
/*
* BMP180 values
*/
// Get a new sensor event
sensors_event_t bmpEvent;
bmp085.getEvent(&bmpEvent);
if (bmpEvent.pressure)
{
bmp085.getTemperature(&temperature);
Serial.print("BMP180 Temperature: ");
Serial.print(temperature);
Serial.println(" deg C");
sendValue(sensorCode_BMP180Temp, temperature);
delay(200);
float pressure = bmpEvent.pressure;
Serial.print("Atm pressure: ");
Serial.print(pressure);
Serial.println(" hPa");
sendValue(sensorCode_BMP180Atm, pressure);
float slPressure = calcSealevelPressure(ALTITUDE, pressure, temperature);
Serial.print("Sea level pressure: ");
Serial.print(slPressure);
Serial.println(" hPa");
sendValue(sensorCode_BMP180Pres, slPressure);
}
else
{
Serial.println("BMP180 Sensor error");
}
#endif
#ifdef _USE_BH1750
uint16_t val = 0;
if(2 == bh1750Read(I2C_BH1750))
{
val = ((buff[0] << 8) | buff[1]) / 1.2;
Serial.print("Light: ");
Serial.print(val);
sendValue(sensorCode_BH1750Light, val);
}
#endif
#ifdef _USE_Si7021
float humidity7021 = si7021.getRH();
float temperature7021 = si7021.getTemp();
Serial.print("Si7021 Humidity: ");
Serial.print(humidity7021);
Serial.println(" %");
sendValue(sensorCode_Si7021Hum, humidity7021);
Serial.print("Si7021 Temperature: ");
Serial.print(temperature7021);
Serial.println(" deg C");
sendValue(sensorCode_Si7021Temp, temperature7021);
#endif
#ifdef _USE_CCS811
//Check to see if data is available
if (ccs811.dataAvailable())
{
//Calling this function updates the global tVOC and eCO2 variables
ccs811.readAlgorithmResults();
/*
#ifdef _USE_Si7021
//This sends the temperature data to the CCS811
ccs811.setEnvironmentalData(humidity7021, temperature7021);
#else
ccs811.setRefResistance( 9950 );
ccs811.readNTC();
Serial.print(" Measured resistance : ");
//After .readNTC() is called, .getResistance() can be called to actually
//get the resistor value. This is not needed to get the temperature,
//but can be useful information for debugging.
//
//Use the resistance value for custom thermistors, and calculate the
//temperature yourself.
Serial.print( ccs811.getResistance() );
Serial.println(" ohms");
//After .readNTC() is called, .getTemperature() can be called to get
//a temperature value providing that part SEN-00250 is used in the
//NTC terminals. (NTCLE100E3103JB0)
Serial.print(" Converted temperature : ");
float readTemperature = ccs811.getTemperature();
Serial.print(readTemperature, 2);
Serial.println(" deg C");
//Pass the temperature back into the CCS811 to compensate
myCCS811.setEnvironmentalData(50, readTemperature);
#endif*/
Serial.print(" CO2 concentration : ");
float co2 = ccs811.getCO2();
Serial.print(co2);
Serial.println(" ppm");
sendValue(sensorCode_CCS811CO2, co2);
Serial.print(" TVOC concentration : ");
float voc = ccs811.getTVOC();
Serial.print(voc);
Serial.println(" ppb");
sendValue(sensorCode_CCS811VOC, voc);
}
else if (ccs811.checkForStatusError())
{
//If the CCS811 found an internal error, print it.
printCCS811SensorError();
}
#endif
#ifdef _USE_ADC
int adcValue = analogRead(A0);
sendValue("ADC_TESTBRD", adcValue);
#endif
/*
* Send WiFi signal strength
*/
rssi = WiFi.RSSI();
sendValue(sensorCode_RSSI, (float) rssi);
/*
* Standard sleep, it eats too many energy from baterry
*/
/*int cnt = REPORT_INTERVAL;
while(cnt--)
delay(1000);*/
goDeepSleep();
}
void goDeepSleep()
{
/*
* Connect GPIO16 to RST to deep sleep functionality
* ESP07-12E eats 6.4 mA while deep sleep
*/
Serial.print("Going to deep sleep");
delay(200);
//sleep and try again
ESP.deepSleep(REPORT_INTERVAL * 1000 * 1000, WAKE_RF_DEFAULT); // x min. update interval
delay(1000);
}
///////////////////////////////////////////////////////////////////////////
//
// BH1750 Light sensor support
//
///////////////////////////////////////////////////////////////////////////
#ifdef _USE_BH1750
int bh1750Read(int address)
{
int i = 0;
Wire.beginTransmission(address);
Wire.requestFrom(address, 2);
while(Wire.available())
{
buff[i++] = Wire.read(); // receive one byte
}
Wire.endTransmission();
return i;
}
void bh1750Init(int address)
{
Wire.beginTransmission(address);
Wire.write(0x10); //1lx resolution 120ms
Wire.endTransmission();
}
#endif
///////////////////////////////////////////////////////////////////////////
//
// BMP180 Digital pressure sensor support
//
///////////////////////////////////////////////////////////////////////////
#ifdef _USE_BMP180
float calcAltitude(float pressure)
{
return 44330.0 * (1 - pow(pressure / SEA_LEVEL_PRESSURE, (1 / 5.25588)));
}
float calcMeanPressure(float altitude)
{
return pow(1.0 - (altitude / 44330.0), 5.25588) * SEA_LEVEL_PRESSURE;
}
/*
* http://keisan.casio.com/exec/system/1224575267
*/
float calcSealevelPressure(float altitude, float atm, float temperature)
{
float alt = (0.0065 * altitude);
return atm * pow(1.0 - (alt / (temperature + alt + 273.15)), -5.25588);
}
#endif
#ifdef _USE_CCS811
///////////////////////////////////////////////////////////////////////////
//
// CCS811 Air Quality sensor support
//
///////////////////////////////////////////////////////////////////////////
/*
* Decode the CCS811Core::status type and prints the type of error to the serial terminal.
*
* Save the return value of any function of type CCS811Core::status, then pass
* to this function to see what the output was.
*/
void printCCS811DriverError(CCS811Core::status errorCode)
{
switch (errorCode)
{
case CCS811Core::SENSOR_SUCCESS:
Serial.print("CCS811 SUCCESS");
break;
case CCS811Core::SENSOR_ID_ERROR:
Serial.print("CCS811 ID ERROR");
break;
case CCS811Core::SENSOR_I2C_ERROR:
Serial.print("CCS811 I2C ERROR");
break;
case CCS811Core::SENSOR_INTERNAL_ERROR:
Serial.print("CCS811 INTERNAL ERROR");
break;
case CCS811Core::SENSOR_GENERIC_ERROR:
Serial.print("CCS811 GENERIC ERROR");
break;
default:
Serial.print("Unspecified error.");
}
}
/*
* Gets, clears, then prints the errors saved within the error register.
*/
void printCCS811SensorError()
{
uint8_t error = ccs811.getErrorRegister();
if (error == 0xFF) //comm error
{
Serial.println("Failed to get ERROR_ID register.");
}
else
{
Serial.print("Error: ");
if (error & 1 << 5) Serial.print("HeaterSupply");
if (error & 1 << 4) Serial.print("HeaterFault");
if (error & 1 << 3) Serial.print("MaxResistance");
if (error & 1 << 2) Serial.print("MeasModeInvalid");
if (error & 1 << 1) Serial.print("ReadRegInvalid");
if (error & 1 << 0) Serial.print("MsgInvalid");
Serial.println();
}
}
#endif