Skip to content

Instantly share code, notes, and snippets.

@Bolukan
Created December 18, 2018 20:08
Show Gist options
  • Select an option

  • Save Bolukan/a0e1016219d8e6c588ae925b2b2b2888 to your computer and use it in GitHub Desktop.

Select an option

Save Bolukan/a0e1016219d8e6c588ae925b2b2b2888 to your computer and use it in GitHub Desktop.
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h> // BME280 library demand
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include <WiFiClient.h>
#include <PubSubClient.h>
#include "secrets.h"
#include <time.h>
#include <rtcmem.h>
#include <CRC32.h>
#include <BME280I2C.h>
/*
* CONSTANTS
*/
// wifi
#ifndef SECRETS_H
#define SECRETS_H
const char WIFI_SSID[] = "*** WIFI SSID ***";
const char WIFI_PASSWORD[] = "*** WIFI PASSWORD ***";
#endif
// time
const char TIME_NTPSERVER_1[] = "nl.pool.ntp.org";
const char TIME_NTPSERVER_2[] = "pool.ntp.org";
// other
const uint32_t SECONDS_OFFSET = 60;
const uint64_t SLEEPTIME = 60e6;
const long SERIAL_BAUD = 115200;
//const int SENSOR_INTERVAL_MILLIS = 60000;
// http log
const char* SERVER = "xxx.xxx.org";
const char* HTTPGET = "deviceid=%d&sensorid=%d&secondsoffset=%d&humidity=%d&pressure=%d&temperature=%d";
const char* MQTTPUB = "{'deviceid':%d,'sensorid':%d,'secondsoffset':%d,'humidity':%d,'pressure':%d,'temperature':%d}";
const char* MQTT_SERVER = "192.168.1.100";
const int MQTT_PORT = 1883;
ADC_MODE(ADC_VCC);
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
/*
* GLOBALS
*/
// BME280
BME280I2C::Settings settings(
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 bme(settings);
typedef struct {
uint32_t hum100;
uint32_t pres100;
int32_t temp100;
} sensorData;
sensorData sensordata;
// rtcmem
RTCMEM localmemory;
/*
* FUNCTIONS
*/
// wifi on, get time
void connectToWiFi() {
//Serial.printf("%u: ConnectToWiFi start\n", millis());
WiFi.forceSleepWake();
delay(1);
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
configTime(0, 0, TIME_NTPSERVER_1, TIME_NTPSERVER_2);
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 0);
Serial.printf("%lu: ConnectToWiFi\n", millis());
}
// save mem, wifi off, sleep
void GoToSleep() {
localmemory.saveMem();
WiFi.disconnect(true);
delay(1);
WiFi.mode(WIFI_OFF);
WiFi.forceSleepBegin();
delay(5);
Serial.printf("%lu: Going to sleep\n", millis());
Serial.flush();
// WAKE_RF_DISABLED to keep the WiFi radio disabled when we wake up
ESP.deepSleep( SLEEPTIME, RF_DISABLED );
}
char* dtostrfd(double number, unsigned char prec, char *s)
{
if ((isnan(number)) || (isinf(number))) { // Fix for JSON output (https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript)
strcpy(s, "null");
return s;
} else {
return dtostrf(number, 1, prec, s);
}
}
// deviceID
uint32_t deviceid()
{
#if defined(ESP8266)
return ESP.getChipId();
#elif defined(ESP32)
return ESP.getEfuseMac() & 0xffffff;
#endif
}
// sensorID
uint32_t sensorid()
{
uint8_t test[32];
CRC32 crc;
return CRC32::calculate(bme.compensationParameters(test), 32);
}
void setup() {
// Set WiFi Off
WiFi.mode(WIFI_OFF);
WiFi.forceSleepBegin();
delay(1);
// Serial
Serial.begin(SERIAL_BAUD);
Serial.println();
// BME280
Serial.println(F("Starting BME280"));
Wire.begin();
if (!bme.begin()) {
Serial.println(F("Could not find BME280 sensor"));
Serial.println(F("You have 60 seconds to connect the wires ..."));
delay(60000);
ESP.restart();
}
if (bme.chipModel() != BME280::ChipModel_BME280) {
Serial.println(F("Found BME280, but not full BME280 model"));
Serial.println(F("You have 60 seconds to connect a full BME280 ..."));
delay(60000);
ESP.restart();
}
// RTCMEM
if (localmemory.loadMem()) {
Serial.print("RTCMEM: OK Records: ");
Serial.println(localmemory.recordCount());
} else {
Serial.println("RTCMEM: Error");
localmemory.reset(sizeof(sensordata));
}
}
void loop() {
// read BME280
float temp(NAN), hum(NAN), pres(NAN);
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
bme.read(pres, temp, hum, tempUnit, presUnit);
sensordata.hum100 = (uint32_t)(hum * 100);
sensordata.pres100 = (uint32_t)(pres * 100);
sensordata.temp100 = (int32_t)(temp * 100);
// save in rtc memory
localmemory.addRecord(&sensordata, sizeof(sensordata));
// Check for transfering memory
if (localmemory.recordCount() > 5 || localmemory.isMemoryFull())
{
// deviceID and sensorID
uint32_t deviceID = deviceid();
uint32_t sensorID = sensorid();
char buffer[200];
char topic[100];
// WiFi and time
WiFiClient client;
connectToWiFi();
while (WiFi.status() != WL_CONNECTED) delay(1);
while (time(nullptr) < 24 * 3600) delay(1);
// mqtt
PubSubClient mqtt(MQTT_SERVER, MQTT_PORT, callback, client);
mqtt.setServer(MQTT_SERVER, MQTT_PORT);
String clientId = "ESP";
clientId += String(deviceID, HEX);
// Attempt to connect
if (mqtt.connect(clientId.c_str())) {
Serial.println("Connected");
} else {
Serial.println("MQTT not connected");
}
// VCC log
char sVCC[33];
dtostrfd((double)ESP.getVcc()/1000, 3, sVCC);
sprintf(topic, "sensor/%d/tele", deviceID);
sprintf(buffer, "{\"deviceid\":%d,\"VCC\":\"%s\"}", deviceID, sVCC);
mqtt.publish(topic, buffer);
mqtt.loop();
uint16_t records = localmemory.recordCount();
uint16_t recordnr = 0;
while (recordnr < records)
{
localmemory.getRecord(&sensordata, recordnr);
sprintf(topic, "sensor/%d/bme280/%d", deviceID, sensorID);
sprintf(buffer, "{\"deviceid\":%d,\"sensorid\":%d,\"o\":%d,\"h\":%d,\"p\":%d,\"t\":%d}",
deviceID, sensorID, (records-recordnr-1) * SECONDS_OFFSET, sensordata.hum100, sensordata.pres100, sensordata.temp100);
Serial.printf("%s %s\n", topic, buffer);
mqtt.publish(topic, buffer);
mqtt.loop();
delay(50);
recordnr++;
}
delay(50);
//mqtt.disconnect();
localmemory.reset(sizeof(sensordata));
}
GoToSleep();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment