Skip to content

Instantly share code, notes, and snippets.

@dadosch
Created May 2, 2020 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dadosch/71253c0f5f52be0457114451374d28f6 to your computer and use it in GitHub Desktop.
Save dadosch/71253c0f5f52be0457114451374d28f6 to your computer and use it in GitHub Desktop.
esp8266 with CCS811 and deep sleep
const int FW_VERSION = 01;
const char* fwUrlBase = "http://someurl.tld/esp_update/";
#include "main.h"
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
//needed for WifiManager
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
// for firmware update
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#ifdef USE_BMP180
// I2C: 0x77
#include <Wire.h>
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
boolean bmp180_available=true;
#endif
#ifdef USE_BME280
// I2C: 0x76
#include <BME280I2C.h>
#include <Wire.h>
BME280I2C::Settings bme280Settings(
BME280::OSR_X1,
BME280::OSR_X1,
BME280::OSR_X1,
BME280::Mode_Forced,
BME280::StandbyTime_1000ms,
BME280::Filter_Off,
BME280::SpiEnable_False,
BME280I2C::I2CAddr_0x76 // I2C address. I2C specific.
);
BME280I2C bme280(bme280Settings);
boolean bme280_available=true;
#endif
#ifdef USE_BH1750
// I2C: 0x23
#include <Wire.h>
#include <BH1750.h>
BH1750 bh1750(0x23);
boolean bh1750_available=true;
#endif
#ifdef USE_CCS811
#include <Wire.h> // I2C library
// I2C: 0x5A
#include <ccs811.h>
CCS811 ccs811;
boolean ccs811_available=true;
#endif
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
const String MQTT_USERNAME = "user";
const String MQTT_PASSWORD = "pass";
ADC_MODE(ADC_VCC);
String macToStr(const uint8_t* mac){
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
}
return result;
}
String getMAC(){
String clientMac = "";
unsigned char mac[6];
WiFi.macAddress(mac);
clientMac += macToStr(mac);
return String( clientMac );
}
void checkForUpdates() {
String mac = getMAC();
String fwURL = String( fwUrlBase );
fwURL.concat( mac );
String fwVersionURL = fwURL;
fwVersionURL.concat( ".version" );
Serial.println( "Checking for firmware updates." );
Serial.print( "MAC address: " );
Serial.println( mac );
Serial.print( "Firmware version URL: " );
Serial.println( fwVersionURL );
HTTPClient httpClient;
httpClient.begin(wifiClient, fwVersionURL );
int httpCode = httpClient.GET();
if( httpCode == 200 ) {
String newFWVersion = httpClient.getString();
Serial.print( "Current firmware version: " );
Serial.println( FW_VERSION );
Serial.print( "Available firmware version: " );
Serial.println( newFWVersion );
int newVersion = newFWVersion.toInt();
if( newVersion > FW_VERSION ) {
Serial.println( "Preparing to update" );
String fwImageURL = fwURL;
fwImageURL.concat( ".bin" );
t_httpUpdate_return ret = ESPhttpUpdate.update(wifiClient, fwImageURL );
switch(ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
break;
}
}
else {
Serial.println( "Already on latest version" );
}
}
else {
Serial.print( "Firmware version check failed, got HTTP response code " );
Serial.println( httpCode );
}
httpClient.end();
}
void connectWiFiAndMqtt(){
Serial.println("now starting WiFiManager…");
WiFiManager wifiManager;
wifiManager.autoConnect();
Serial.println("WiFiManager started and connected.");
checkForUpdates();
Serial.println("now starting MQTT…");
mqttClient.setServer("host", 1883);
while(! mqttClient.connected()){
Serial.print("connecting...");
String clientId = "sensorhub-";
clientId += String(ESP.getChipId());
mqttClient.connect(clientId.c_str(),MQTT_USERNAME.c_str(),MQTT_PASSWORD.c_str());
}
Serial.println("mqtt connected.");
}
void initializeSensors(){
Serial.println("now starting sensors…");
#ifdef USE_BH1750
// Wire is not started by BH1750, but by Adafruit library.
Wire.begin();
if(!bh1750.begin(BH1750::ONE_TIME_HIGH_RES_MODE)){
Serial.println("Could not find a valid BH1750 sensor, check wiring!");
bh1750_available=false;
}
#endif
#ifdef USE_BMP180
if (!bmp.begin()) {
Serial.println("Could not find a valid BMP180 sensor, check wiring!");
bmp180_available=false;
}
#endif
#ifdef USE_BME280
Wire.begin();
if(!bme280.begin()){
Serial.println("Could not find a valid BME280 sensor, check wiring!");
bme280_available=false;
}
#endif
#ifdef USE_CCS811
Wire.begin();
ccs811.set_i2cdelay(50); // Needed for ESP8266 because it doesn't handle I2C clock stretch correctly
rst_info * rstinfo = ESP.getResetInfoPtr();
// when NOT coming out of deepsleep:
if (rstinfo->reason != REASON_DEEP_SLEEP_AWAKE){
// setup ccs811 into correct mode
Serial.println("CCS811: setup begins.");
bool ok= ccs811.begin();
if( !ok ) Serial.println("setup: CCS811 begin FAILED");
ok= ccs811.start(CCS811_MODE_60SEC);
if( !ok ){
// start failed!
Serial.println("setup: CCS811 start FAILED");
}
}else{
// we come out of deep sleep and ccs811 is in known state.
Serial.println("CCS811: setup already done.");
}
#endif
}
void submitSensorData(String sensorName, String whatIsMeasured,float value){
Serial.println(sensorName+" Sensor data: "+whatIsMeasured + " " +String(value));
String mqttId = String(ESP.getChipId());
String topic = "sensors/"+mqttId;
String mqttValue = "{\""+whatIsMeasured+"\":"+String(value)+"}";
mqttClient.publish(topic.c_str(), mqttValue.c_str());
}
void runSensors(){
#ifdef USE_BMP180
if(bmp180_available){
float bmp180_temp = bmp.readTemperature();
float bmp180_press = bmp.readPressure();
submitSensorData("bmp180","temp",bmp180_temp);
submitSensorData("bmp180","press",bmp180_press);
}
#endif
#ifdef USE_BME280
if(bme280_available){
float bme280_press, bme280_temp, bme280_hum;
bme280.read(bme280_press, bme280_temp, bme280_hum);
submitSensorData("bme280","press",bme280_press);
submitSensorData("bme280","temp",bme280_temp);
submitSensorData("bme280","hum",bme280_hum);
}
#endif
#ifdef USE_BH1750
float bh1750_lightlevel = bh1750.readLightLevel();
submitSensorData("bh1750","lightlevel",bh1750_lightlevel);
#endif
#ifdef USE_CCS811
uint16_t eco2, etvoc, errstat, raw;
ccs811.read(&eco2,&etvoc,&errstat,&raw);
// Print measurement results based on status
if( errstat==CCS811_ERRSTAT_OK ) {
// everything is fine, we have new data
submitSensorData("ccs811","eco2",eco2);
submitSensorData("ccs811","etvoc",etvoc);
} else if( errstat==CCS811_ERRSTAT_OK_NODATA ) {
// everything is fine, but there is no new data yet.)
Serial.println("CCS811: waiting for (new) data");
} else if( errstat & CCS811_ERRSTAT_I2CFAIL ) {
// I2C Connection failed
Serial.println("CCS811: I2C error");
} else {
// other error
Serial.print("CCS811: errstat="); Serial.print(errstat,HEX);
Serial.print("="); Serial.println( ccs811.errstat_str(errstat) );
}
#endif
// submit power supply (battery voltage)
float esp_vcc = ESP.getVcc();
submitSensorData("esp8266","vcc",esp_vcc);
}
void setup() {
Serial.begin(115200);
Serial.println("sensor station started.");
connectWiFiAndMqtt();
initializeSensors();
runSensors();
mqttClient.disconnect();
Serial.println("going to sleep now!");
//sleep 60 seconds, with 2 extra seconds, because ccs811's clock might be not too accurate.
ESP.deepSleep(62e6);
}
void loop() {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment