Nano 33 iot RTC DS3231 and Low Power library, eventually with ArduinoOTA

Hello all,
I am having trouble finding the appropriate library or libraries to use for my project. I am trying to use a DS3231 module, Overview | Adafruit DS3231 Precision RTC Breakout | Adafruit Learning System , with the nano 33 (I know it has a built in RTC). I then want the DS3231 to wake up the nano from sleep using an interrupt. Eventually, I will add in the ArduinoOTA code, so that I can update the program running on the arduino, to change the times via WiFi.

This is all to control a set of Exterior LED lights via 5V relays. I am trying to keep power usage to an absolute minimum as last time I did this, with the DS3231, Rocketstream’s Low Power library and an UNO. It killed a 12V lawn tractor battery in 2 months. It has a 10W solar panel connected to the battery.

I do plan on using a cheap 12V to 5V USB DC plug so that the arduino nano is still powered via USB. I need the 5V for the relays. The relays are active LOW.

// Hardware:
// Arduino nano 33 iot, DS3231 myRTC.
// Connect myRTC SDA to Arduino pin SDA.
// Connect myRTC SCL to Arduino pin SCL.
// Connect myRTC INT/SQW to Arduino pin 2.
//
// Based on the example Alarm_ex8 by Jack Christensen 17Dec2018


#include <TimeLib.h>
#include <TimeAlarms.h>
#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232myRTC
#include <Streaming.h>        // http://arduiniana.org/libraries/streaming/
#include "ArduinoLowPower.h"
//#include <Time.h>

#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoOTA.h>

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;      // your network SSID (name)
char pass[] = SECRET_PASS;   // your network password

int status = WL_IDLE_STATUS;

// pin definitions
const uint8_t myRTC_INT_PIN(2);
const int LEDPin = LED_BUILTIN;
const int relayPin = 7;     // use this pin to drive the transistor
const int hourInt = 10;  
const int minInt = 56;
boolean awake;

unsigned long previousMillis = 0;        // will store last time LED was updated

const long timeON = 6000;

// current time from the RTC in text format
char timestamp[32];

DS3232RTC myRTC(false);

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void wakeUp()
{
  // Just a handler for the pin interrupt.
  awake = true;
}

void setAlarm () {
  tmElements_t tm2;
  tm2.Hour = hourInt;
  tm2.Minute = minInt;
  tm2.Second = 0;
  //  formatTime(timestamp, tm2);
  time_t alarmTime = makeTime(tm2);
  formatTime(timestamp, alarmTime);
  timestamp[8] = 0;                   // keep just hh:mm:ss
  myRTC.setAlarm(ALM1_MATCH_HOURS, minute(alarmTime), hour(alarmTime), 1);
  myRTC.alarm(ALARM_1);                 // ensure myRTC interrupt flag is cleared
  myRTC.alarmInterrupt(ALARM_1, true);
}

// format a time_t value, return the formatted string in buf (must be at least 25 bytes)
void formatTime(char *buf, time_t t)
{
  char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
  strcpy(m, monthShortStr(month(t)));
  sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d",
          hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t));
}

