689 lines
19 KiB
C++
689 lines
19 KiB
C++
#include <Wire.h>
|
|
// display mapping for Arduino MEGA
|
|
// BUSY -> 7, RST -> 9, DC -> 8, CS-> 53, CLK -> 52, DIN -> 51
|
|
#include <GxEPD2_BW.h>
|
|
#include <Fonts/FreeSansBold9pt7b.h>
|
|
#include "FreeSansBold11pt7b.h"
|
|
#include "FreeSans22pt7b.h"
|
|
#include <Fonts/TomThumb.h>
|
|
#include <MD_DS3231.h>
|
|
#include <BME280I2C.h>
|
|
#include <bc_co2_module_arduino.h>
|
|
|
|
/**************************** BME280 setup **********************************/
|
|
BME280I2C::Settings settings(
|
|
BME280::OSR_X1,
|
|
BME280::OSR_X1,
|
|
BME280::OSR_X1,
|
|
BME280::Mode_Forced,
|
|
BME280::StandbyTime_1000ms,
|
|
BME280::Filter_4,
|
|
BME280::SpiEnable_False,
|
|
0x76 // I2C address. I2C specific.
|
|
);
|
|
|
|
BME280I2C bme(settings);
|
|
|
|
/**************************** Serial setup **********************************/
|
|
#define BAUDRATE 115200
|
|
|
|
/**************************** Screen setup **********************************/
|
|
|
|
#define MAX_DISPAY_BUFFER_SIZE 32
|
|
#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 *******************************/
|
|
|
|
struct data {
|
|
float temp;
|
|
float hum;
|
|
int rhum;
|
|
float pres;
|
|
unsigned int rpres;
|
|
int16_t co2;
|
|
};
|
|
|
|
volatile static struct data dataset;
|
|
static struct lp8_t sensor;
|
|
char incoming[40];
|
|
char ssid[16];
|
|
char ip[16];
|
|
static byte bmeerr = 0;
|
|
|
|
/******************************* Setup routine ******************************/
|
|
void setup() {
|
|
|
|
ADCSRA = 0; //turn off adc to save power as it is not needed
|
|
|
|
pinMode(13, OUTPUT);
|
|
digitalWrite(13, LOW); //turn off led
|
|
|
|
Serial.begin(BAUDRATE);
|
|
Serial2.begin(BAUDRATE);
|
|
Wire.begin();
|
|
|
|
Serial.print(F("\r\n***Enviro data monitor***\r\n"));
|
|
//start co2 module
|
|
init_co2_module();
|
|
|
|
display.init(); //init display
|
|
delay(100);
|
|
layoutScreen(); //print static parts of screen
|
|
|
|
//make sure we're always in 24hr mode, invert to change to 12h
|
|
switch (RTC.status(DS3231_12H)) {
|
|
case DS3231_OFF:
|
|
Serial.println(F("RTC in 24h mode"));
|
|
break;
|
|
case DS3231_ON:
|
|
Serial.println(F("RTC in 12h mode, fixing")); //should not occur
|
|
RTC.control(DS3231_12H, DS3231_OFF);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Serial.println(F("Waiting for ESP to boot"));
|
|
bool n;
|
|
static byte tries = 0;
|
|
Serial.print("[");
|
|
while(1) {
|
|
delay(1000);
|
|
Serial.print("=");
|
|
n = readNetInfo();
|
|
if(n == true) {
|
|
break;
|
|
}
|
|
else {
|
|
tries++;
|
|
if(tries >= 33) {
|
|
Serial.print("X");
|
|
Serial.println();
|
|
Serial.println(F("Could not read connection info, likely no network connection"));
|
|
display.setFont(&TomThumb);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
uint16_t x = 10;
|
|
uint16_t y = 277;
|
|
|
|
display.setPartialWindow(0, 270, display.width(), 20);
|
|
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x,y);
|
|
display.print("Network error");
|
|
}
|
|
while (display.nextPage());
|
|
tries = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static byte retries = 0;
|
|
bool t;
|
|
while(1){ //sync time with network
|
|
delay(5000);
|
|
t = syncTime();
|
|
if(t == true) {
|
|
break;
|
|
}
|
|
else {
|
|
retries++;
|
|
if(retries > 4){ //break after 5 tries
|
|
Serial.println(F("Could not sync time\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
retries = 0;
|
|
printRTCTimeToScreen(); //print time to screen
|
|
printRTCDateToScreen(); //print date to screen
|
|
|
|
bool tsens;
|
|
while(1) {
|
|
tsens = bme.begin();
|
|
if(tsens == true) {
|
|
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."));
|
|
}
|
|
break;
|
|
}
|
|
else {
|
|
delay(2000);
|
|
retries++;
|
|
if(retries > 4) {
|
|
Serial.println(F("Could not find BME280 sensor."));
|
|
//display error message on screen
|
|
display.setFont(&FreeSansBold11pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
int16_t tbx, tby; uint16_t tbw, tbh;
|
|
display.getTextBounds("SENS ERR!", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t y = (92 - tbh) - tby + 20;
|
|
|
|
display.setPartialWindow(0, 70 + 20, display.width(), 33);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(6, y);
|
|
display.print(F("SENS ERR!"));
|
|
}
|
|
while (display.nextPage());
|
|
bmeerr = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Serial.println(F("Setup complete"));
|
|
};
|
|
|
|
/********************************* MAINLOOP ***************************************/
|
|
void loop() {
|
|
static byte oldmins;
|
|
|
|
RTC.readTime();
|
|
if(RTC.m != oldmins){ //run this every minute
|
|
printRTCTimeToScreen(); //update time on screen
|
|
if(bmeerr == 0){ //only attempt to measure anything if the sensor is present
|
|
doStuff(); //acquire data
|
|
sendDataToServer(); //send over to esp for publishing
|
|
printDataToScreen(); //update values on screen
|
|
}
|
|
oldmins = RTC.m; //save old value
|
|
}
|
|
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(); //refresh date on midnight
|
|
}
|
|
else if(RTC.m == 0 && RTC.h == 2 && RTC.s == 33) { //resync time at 2am
|
|
static byte retries = 0;
|
|
bool t;
|
|
while(1){
|
|
delay(2000);
|
|
t = syncTime();
|
|
if(t == true) {
|
|
break;
|
|
}
|
|
else {
|
|
retries++;
|
|
if(retries > 4){ //break after 5 tries
|
|
Serial.println(F("Could not sync time\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delay(500);
|
|
};
|
|
/************************************************************************************/
|
|
|
|
void doStuff() {
|
|
dataset.temp = measureTemp();
|
|
dataset.hum = measureHum();
|
|
dataset.rhum = round(dataset.hum);
|
|
dataset.pres = measurePres();
|
|
dataset.rpres = round(dataset.pres);
|
|
dataset.co2 = measureCO2();
|
|
};
|
|
|
|
bool readNetInfo() {
|
|
char buf;
|
|
bool commRecvd = false;
|
|
static byte i=0;
|
|
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;
|
|
Serial.print("]");
|
|
Serial.println();
|
|
Serial.print(F("Got conn info:\n"));
|
|
Serial.println(ssid);
|
|
Serial.println(ip);
|
|
printConnInfo();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool syncTime() {
|
|
char tbuf;
|
|
static bool trecvd = false;
|
|
static bool trecvn = false;
|
|
char tarry[21];
|
|
static byte j = 0;
|
|
byte dst;
|
|
|
|
dst = checkDST();
|
|
|
|
Serial.print(F("Syncing time...\n"));
|
|
delay(10);
|
|
Serial2.print("?ntp");
|
|
Serial2.print("\n");
|
|
delay(300);
|
|
while(Serial2.available() > 0 && trecvd == false){
|
|
tbuf = Serial2.read();
|
|
if(trecvn == true) {
|
|
if(tbuf != '\n'){
|
|
tarry[j] = tbuf;
|
|
j++;
|
|
}
|
|
else {
|
|
tarry[j] = '\0';
|
|
trecvn = false;
|
|
j = 0;
|
|
trecvd = true;
|
|
}
|
|
}
|
|
else if (tbuf == '>'){
|
|
trecvn = true;
|
|
}
|
|
}
|
|
j = 0;
|
|
if(trecvd == true){
|
|
Serial.println(tarry);
|
|
char* token = strtok(tarry, "/");
|
|
while(token != NULL){
|
|
if(j == 0){
|
|
RTC.yyyy = atoi(token);
|
|
};
|
|
if(j == 1) {
|
|
RTC.mm = atoi(token);
|
|
};
|
|
if(j == 2) {
|
|
RTC.dd = atoi(token);
|
|
};
|
|
if(j == 3) {
|
|
if(dst == 1) {
|
|
if(atoi(token) == 23) {
|
|
RTC.h = 0;
|
|
}
|
|
else {
|
|
RTC.h = atoi(token) + 1;
|
|
}
|
|
}
|
|
if(dst == 0) {
|
|
RTC.h = atoi(token);
|
|
}
|
|
};
|
|
if(j == 4){
|
|
RTC.m = atoi(token);
|
|
};
|
|
if(j == 5){
|
|
RTC.s = atoi(token);
|
|
};
|
|
token = strtok(NULL, "/");
|
|
j++;
|
|
}
|
|
j = 0;
|
|
RTC.writeTime();
|
|
Serial.println(F("NTP sync complete"));
|
|
trecvd = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void layoutScreen() {
|
|
display.setRotation(0); //portrait, connector at the top
|
|
display.setFullWindow();
|
|
|
|
display.setFont(&TomThumb);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(8, 69+20);
|
|
display.print(F("Temperature:"));
|
|
display.setCursor(8, (69 + 40 + 20));
|
|
display.print(F("Humidity:"));
|
|
display.setCursor(8, (69 + 80) + 20);
|
|
display.print(F("Pressure:"));
|
|
display.setCursor(8, (69 + 120) + 20);
|
|
display.print(F("CO2 concentration:"));
|
|
display.setCursor(8, 269);
|
|
display.print(F("Network info:"));
|
|
}
|
|
while (display.nextPage());
|
|
}
|
|
|
|
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() {
|
|
char delim[] = ":";
|
|
RTC.readTime();
|
|
display.setFont(&FreeSans22pt7b);
|
|
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);
|
|
uint16_t y = ((32 - tbh) / 2) - (tby - 4) + 10;
|
|
display.getTextBounds("00", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x2 = (display.width() / 2) - 8 - tbw ;
|
|
uint16_t y2 = ((32 - tbh) / 2) - ( tby - 4) + 10;
|
|
display.getTextBounds("00", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x3 = (display.width() / 2) + 8;
|
|
display.setPartialWindow(0, 0, display.width(), (display.height() - (display.height() - 32)) + 20);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x, y);
|
|
display.print(delim);
|
|
display.setCursor(x2, y2);
|
|
if(RTC.h < 10) {
|
|
display.print("0");
|
|
display.print(RTC.h);
|
|
}
|
|
else {
|
|
display.print(RTC.h);
|
|
}
|
|
display.setCursor(x3, y2);
|
|
if(RTC.m < 10) {
|
|
display.print("0");
|
|
display.print(RTC.m);
|
|
}
|
|
else {
|
|
display.print(RTC.m);
|
|
}
|
|
}
|
|
while(display.nextPage());
|
|
}
|
|
|
|
void printRTCDateToScreen() {
|
|
RTC.readTime();
|
|
|
|
display.setFont(&FreeSansBold9pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
int16_t tbx, tby; uint16_t tbw, tbh;
|
|
display.getTextBounds("00 - 00 - 0000", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x = (display.width() / 2) - (tbw / 2) ;
|
|
uint16_t y = 48 + (tbh / 2) + 20;
|
|
|
|
display.setPartialWindow(0, 33 + 20, display.width(), 31);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x, y);
|
|
if(RTC.dd < 10) {
|
|
display.print("0");
|
|
display.print(RTC.dd);
|
|
}
|
|
else {
|
|
display.print(RTC.dd);
|
|
}
|
|
display.print(" - ");
|
|
if(RTC.mm < 10){
|
|
display.print("0");
|
|
display.print(RTC.mm);
|
|
}
|
|
else {
|
|
display.print(RTC.mm);
|
|
}
|
|
display.print(" - ");
|
|
display.print(RTC.yyyy);
|
|
}
|
|
while(display.nextPage());
|
|
}
|
|
|
|
void printDataToScreen() {
|
|
struct data *dtsp = &dataset;
|
|
display.setFont(&FreeSansBold11pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
int16_t tbx, tby; uint16_t tbw, tbh;
|
|
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 +20;
|
|
display.getTextBounds("00 %", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x2 = ((display.width() - tbw) / 2) - tbx;
|
|
uint16_t y2 = (132 - tbh) - tby + 20;
|
|
display.getTextBounds("1488 hpa", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x3 = ((display.width() - tbw) / 2) - tbx;
|
|
uint16_t y3 = ( 176 - tbh) - tby + 20;
|
|
display.getTextBounds("1488 ppm", 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t y4 = ( 216 - tbh) - tby + 20;
|
|
|
|
display.setPartialWindow(0, 70 + 20, display.width(), 33);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x, y);
|
|
display.print(dtsp -> temp, 1);
|
|
display.drawCircle(x+48,80 + 20,3,GxEPD_BLACK);
|
|
display.drawCircle(x+48,80 + 20,2,GxEPD_BLACK); //quick and dirty way to get a "degrees symbol"
|
|
display.print(F(" C"));
|
|
}
|
|
while (display.nextPage());
|
|
|
|
display.setPartialWindow(0, 110 + 20, display.width(), 33);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x2, y2);
|
|
display.print(dtsp -> rhum);
|
|
display.print(F(" %"));
|
|
}
|
|
while(display.nextPage());
|
|
|
|
display.setPartialWindow(0, 150 + 20,display.width(), 33);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x3, y3);
|
|
display.print(dtsp -> rpres);
|
|
display.print(F(" hPa"));
|
|
}
|
|
while(display.nextPage());
|
|
|
|
display.setPartialWindow(0, 190 +20 ,display.width(), 33);
|
|
display.firstPage();
|
|
do {
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x3, y4);
|
|
display.print(dtsp -> co2);
|
|
display.print(F(" ppm"));
|
|
}
|
|
while(display.nextPage());
|
|
}
|
|
|
|
float measureTemp() {
|
|
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
|
int temps[5];
|
|
|
|
//light led while measuring
|
|
digitalWrite(13, HIGH);
|
|
|
|
Serial.print(F("Measuring temperature"));
|
|
|
|
for(char i = 0; i < 5; i++){
|
|
temps[i] = bme.temp() * 100;
|
|
Serial.print(F("."));
|
|
delay(1000);
|
|
}
|
|
|
|
float temp;
|
|
|
|
temp = (temps[0] + temps[1] + temps[2] + temps[3] + temps[4]) / 5;
|
|
|
|
Serial.print(F("done: "));
|
|
Serial.println(temp / 100);
|
|
digitalWrite(13, LOW);
|
|
|
|
return temp/100;
|
|
}
|
|
|
|
float measureHum() {
|
|
int hums[5];
|
|
|
|
//light led while measuring
|
|
digitalWrite(13, HIGH);
|
|
|
|
Serial.print(F("Measuring humidity"));
|
|
|
|
for(char i = 0; i < 5; i++){
|
|
hums[i] = bme.hum() * 100;
|
|
Serial.print(F("."));
|
|
delay(1000);
|
|
}
|
|
|
|
float hum;
|
|
|
|
hum = (hums[0] + hums[1] + hums[2] + hums[3] + hums[4]) / 5;
|
|
|
|
Serial.print(F("done: "));
|
|
Serial.println(hum / 100);
|
|
|
|
digitalWrite(13, LOW);
|
|
return hum / 100;
|
|
}
|
|
|
|
float measurePres() {
|
|
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
|
float presrs[5];
|
|
|
|
//light led while measuring
|
|
digitalWrite(13, HIGH);
|
|
|
|
Serial.print(F("Measuring pressure"));
|
|
|
|
for(char i = 0; i < 5; i++){
|
|
presrs[i] = bme.pres(BME280::PresUnit_hPa);
|
|
Serial.print(F("."));
|
|
delay(1000);
|
|
}
|
|
|
|
float pres;
|
|
|
|
pres = (presrs[0] + presrs[1] + presrs[2] + presrs[3] + presrs[4]) / 5;
|
|
|
|
Serial.print(F("done: "));
|
|
Serial.println(pres);
|
|
|
|
digitalWrite(13, LOW);
|
|
return pres;
|
|
}
|
|
|
|
int16_t measureCO2(){
|
|
digitalWrite(13, HIGH);
|
|
Serial.print(F("Measuring CO2....."));
|
|
|
|
int16_t co2conc = get_co2_concentration(uint16_t(dataset.pres * 10));
|
|
|
|
Serial.print(F("done:"));
|
|
Serial.println(co2conc);
|
|
|
|
digitalWrite(13, LOW);
|
|
return(co2conc);
|
|
}
|
|
|
|
bool sendDataToServer(){
|
|
char payload[32];
|
|
char stemp[8];
|
|
char shum[8];
|
|
char check[] = "=";
|
|
dtostrf(dataset.temp, 5, 2, stemp);
|
|
dtostrf(dataset.hum, 5, 2, shum); //convert floats to strings
|
|
sprintf(payload, "%s,%s,%s,%d,%d", check, stemp, shum, dataset.rpres, dataset.co2); //convert everything to a string
|
|
Serial2.print(payload); //send over serial 2 to esp
|
|
Serial2.print('\n'); //terminate transmission
|
|
delay(1000); //give time to process comm
|
|
Serial.print(F("Data sent\r\n"));
|
|
return(true);
|
|
}
|
|
|
|
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);
|
|
}
|