Weather station for mom in law complete, is code "sane"/correct

Hi all

So i finally got the weather station done, and after much testing an advice on this thread: Random falling interrupts being detected - Project Guidance - Arduino Forum i figured the last of problems where insane amounts of RF noise made it count rain at random even indoors :slight_smile:

I have eyeballed the code over and over again to check if errors should have sneaked in, i cant find any but just had what might look like a glitch where rain got reset, it should only happen the first day every month just past midnight

if anyone have time i could use as many extra set of eyes i can get, i will keep the hardware for at least a few weeks more to do some more testing to see if things behaves

first is the code for the outdoor unit which is made up of an arduino nano, ultimate gps from adafruit, bme280 module also from adafruit plus a nrf24 radio module to transmit data inside

in wide term words here is what it should do:

first is reads output from bme280
then it calculates how many mm of rain has fallen based on how many times the rain bucket has tipped
then it takes the UTC time from the gps module and converts it in to local europe time, i use the timezone lib to automatic switch from summer to winter time and vise versa
data is then transmitted wireless
next it checks to see if the day is 1 (first day of month) if hour and minute is 0 (just past midnight) and if a var called Res is 0, if all those are true the number of tips of the bucket is reset to 0 and Res variable is set to 1 to prevent multiple resets
a minute later Res variable is set back to 0, since minute is now 1 the above conditions should not be true before next month

but again a few other set of eyes would not hurt

since this post is over 9000 char's i have to use pastebin for the code, the best i could think of

code from link, and autoformatted

***************************************************************************
This is a library for the BME280 humidity, temperature & pressure sensor

Designed specifically to work with the Adafruit BME280 Breakout
---- > http : //www.adafruit.com/products/2650

These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface. The device's I2C address is either 0x76 or 0x77.

Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!

Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Time.h>                  
#include <Timezone.h> 

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 9

Adafruit_BME280 bme(BME_CS); // hardware SPI

#include <RF24.h>

#define CE_PIN   8
#define CSN_PIN 10
const byte slaveAddress[5] = {'R','x','A','A','A'};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

struct package
{
int temperature ;
int pressure;
int humidity ;
float rain;
int rf_hh;
int rf_mm;
int rf_dd;
int rf_mo;
int rf_yy;
};
typedef struct package Package;
Package data;


unsigned long delayTime;

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(5, 4);

Adafruit_GPS GPS(&mySerial);

#define GPSECHO  false

boolean usingInterrupt = false;

TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};       // Central European Standard Time
Timezone CE(CEST, CET);

const byte interruptPin = 3;
volatile byte buckettips = 0;
long debouncing_time = 500; //Debouncing Time in Milliseconds
volatile unsigned long last_micros;
int Res = 0;

void setup() {

Serial.begin(115200);
Serial.println(F("BME280 test"));

bool status;


status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}

Serial.println();
pinMode(3, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), bucketTipped, FALLING);

GPS.begin(9600);


GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
GPS.sendCommand(PGCMD_ANTENNA);

useInterrupt(true);

mySerial.println(PMTK_Q_RELEASE);

radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.openWritingPipe(slaveAddress);

delayTime = 1000;

delay(1000);


}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
// if you want to debug, this is a good time to do it!
#ifdef UDR0
if (GPSECHO)
if (c) UDR0 = c;
// writing direct to UDR0 is much much faster than Serial.print
// but only one character can be written at a time.
#endif
}

void useInterrupt(boolean v) {
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
  // do not call the interrupt function COMPA anymore
  TIMSK0 &= ~_BV(OCIE0A);
  usingInterrupt = false;
}
}

uint32_t timer = millis();

void loop() {

  printValues();
  radio.write(&data, sizeof(data));
  // Always use sizeof() as it gives the size as the number of bytes.
  // For example if dataToSend was an int sizeof() would correctly return 2
  resetrain();
  delay(delayTime);
  Serial.write(27);       // ESC command
  Serial.print("[2J");    // clear screen command
  Serial.write(27);
  Serial.print("[H");     // cursor to home command

}


void printValues() {
  uint8_t hh, mm, ss, dd, mo, yy;
  Serial.println("---Start---");
  Serial.print("Temperature = ");
  int temp_int = bme.readTemperature();
  Serial.print(temp_int);
  Serial.println(" *C");
  data.temperature = temp_int;
  Serial.print("Pressure = ");
  int pres_int = (bme.readPressure() / 100.0F);
  Serial.print(pres_int);
  Serial.println(" hPa");
  data.pressure = pres_int;
  Serial.print("Humidity = ");
  int hum_int = bme.readHumidity();
  Serial.print(hum_int);
  Serial.println(" %");
  Serial.println();
  data.humidity = hum_int;
  Serial.print("Bucket tipped ");
  Serial.print(buckettips);
  Serial.println(" times");
  data.rain = buckettips * 0.33;
  Serial.print(data.rain);
  Serial.println(" mm of rain");

  // in case you are not using the interrupt above, you'll
  // need to 'hand query' the GPS, not suggested :(
  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) Serial.print(c);
  }

  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false

    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }



  Serial.print("\nTime: ");
  hh = GPS.hour;
  Serial.print(hh, DEC); Serial.print(':');
  mm = GPS.minute;
  Serial.print(mm, DEC); Serial.print(':');
  ss = GPS.seconds;
  Serial.println(ss, DEC);
  Serial.print("Date: ");
  dd = GPS.day;
  Serial.print(dd, DEC); Serial.print('/');
  mo = GPS.month;
  Serial.print(mo, DEC); Serial.print("-20");
  yy = GPS.year;
  Serial.println(yy, DEC);
  Serial.println();

  setTime(hh, mm, ss, dd, mo, yy);

  time_t utc = now();
  //    local = myTZ.toLocal(utc, &tcr);
  printDateTime(CE, utc);

}

// given a Timezone object, UTC and a string description, convert and print local time with time zone
void printDateTime(Timezone tz, time_t utc)
{
  uint8_t rf_hh, rf_mm, rf_dd, rf_mo, rf_yy;
  char buf[40];
  char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
  TimeChangeRule *tcr;        // pointer to the time change rule, use to get the TZ abbrev

  time_t t = tz.toLocal(utc, &tcr);
  strcpy(m, monthShortStr(month(t)));
  sprintf(buf, "%.2d:%.2d:%.2d %d/%d-%d",
          hour(t), minute(t), second(t), day(t), month(t), year(t));
  Serial.println(buf);
  data.rf_hh = hour(t);
  data.rf_mm = minute(t);
  data.rf_dd = day(t);
  data.rf_mo = month(t);
  data.rf_yy = year(t);
  Serial.print("---End---");


}

void resetrain() {

  if (data.rf_dd == 1)
  {
    if (data.rf_hh == 0)
    {
      if (data.rf_mm == 0)
      {
        if (Res == 0)
        {
          buckettips = 0;
          Res = 1;
        }
      }
    }
  }

  if (data.rf_dd == 1)
  {
    if (data.rf_hh == 0)
    {
      if (data.rf_mm == 1)
      {
        Res = 0;
      }
    }
  }

}

void bucketTipped() {
  if ((long)(micros() - last_micros) >= debouncing_time * 1000) {
    buckettips++;
    last_micros = micros();
  }
}