void printDigits(int digits)
{
    // utility function for digital clock display: prints preceding colon and leading 0
    Serial.print(':');
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

void setup()
{
  Serial.begin(115200);
  delay(1000);
  //    Serial << F( "\n" __FILE__ " " __DATE__ " " __TIME__ "\n" );
  pinMode(myRTC_INT_PIN, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  setSyncProvider(myRTC.get);   // the function to get the time from the RTC
  LowPower.attachInterruptWakeup(myRTC_INT_PIN, wakeUp, CHANGE);
  awake = true;
//
  // attempt to connect to Wifi network:
//  while ( status != WL_CONNECTED) {
//    Serial.print("Attempting to connect to SSID: ");
//    Serial.println(ssid);
//    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
//    status = WiFi.begin(ssid, pass);
//  }
//
//  // start the WiFi OTA library with internal (flash) based storage
//  ArduinoOTA.begin(WiFi.localIP(), "Arduino", "Eastwind3", InternalStorage);
//
//  // you're connected now, so print out the status:
//  printWifiStatus();
}

void loop()
{
    // print the current time
//    time_t t = myRTC.get();
//    formatTime(timestamp, t);
//      Serial << millis() << F(" Current RTC time ") << timestamp << endl;
//    
//    ArduinoOTA.poll();
    

    if (awake) {
//    Serial.println("I'm awake");
    digitalWrite(relayPin, LOW);

        delay(timeON); //3 hours in ms, 10800000
//    unsigned long currentMillis = millis();
//    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
//      previousMillis = currentMillis;
      digitalWrite(relayPin, HIGH);
      myRTC.alarm(ALARM_1);
      awake = false;
      setAlarm();
    }
      
  // check to see if the INT/SQW pin is low, i.e. an alarm has occurred
  // Allow wake up pin to trigger interrupt on low.
  digitalWrite(LEDPin, LOW);
  // Enter power down state with ADC and BOD module disabled.
  // Wake up when wake up pin is low.
//  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    LowPower.sleep();
  }

As it stands, I can get a good Low power library to work: GitHub - arduino-libraries/ArduinoLowPower: Powersave features for SAMD boards
The trouble starts to arise when I try to wake it up using the SQW pin on the DS3231, I can’t seem to find a library that support the SAMD architecture.

Any help would be appreciated.

on battery powered devices it is better to download the update from a server, the to upload it from IDE.

Great idea, but the nano won’t be in WiFi range, I plan on creating a network using my laptop (Intel MyWiFi Technology). The nano will be sealed in a watertight box with the battery, etc. I want to be able to update the time the lights turn on and how long they stay on, wirelessly.

That is not the root of my problem though. Currently, I can’t get the DS3231 library to work well with the Lower Power library.

// Hardware:
// Arduino nano 33 iot, DS3231 myRTC.
// Connect myRTC SDA to Arduino pin SDA.
// Connect myRTC SCL to Arduino pin SCL.
// Connect myRTC INT/SQW to Arduino pin 2.
//
// Based on the example Alarm_ex8 by Jack Christensen 17Dec2018


#include <TimeLib.h>
#include <TimeAlarms.h>
#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232myRTC
#include <Streaming.h>        // http://arduiniana.org/libraries/streaming/
#include <ArduinoLowPower.h>
//#include <Time.h>

#include <SPI.h>

// pin definitions
const uint8_t myRTC_INT_PIN(2);
const int LEDPin = LED_BUILTIN;
const int relayPin = 7;     // use this pin to drive the transistor
const int hourInt = 10;  
const int minInt = 56;
boolean awake;

unsigned long previousMillis = 0;        // will store last time LED was updated

// const long interval = 120000;           // interval at which to blink (milliseconds)
const long timeON = 6000;
//21600000;

// current time from the RTC in text format
char timestamp[32];

DS3232RTC myRTC(false);

void wakeUp()
{
  // Just a handler for the pin interrupt.
  awake = true;
}

void setAlarm () {
  tmElements_t tm2;
  tm2.Hour = hourInt;
  tm2.Minute = minInt;
  tm2.Second = 0;
  //  formatTime(timestamp, tm2);
  time_t alarmTime = makeTime(tm2);
  formatTime(timestamp, alarmTime);
  timestamp[8] = 0;                   // keep just hh:mm:ss
  myRTC.setAlarm(ALM1_MATCH_HOURS, minute(alarmTime), hour(alarmTime), 1);
  myRTC.alarm(ALARM_1);                 // ensure myRTC interrupt flag is cleared
  myRTC.alarmInterrupt(ALARM_1, true);
}

// format a time_t value, return the formatted string in buf (must be at least 25 bytes)
void formatTime(char *buf, time_t t)
{
  char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
  strcpy(m, monthShortStr(month(t)));
  sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d",
          hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t));
}

