fw_mega/fw_mega.ino

591 lines
16 KiB
Arduino
Raw Normal View History

#include <Wire.h>
2020-02-14 14:19:51 +01:00
// display mapping suggestion for Arduino MEGA
// BUSY -> 7, RST -> 9, DC -> 8, CS-> 53, CLK -> 52, DIN -> 51
#include <GxEPD2_BW.h>
#include <Fonts/FreeSans18pt7b.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/TomThumb.h>
2020-02-14 14:19:51 +01:00
#include <MD_DS3231.h>
//#include <BME280I2C.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
2020-04-10 14:01:56 +02:00
#include<bc_co2_module_arduino.h>
2020-02-14 14:19:51 +01:00
//BME280I2C bme;
Adafruit_BME280 bme;
2020-02-15 22:03:22 +01:00
/**************************** Serial setup ************************************/
#define BAUDRATE 115200
2020-02-14 14:19:51 +01:00
2020-02-15 22:03:22 +01:00
/**************************** I2C setup **************************************/
2020-02-14 14:19:51 +01:00
2020-02-15 22:03:22 +01:00
#define BME280_ADDR 0x76
#define BME280_ID 0x60
2020-02-14 14:19:51 +01:00
/**************************** Screen setup **********************************/
2020-02-14 14:19:51 +01:00
#define MAX_DISPAY_BUFFER_SIZE 32 //
2020-02-15 22:03:22 +01:00
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW<GxEPD2_290, MAX_HEIGHT(GxEPD2_290)> display(GxEPD2_290(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
/*************************** Global variables *********************************/
2020-02-14 14:19:51 +01:00
struct data {
2020-02-14 15:21:43 +01:00
float temp;
float hum;
int rhum;
float pres;
unsigned int rpres;
2020-04-10 14:01:56 +02:00
int16_t co2;
2020-02-14 14:19:51 +01:00
};
volatile static struct data dataset;
char incoming[40];
bool commRecvd = false;
char ssid[16];
char ip[16];
2020-02-14 14:19:51 +01:00
//
2020-02-15 22:03:22 +01:00
void setup() {
char buf;
static byte i=0;
ADCSRA = 0; //turn off adc to save power as it is not needed
2020-02-15 22:03:22 +01:00
pinMode(13, OUTPUT);
digitalWrite(13, LOW); //turn off led
2020-02-15 22:03:22 +01:00
Serial.begin(BAUDRATE);
Serial2.begin(BAUDRATE);
Wire.begin();
2020-04-10 14:01:56 +02:00
Serial.print(F("\r\n***Enviro data monitor***\r\n"));
//start co2 module
2020-04-10 14:01:56 +02:00
init_module();
2020-04-10 14:01:56 +02:00
while(!bme.begin(BME280_ADDR)) { //for adafruit driver
// while(!bme.begin()) { //for bme280i2c driver
Serial.println(F("Could not find BME280 sensor"));
2020-02-15 22:03:22 +01:00
delay(1000);
}
2020-04-10 14:01:56 +02:00
//for adafruit driver
2020-02-15 22:03:22 +01:00
if(bme.sensorID() == BME280_ID){
2020-04-10 14:01:56 +02:00
Serial.println(F("Found BME280 sensor"));
2020-02-15 22:03:22 +01:00
}
else {
2020-04-10 14:01:56 +02:00
Serial.println(F("Found unknown sensor"));
2020-02-15 22:03:22 +01:00
}
2020-04-10 14:01:56 +02:00
//for bme280i2c driver
// switch(bme.chipModel()) {
// case BME280::ChipModel_BME280:
// Serial.println(F("Found BME280 sensor!"));
// break;
// case BME280::ChipModel_BMP280:
// Serial.println(F("Found BMP280 sensor! No Humidity available."));
// break;
// default:
// Serial.println(F("Error, found UNKNOWN sensor."));
// }
2020-04-10 14:01:56 +02:00
display.init(); //init display
2020-02-15 22:03:22 +01:00
delay(100);
layoutScreen(); //print static parts of screen
//make sure we're always in 24hr mode
if(RTC.status(DS3231_12H)){ //invert to change to 12h
RTC.control(DS3231_12H, DS3231_OFF); //use DS3231_ON to enable 12h mode
2020-02-15 22:03:22 +01:00
switch (RTC.status(DS3231_12H) ){
2020-04-10 14:01:56 +02:00
case 0: Serial.println(F("24h mode"));
case 1: Serial.println(F("12h mode")); //should not occur
2020-02-15 22:03:22 +01:00
}
}
delay(2000); //leave time for esp to connect to wireless network
static bool recv = false;
while(Serial2.available() > 0) {
buf = Serial2.read();
if(recv == true) {
if(buf != '\n'){
incoming[i] = buf;
i++;
}
else {
incoming[i] = '\0';
recv = false;
i = 0;
commRecvd = true;
}
}
else if (buf == '!'){
recv = true;
}
}
i = 0;
if(commRecvd == true){
char* token = strtok(incoming, ",");
while(token != NULL){
if(i == 0){
sprintf(ssid,"%s", token);
};
if(i == 1) {
sprintf(ip,"%s", token);
};
token = strtok(NULL, ",");
i++;
}
i = 0;
commRecvd = false;
printConnInfo();
Serial.print(F("Got conn info:\n"));
Serial.println(ssid);
Serial.println(ip);
}
static byte retries = 0;
2020-02-15 22:03:22 +01:00
while(!syncTime()){ //sync time with network
delay(1750); //should take about a second and a half
retries++;
if(retries > 4){
break; //break the loop in case of no connectivity/ other error
}
2020-02-15 22:03:22 +01:00
}
printRTCTimeToScreen(); //print time to screen
printRTCDateToScreen(); //print date to screen
2020-04-10 14:01:56 +02:00
Serial.println(F("Setup complete"));
2020-02-14 14:19:51 +01:00
};
void loop() {
static byte oldmins;
2020-02-14 15:21:43 +01:00
RTC.readTime();
if(RTC.m != oldmins){ //run this every minute
printRTCTimeToScreen(); //update time on screen
doStuff(); //acquire data
sendDataToServer(); //send over to esp for publishing
printTempToScreen(); //update values on screen
oldmins = RTC.m; //save old value
2020-02-14 15:21:43 +01:00
}
else if((RTC.m == 0 || RTC.m == 30) && RTC.s == 55) {
delay(1100); //delay to prevent firing multiple times
display.refresh(); //perform a full display refresh every half hour, removes quick refresh artifacts
}
else if(RTC.m == 0 && RTC.h == 0 && RTC.s == 40){
delay(1100); //delay to prevent firing multiple times
printRTCDateToScreen(); //change date on midnight
}
//sync time every morning and evening. only here for safety should the device run for long periods of time without restarting
if ((RTC.h == 6 || RTC.h == 22) && (RTC.m == 00) && RTC.s == 40){
delay(1100); //delay to prevent firing multiple times
static byte retries = 0;
while(!syncTime()){ //sync time with network
delay(1500); //should take about a second and a half
retries++;
if(retries > 4){
break; //break the loop in case of no connectivity
}
}
2020-02-14 15:21:43 +01:00
}
};
2020-02-14 14:19:51 +01:00
2020-02-15 22:03:22 +01:00
void doStuff() {
//function to acquire and save data from sensors
2020-02-15 22:03:22 +01:00
dataset.temp = measureTemp();
dataset.hum = measureHum();
dataset.rhum = round(dataset.hum);
dataset.pres = measurePres();
dataset.rpres = round(dataset.pres);
2020-04-10 14:01:56 +02:00
dataset.co2 = measureCO2();
2020-02-15 22:03:22 +01:00
};
bool syncTime() {
2020-02-14 15:21:43 +01:00
char tbuf;
static bool trecvd = false;
static bool trecvn = false;
char tarry[21];
static byte j = 0;
2020-04-10 14:01:56 +02:00
Serial.print(F("Syncing time...\n"));
2020-02-14 15:21:43 +01:00
delay(50);
Serial2.print("?ntp");
Serial2.print("\n");
2020-02-15 22:03:22 +01:00
delay(25);
2020-02-14 15:21:43 +01:00
while(Serial2.available() > 0 && trecvd == false){
tbuf = Serial2.read();
if(trecvn == true) {
2020-02-14 15:21:43 +01:00
if(tbuf != '\n'){
tarry[j] = tbuf;
j++;
}
2020-02-15 22:03:22 +01:00
else {
2020-02-14 15:21:43 +01:00
tarry[j] = '\0';
trecvn = false;
j = 0;
trecvd = true;
}
}
2020-02-15 22:03:22 +01:00
else if (tbuf == '>'){
2020-02-14 15:21:43 +01:00
trecvn = true;
}
2020-02-14 14:19:51 +01:00
}
2020-02-14 15:21:43 +01:00
if(trecvd == true){
2020-02-15 22:03:22 +01:00
Serial.println(tarry);
char* token = strtok(tarry, "/");
2020-02-14 15:21:43 +01:00
while(token != NULL){
if(j == 0){
2020-02-15 22:03:22 +01:00
RTC.yyyy = atoi(token);
2020-02-14 15:21:43 +01:00
};
if(j == 1) {
2020-02-15 22:03:22 +01:00
RTC.mm = atoi(token);
2020-02-14 15:21:43 +01:00
};
if(j == 2) {
2020-02-15 22:03:22 +01:00
RTC.dd = atoi(token);
2020-02-14 15:21:43 +01:00
};
if(j == 3) {
2020-02-15 22:03:22 +01:00
RTC.h = atoi(token);
2020-02-14 15:21:43 +01:00
};
if(j == 4){
2020-02-15 22:03:22 +01:00
RTC.m = atoi(token);
2020-02-14 15:21:43 +01:00
};
if(j == 5){
2020-02-15 22:03:22 +01:00
RTC.s = atoi(token);
2020-02-14 15:21:43 +01:00
};
2020-02-15 22:03:22 +01:00
token = strtok(NULL, "/");
j++;
2020-02-14 15:21:43 +01:00
}
j = 0;
2020-04-10 14:01:56 +02:00
Serial.println(F("NTP sync complete"));
2020-02-14 15:21:43 +01:00
RTC.writeTime();
trecvd = false;
2020-02-15 22:03:22 +01:00
return(true);
2020-02-14 14:19:51 +01:00
}
}
void layoutScreen() {
2020-04-10 14:01:56 +02:00
display.setRotation(0); //portrait, connector at the top
2020-02-14 15:21:43 +01:00
display.setFullWindow();
2020-04-10 14:01:56 +02:00
display.setFont(&TomThumb);
display.setTextColor(GxEPD_BLACK);
2020-02-14 15:21:43 +01:00
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
2020-04-10 14:01:56 +02:00
display.setCursor(8, 69);
display.print(F("Temperature:"));
display.setCursor(8, (69 + 40));
display.print(F("Humidity:"));
display.setCursor(8, (69 + 80));
display.print(F("Pressure:"));
display.setCursor(8, (69 + 120));
display.print(F("CO2 concentration:"));
display.setCursor(8, 269);
display.print(F("Network info:"));
2020-02-14 15:21:43 +01:00
}
while (display.nextPage());
2020-02-14 14:19:51 +01:00
}
void printConnInfo() {
display.setFont(&TomThumb);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby; uint16_t tbw, tbh;
display.getTextBounds(ssid, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = 10;
uint16_t y = 277;
display.getTextBounds(ip, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x2 = 10;
uint16_t y2 = 284;
display.setPartialWindow(0, 270, display.width(), 20);
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x,y);
display.print("SSID: ");
display.print(ssid);
display.setCursor(x2,y2);
display.print("IP: ");
display.print(ip);
}
while (display.nextPage());
}
void printRTCTimeToScreen() {
2020-02-14 15:21:43 +01:00
char delim[] = ":";
byte hrs;
byte DST;
DST = checkDST(); //check whether DST is active and set the var accordingly
2020-02-14 15:21:43 +01:00
RTC.readTime();
hrs = RTC.h;
if(DST == 1){
hrs = hrs + 1;
}
2020-02-14 15:21:43 +01:00
display.setFont(&FreeSans18pt7b);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby; uint16_t tbw, tbh;
display.getTextBounds(delim, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((display.width() / 2) - tbw);
2020-04-10 14:01:56 +02:00
uint16_t y = ((32 - tbh) / 2) - (tby - 4);
2020-02-14 15:21:43 +01:00
display.getTextBounds("00", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x2 = (display.width() / 2) - 8 - tbw ;
2020-04-10 14:01:56 +02:00
uint16_t y2 = ((32 - tbh) / 2) - ( tby - 4);
2020-02-14 15:21:43 +01:00
display.getTextBounds("00", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x3 = (display.width() / 2) + 8;
2020-02-14 15:21:43 +01:00
display.setPartialWindow(0, 0, display.width(), (display.height() - (display.height() - 32)));
2020-02-14 15:21:43 +01:00
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(delim);
2020-04-10 14:01:56 +02:00
display.setCursor(x2, y2);
if(hrs < 10) {
2020-02-14 15:21:43 +01:00
display.print("0");
display.print(hrs);
}
2020-02-15 22:03:22 +01:00
else {
display.print(hrs);
2020-02-14 15:21:43 +01:00
}
2020-04-10 14:01:56 +02:00
display.setCursor(x3, y2);
2020-02-14 15:21:43 +01:00
if(RTC.m < 10) {
display.print("0");
display.print(RTC.m);
}
2020-02-15 22:03:22 +01:00
else {
2020-02-14 15:21:43 +01:00
display.print(RTC.m);
}
2020-02-14 14:19:51 +01:00
}
2020-02-14 15:21:43 +01:00
while(display.nextPage());
2020-02-14 14:19:51 +01:00
}
void printRTCDateToScreen() {
2020-02-14 15:21:43 +01:00
RTC.readTime();
display.setFont(&FreeSansBold9pt7b);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby; uint16_t tbw, tbh;
2020-02-15 22:03:22 +01:00
display.getTextBounds("00 - 00 - 0000", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = (display.width() / 2) - (tbw / 2) ;
2020-02-14 15:21:43 +01:00
uint16_t y = 48 + (tbh / 2);
display.setPartialWindow(0, 33, display.width(), 31);
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
2020-02-14 15:21:43 +01:00
display.setCursor(x, y);
if(RTC.dd < 10) {
display.print("0");
display.print(RTC.dd);
}
else {
display.print(RTC.dd);
}
2020-02-14 15:21:43 +01:00
display.print(" - ");
2020-02-15 22:03:22 +01:00
if(RTC.mm < 10){
display.print("0");
display.print(RTC.mm);
}
2020-02-15 22:03:22 +01:00
else {
display.print(RTC.mm);
}
2020-02-14 15:21:43 +01:00
display.print(" - ");
display.print(RTC.yyyy);
}
while(display.nextPage());
2020-02-14 14:19:51 +01:00
}
void printTempToScreen() {
2020-02-14 15:21:43 +01:00
struct data *dtsp = &dataset;
display.setFont(&FreeSansBold9pt7b);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby; uint16_t tbw, tbh;
2020-04-10 14:01:56 +02:00
display.getTextBounds("00.0 C", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((display.width() - tbw) / 2) - tbx;
uint16_t y = (92 - tbh) - tby;
display.getTextBounds("00 %", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x2 = ((display.width() - tbw) / 2) - tbx;
uint16_t y2 = (132 - tbh) - tby;
display.getTextBounds("1488 hpa", 0, 0, &tbx, &tby, &tbw, &tbh);
2020-02-14 15:21:43 +01:00
uint16_t x3 = ((display.width() - tbw) / 2) - tbx;
2020-04-10 14:01:56 +02:00
uint16_t y3 = ( 176 - tbh) - tby;
display.getTextBounds("1488 ppm", 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t y4 = ( 216 - tbh) - tby;
2020-04-10 14:01:56 +02:00
display.setPartialWindow(0, 70, display.width(), 33);
2020-02-14 15:21:43 +01:00
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(dtsp -> temp, 1);
2020-04-10 14:01:56 +02:00
display.print(F(" C"));
2020-02-14 15:21:43 +01:00
}
while (display.nextPage());
2020-04-10 14:01:56 +02:00
display.setPartialWindow(0, 110, display.width(), 33);
2020-02-14 15:21:43 +01:00
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
2020-04-10 14:01:56 +02:00
display.setCursor(x2, y2);
2020-02-14 15:21:43 +01:00
display.print(dtsp -> rhum);
2020-04-10 14:01:56 +02:00
display.print(F(" %"));
2020-02-14 15:21:43 +01:00
}
while(display.nextPage());
2020-04-10 14:01:56 +02:00
display.setPartialWindow(0, 150 ,display.width(), 33);
2020-02-14 15:21:43 +01:00
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x3, y3);
display.print(dtsp -> rpres);
display.print(F(" hPa"));
2020-04-10 14:01:56 +02:00
}
while(display.nextPage());
display.setPartialWindow(0, 190 ,display.width(), 33);
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x3, y4);
display.print(dtsp -> co2);
display.print(F(" ppm"));
2020-02-14 15:21:43 +01:00
}
while(display.nextPage());
2020-02-14 14:19:51 +01:00
}
float measureTemp() {
// BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
2020-02-14 15:21:43 +01:00
int temps[6];
2020-02-14 15:21:43 +01:00
//light led while measuring
digitalWrite(13, HIGH);
2020-04-10 14:01:56 +02:00
Serial.print(F("Measuring temperature..."));
2020-02-14 15:21:43 +01:00
for(char i = 0; i <= 5; i++){
temps[i] = bme.readTemperature() * 100;
delay(1000);
}
2020-02-14 15:21:43 +01:00
float temp;
2020-02-14 15:21:43 +01:00
temp = (temps[1] + temps[2] + temps[3] + temps[4] + temps[5]) / 5;
2020-04-10 14:01:56 +02:00
Serial.print(F("done: "));
2020-02-14 15:21:43 +01:00
Serial.println(temp / 100);
digitalWrite(13, LOW);
return temp / 100;
2020-02-14 14:19:51 +01:00
}
float measureHum() {
2020-02-14 15:21:43 +01:00
int hums[6];
2020-02-14 15:21:43 +01:00
//light led while measuring
digitalWrite(13, HIGH);
2020-04-10 14:01:56 +02:00
Serial.print(F("Measuring humidity..."));
2020-02-14 15:21:43 +01:00
for(char i = 0; i <= 5; i++){
hums[i] = bme.readHumidity() * 100;
delay(1000);
}
2020-02-14 15:21:43 +01:00
float hum;
2020-02-14 15:21:43 +01:00
hum = (hums[1] + hums[2] + hums[3] + hums[4] + hums[5]) / 5;
2020-04-10 14:01:56 +02:00
Serial.print(F("done: "));
2020-02-14 15:21:43 +01:00
Serial.println(hum / 100);
2020-02-14 15:21:43 +01:00
digitalWrite(13, LOW);
return hum / 100;
2020-02-14 14:19:51 +01:00
}
float measurePres() {
// BME280::PresUnit presUnit(BME280::PresUnit_hPa);
2020-02-14 15:21:43 +01:00
float presrs[6];
2020-02-14 15:21:43 +01:00
//light led while measuring
digitalWrite(13, HIGH);
2020-04-10 14:01:56 +02:00
Serial.print(F("Measuring pressure..."));
2020-02-14 15:21:43 +01:00
for(char i = 0; i <= 5; i++){
// presrs[i] = bme.pres();
presrs[i] = bme.readPressure() / 100.0F; //returns in Pa, divide by 100 to get value in hPa
2020-02-14 15:21:43 +01:00
delay(1000);
}
2020-02-14 15:21:43 +01:00
float pres;
2020-02-14 15:21:43 +01:00
pres = (presrs[1] + presrs[2] + presrs[3] + presrs[4] + presrs[5]) / 5;
2020-04-10 14:01:56 +02:00
Serial.print(F("done: "));
2020-02-14 15:21:43 +01:00
Serial.println(pres);
2020-02-14 15:21:43 +01:00
digitalWrite(13, LOW);
return pres;
2020-02-14 14:19:51 +01:00
}
2020-04-10 14:01:56 +02:00
int16_t measureCO2(){
digitalWrite(13, HIGH);
2020-04-10 14:01:56 +02:00
Serial.print(F("Measuring CO2..."));
2020-04-10 14:01:56 +02:00
int16_t co2conc = get_concentration();
2020-04-10 14:01:56 +02:00
Serial.print(F("done:"));
Serial.println(co2conc);
digitalWrite(13, LOW);
return(co2conc);
2020-04-10 14:01:56 +02:00
}
2020-02-15 22:03:22 +01:00
bool sendDataToServer(){
char payload[22];
2020-02-14 15:21:43 +01:00
char stemp[8];
char shum[8];
dtostrf(dataset.temp, 5, 2, stemp);
dtostrf(dataset.hum, 5, 2, shum); //convert floats to strings
sprintf(payload, "%s,%s,%d,%d", stemp, shum, dataset.rpres, dataset.co2); //convert everything to a string
2020-02-14 15:21:43 +01:00
Serial2.print(payload); //send over serial 2 to esp
Serial2.print('\n'); //terminate transmission
delay(1000); //give time to process comm
2020-04-10 14:01:56 +02:00
Serial.print(F("Data sent\r\n"));
2020-02-15 22:03:22 +01:00
return(true);
2020-02-14 14:19:51 +01:00
}
byte checkDST() {
byte DST;
RTC.readTime();
// ********************* Calculate offset for Sunday *********************
int y = RTC.yyyy - 2000; //take only last two digits of year (while not universal, this will work for the next 80 years so good enough for me)
int x = (y + y/4 + 2) % 7; // remainder will identify which day of month
// is Sunday by subtracting x from the one
// or two week window. First two weeks for March
// and first week for November
// *********** BEGINS on 2nd Sunday of March @ 2:00 AM *********
if(RTC.mm == 3 && RTC.dd == (14 - x) && RTC.h >= 2) {
DST = 1;
}
if((RTC.mm == 3 && RTC.dd > (14 - x)) || RTC.mm > 3) {
DST = 1;
}
// ************* ENDS on 1st Sunday of Nov @ 2:00 AM ************
if(RTC.mm == 11 && RTC.dd == (7 - x) && RTC.h >= 2) {
DST = 0;
}
if((RTC.mm == 11 && RTC.dd > (7 - x)) || RTC.mm > 11 || RTC.mm < 3) {
DST = 0;
}
return(DST);
}