void printDigits(int digits)
{
    // utility function for digital clock display: prints preceding colon and leading 0
    Serial.print(':');
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

void setup()
{
  Serial.begin(115200);
  delay(1000);
  //    Serial << F( "\n" __FILE__ " " __DATE__ " " __TIME__ "\n" );
  pinMode(myRTC_INT_PIN, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  setSyncProvider(myRTC.get);   // the function to get the time from the RTC
  LowPower.attachInterruptWakeup(myRTC_INT_PIN, wakeUp, CHANGE);
  awake = true;
////
////  setAlarm();
//
  // attempt to connect to Wifi network:
//  while ( status != WL_CONNECTED) {
//    Serial.print("Attempting to connect to SSID: ");
//    Serial.println(ssid);
//    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
//    status = WiFi.begin(ssid, pass);
//  }
//
//  // start the WiFi OTA library with internal (flash) based storage
//  ArduinoOTA.begin(WiFi.localIP(), "Arduino", "Eastwind3", InternalStorage);
//
//  // you're connected now, so print out the status:
//  printWifiStatus();
}

void loop()
{
    // print the current time
//    time_t t = myRTC.get();
//    formatTime(timestamp, t);
//      Serial << millis() << F(" Current RTC time ") << timestamp << endl;

    if (awake) {
//    Serial.println("I'm awake");
    digitalWrite(relayPin, LOW);

        delay(timeON); //3 hours in ms, 10800000
//    unsigned long currentMillis = millis();
//    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
//      previousMillis = currentMillis;
      digitalWrite(relayPin, HIGH);
      myRTC.alarm(ALARM_1);
      awake = false;
      setAlarm();
    }
      
  // check to see if the INT/SQW pin is low, i.e. an alarm has occurred
  // Allow wake up pin to trigger interrupt on low.
  digitalWrite(LEDPin, LOW);
  // Enter power down state with ADC and BOD module disabled.
  // Wake up when wake up pin is low.
//  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
//  awake = true;
  // Disable external pin interrupt on wake up pin.
//  detachInterrupt(0);
    LowPower.sleep();
  }

Errors are attached as txt.

Arduino error messages.txt (44.1 KB)

The OP has reported this as follows

I don't know if this should be in the Programming section (where I posted it) or the Nano 33 section?

It is probably better left here because this forum section gets more visitors than those for the newer Arduino boards which are not so commonly used but it can be moved later if that helps.

Report to Moderator if you want it moved

Why do you need to update the firmware just to change the times? Normally something like that would be in EEPROM or SD, not hard coded.

try to include the ArduinoLowPower library as first

Juraj:
try to include the ArduinoLowPower library as first

aarg:
Why do you need to update the firmware just to change the times? Normally something like that would be in EEPROM or SD, not hard coded.

I guess I can put them in them in the code to adjust the times based on the Month and day. The problem is not with the OTA part though.

Juraj:
try to include the ArduinoLowPower library as first

Do you mean change the order of the include statements?

ian5142:
Do you mean change the order of the include statements?

yes. it changes how the builder evaluates required libraries and hopefully it will not use TimeLib instead of time.h in RTCZero library as the error messages indicate now. (it looks like the ArduinoLowPower user RTCZero)

OK, I uncommented the Time.h include and put it at the top, Arduino Low Power is right under it. No change, same error messages as far as I can see.

ian5142:
OK, I uncommented the Time.h include and put it at the top, Arduino Low Power is right under it. No change, same error messages as far as I can see.

you made it worse by preferring Time.h which is the problem.
the only change should be to have LowPower as first library

OK, I commented out the Time.h and TimeLib.h. The Arduino Low Power Library is at the top. I still get the same errors.

Juraj:
you made it worse by preferring Time.h which is the problem.
the only change should be to have LowPower as first library

Arduino error messages.txt (43.4 KB)

so it still uses the Time.h from TimeLib instead of time.h from avr-lib.
maybe @pert can help