Can I set Time library sync provider?

Is it possible to make the built-in Time library get the current time from a local source like a DS1307 or DS3231 chip? The Arduino Time library has a couple functions that allow this:

setSyncProvider(getTimeFunction);// Set the external time
                                  //  provider
setSyncInterval(interval);    // Set the number of
                               //  seconds between re-sync

I have my Photon mounted to a board that already has a DS3231 w/battery backup and I’d like to use that RTC when I’m not connected to the Internet since it’s more accurate than the one built into the Photon.

Your Photon has a built in RTC, you only need to apply modest power to VBAT. Search the forum. @kennethlimcp rolled out a demo a while back, as I recall.

Thanks. I understand that it has a built-in RTC that can be powered by VBAT. As I said, I am mating the Photon to a board that already has a DS3231, and I’d like to use that since it is almost certainly superior to that RTC.

Time.setTime()

https://docs.particle.io/reference/firmware/photon/#settime-

But reconnecting to the cloud will overwrite… As I recall.

Ah, of course! I was approaching it wrong, thinking I needed to give it a new sync target that Particle.syncTime() would work with. I just need to manually sync with the DS3231 as often as needed instead. Thanks!

1 Like

@jerware would you mind posting your code for setting up the D3231 and syncing the time? I’m trying to accomplish something similar and could use the help :slight_smile:

You just need to hand your RTC’s time to Time.setTime()
frequently if you are also connected to the cloud. I don’t believe there is a Time class function to turn off time syncing…

pseudo:

time_t myTimestamp = goGetMyD3231rtcTimestamp();
Time.setTime(myTimestamp);

So if you have to work so hard to keep overwriting the time, why not just use the device’s internal RTC and leverage that?

My code is all intertwined with unreleased source, but as I recall it the DS1307 library example files worked out of the box. Maybe you could post your code and errors?

I’ll post twice to separate all of this. The broken code I’ll post after this one.

I found another library that I was able to make work. It came from the guy reselling the DS3231 board. Source: https://github.com/switchdoclabs/RTC_SDL_DS3231_ARDUINO/tree/master/DS3231/Examples/DS3231_TEST

His time format spits out like this:
2017-3-20 22:27:1
Temperature=20

My goal with this is to log temperature and humidity in a concrete curing chamber. I don’t want to have to rely on having to blanket the entire shop with wifi to have accurate time stamps so I thought I would use the DS3231 since it loses approx 1 min a year and it’s cheap.

With the code, I’ve been able to set the RTC clock, but how (and where) do I implement your suggestion @BulldogLowell? Also, will I need to reformat the date to match up with the format the Photon expects?

This portion of the project is a bit out of my range so any specific guidance (and comments on code) are helpful :slight_smile:

The code is:

/*
DS3231_test.pde
Eric Ayars
4/11

Test/demo of read routines for a DS3231 RTC.

Turn on the serial monitor after loading this to check if things are
working as they should.

#include "ds3231.h"
#include "application.h"

DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

byte year, month, date, DoW, hour, minute, second;

void setup() {
	// Start the I2C interface
	Wire.begin();
	    //sets the time ONLY NEED TO DO ONCE
	    //set 20 seconds ahead of when you plan to click flash
        //Clock is 2-3s fast
        /*
        Clock.setSecond(0);//Set the second 
        Clock.setMinute(42);//Set the minute 
        Clock.setHour(11);  //Set the hour 
        Clock.setDoW(1);    //Set the day of the week
        Clock.setDate(20);  //Set the date of the month
        Clock.setMonth(3);  //Set the month of the year
        Clock.setYear(17);  //Set the year (Last two digits of the year)
	    */
	// Start the serial interface
	Serial.begin(115200);
	//Serial.begin(9600);
}
void ReadDS3231()
{
  int second,minute,hour,date,month,year,temperature; 
  second=Clock.getSecond();
  minute=Clock.getMinute();
  hour=Clock.getHour(h12, PM);
  date=Clock.getDate();
  month=Clock.getMonth(Century);
  year=Clock.getYear();
  
  temperature=Clock.getTemperature();
  
  Serial.print("20");
  Serial.print(year,DEC);
  Serial.print('-');
  Serial.print(month,DEC);
  Serial.print('-');
  Serial.print(date,DEC);
  Serial.print(' ');
  Serial.print(hour,DEC);
  Serial.print(':');
  Serial.print(minute,DEC);
  Serial.print(':');
  Serial.print(second,DEC);
  Serial.print('\n');
  Serial.print("Temperature=");
  Serial.print(temperature); 
  Serial.print('\n');
}
void loop()
{
    ReadDS3231();
    delay(1000);
	// send what's going on to the serial monitor.
	// Start with the year
/*	Serial.print("2");
	if (Century) {			// Won't need this for 89 years.
		Serial.print("1");
	} else {
		Serial.print("0");
	}
	Serial.print(Clock.getYear(), DEC);
	Serial.print('-');
	// then the month
	Serial.print(Clock.getMonth(Century), DEC);
	Serial.print('-');
	// then the date
	Serial.print(Clock.getDate(), DEC);
	Serial.print(' ');*/
	// and the day of the week
	/*Serial.print(Clock.getDoW(), DEC);
	Serial.print(' ');*/
	// Finally the hour, minute, and second
	/*Serial.print(Clock.getHour(h12, PM), DEC);
	Serial.print(':');
	Serial.print(Clock.getMinute(), DEC);
	Serial.print(':');
	Serial.print(Clock.getSecond(), DEC);
	// Add AM/PM indicator
	if (h12) {
		if (PM) {
			Serial.print(" PM ");
		} else {
			Serial.print(" AM ");
		}
	} else {
		Serial.print(" 24h ");
	}
	// Display the temperature
	Serial.print("T=");
	Serial.print(Clock.getTemperature(), 2);
	// Tell whether the time is (likely to be) valid
	if (Clock.oscillatorCheck()) {
		Serial.print(" O+");
	} else {
		Serial.print(" O-");
	}*/
	// Indicate whether an alarm went off
	/*if (Clock.checkIfAlarm(1)) {
		Serial.print(" A1!");
	}
	if (Clock.checkIfAlarm(2)) {
		Serial.print(" A2!");
	}*/
	// New line on display
	//Serial.print('\n');
       // delay(1000);
	// Display Alarm 1 information
/*	Serial.print("Alarm 1: ");
	Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
	Serial.print(ADay, DEC);
	if (ADy) {
		Serial.print(" DoW");
	} else {
		Serial.print(" Date");
	}
	Serial.print(' ');
	Serial.print(AHour, DEC);
	Serial.print(' ');
	Serial.print(AMinute, DEC);
	Serial.print(' ');
	Serial.print(ASecond, DEC);
	Serial.print(' ');
	if (A12h) {
		if (Apm) {
			Serial.print('pm ');
		} else {
			Serial.print('am ');
		}
	}
	if (Clock.checkAlarmEnabled(1)) {
		Serial.print("enabled");
	}
	Serial.print('\n');
	// Display Alarm 2 information
	Serial.print("Alarm 2: ");
	Clock.getA2Time(ADay, AHour, AMinute, ABits, ADy, A12h, Apm);
	Serial.print(ADay, DEC);
	if (ADy) {
		Serial.print(" DoW");
	} else {
		Serial.print(" Date");
	}
	Serial.print(' ');
	Serial.print(AHour, DEC);
	Serial.print(' ');
	Serial.print(AMinute, DEC);
	Serial.print(' ');
	if (A12h) {
		if (Apm) {
			Serial.print('pm');
		} else {
			Serial.print('am');
		}
	}
	if (Clock.checkAlarmEnabled(2)) {
		Serial.print("enabled");
	}*/
	/* display alarm bits
	Serial.print('\n');
	Serial.print('Alarm bits: ');
	Serial.print(ABits, DEC);
	*/
/*
	Serial.print('\n');
	Serial.print('\n');
	delay(1000);

	// Display the time once more as a test of the getTime() function
	Clock.getTime(year, month, date, DoW, hour, minute, second);
	
        Serial.print(year, DEC);
        Serial.print("/");
	Serial.print(month, DEC);
        Serial.print("/");
	Serial.print(date, DEC);
        Serial.print("day of the week :");
	Serial.println(DoW, DEC);
	Serial.print(hour, DEC);
        Serial.print(":");
	Serial.print(minute, DEC);
        Serial.print(":");
	Serial.println(second, DEC);*/
}

Below is both the code from the library you had suggested in another thread (the DS1307 IIRC) AND the errors. The two are separated.

I’m a little befuddled that I copied and pasted the code (and adjusted the appropriate #includes) and it shot out so many errors.

// This #include statement was automatically added by the Particle IDE.
#include "ds1307.h"

#define DS1307_ADDRESS 0x68
 
#include "application.h"

// Date and time functions using a DS1307 RTC connected via I2C
//
// WIRE IT UP!
//
// DS1307               SPARK CORE
//--------------------------------------------------------------------
// VCC                - Vin (5V only, does not work on 3.3)
// Serial Clock (SCL) - D1 (needs 2.2k to 10k pull up resistor to Vin)
// Serial Data  (SDA) - D0 (needs 2.2k to 10k pull up resistor to Vin)
// Ground             - GND
//--------------------------------------------------------------------

RTC_DS1307 rtc;

void setup() {
  Serial1.begin(57600);
  Wire.begin();
  rtc.begin();

  if (!rtc.isrunning()) {
    Serial1.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    // ...however it doesn't work in the Spark IDE
    // rtc.adjust(DateTime(__DATE__, __TIME__));
    //
    // Try these methods instead:
    //rtc.adjust(DateTime("Jan 12 2014", "11:26:30")); // date, 24 hour time string
    //rtc.adjust(DateTime(1234567890)); // unix time
    rtc.adjust(DateTime(2014, 1, 31, 23, 59, 59)); // year, month, day, hour, min, sec
  }
}

void loop() {
  DateTime now = rtc.now();

  Serial1.print(now.year(), DEC);
  Serial1.print('/');
  Serial1.print(now.month(), DEC);
  Serial1.print('/');
  Serial1.print(now.day(), DEC);
  Serial1.print(' ');
  Serial1.print(now.hour(), DEC);
  Serial1.print(':');
  Serial1.print(now.minute(), DEC);
  Serial1.print(':');
  Serial1.print(now.second(), DEC);
  Serial1.println();

  Serial1.print(" since midnight 1/1/1970 = ");
  Serial1.print(now.unixtime());
  Serial1.print("s = ");
  Serial1.print(now.unixtime() / 86400L);
  Serial1.println("d");

  // calculate a date which is 7 days and 30 seconds into the future
  DateTime future(now.unixtime() + 7 * 86400L + 30);

  Serial1.print(" now + 7d + 30s: ");
  Serial1.print(future.year(), DEC);
  Serial1.print('/');
  Serial1.print(future.month(), DEC);
  Serial1.print('/');
  Serial1.print(future.day(), DEC);
  Serial1.print(' ');
  Serial1.print(future.hour(), DEC);
  Serial1.print(':');
  Serial1.print(future.minute(), DEC);
  Serial1.print(':');
  Serial1.print(future.second(), DEC);
  Serial1.println();

  Serial1.println();
  delay(3000);
}

And the errors:

In file included from /src/rtc_1307lib_dnw.cpp:2:0:

lib/ds1307/src/ds1307.h:14:24: error: expected ')' before 't'
     DateTime (uint32_t t =0);
                        ^


lib/ds1307/src/ds1307.h:15:24: error: expected ')' before 'year'
     DateTime (uint16_t year, uint8_t month, uint8_t day,
                        ^


lib/ds1307/src/ds1307.h:18:5: error: 'uint16_t' does not name a type
     uint16_t year() const       { return 2000 + yOff; }
     ^


lib/ds1307/src/ds1307.h:19:5: error: 'uint8_t' does not name a type
     uint8_t month() const       { return m; }
     ^


lib/ds1307/src/ds1307.h:20:5: error: 'uint8_t' does not name a type
     uint8_t day() const         { return d; }
     ^


lib/ds1307/src/ds1307.h:21:5: error: 'uint8_t' does not name a type
     uint8_t hour() const        { return hh; }
     ^


lib/ds1307/src/ds1307.h:22:5: error: 'uint8_t' does not name a type
     uint8_t minute() const      { return mm; }
     ^


lib/ds1307/src/ds1307.h:23:5: error: 'uint8_t' does not name a type
     uint8_t second() const      { return ss; }
     ^


lib/ds1307/src/ds1307.h:24:5: error: 'uint8_t' does not name a type
     uint8_t dayOfWeek() const;
     ^


lib/ds1307/src/ds1307.h:29:5: error: 'uint32_t' does not name a type
     uint32_t unixtime(void) const;
     ^


lib/ds1307/src/ds1307.h:32:5: error: 'uint8_t' does not name a type
     uint8_t yOff, m, d, hh, mm, ss;
     ^


lib/ds1307/src/ds1307.h:38:12: error: 'uint8_t' does not name a type
     static uint8_t begin(void);
            ^


lib/ds1307/src/ds1307.h:40:5: error: 'uint8_t' does not name a type
     uint8_t isrunning(void);
     ^


/src/rtc_1307lib_dnw.cpp: In function 'void setup()':

/src/rtc_1307lib_dnw.cpp:25:7: error: 'class RTC_DS1307' has no member named 'begin'
 void setup() {
       ^


/src/rtc_1307lib_dnw.cpp:27:12: error: 'class RTC_DS1307' has no member named 'isrunning'
   Wire.begin();
            ^


/src/rtc_1307lib_dnw.cpp:36:48: error: no matching function for call to 'DateTime::DateTime(int, int, int, int, int, int)'
     // Try these methods instead:
                                                ^


/src/rtc_1307lib_dnw.cpp:36:48: note: candidates are:
In file included from /src/rtc_1307lib_dnw.cpp:2:0:
lib/ds1307/src/ds1307.h:17:5: note: DateTime::DateTime(const char*, const char*)
     DateTime (const char* date, const char* time);
     ^
lib/ds1307/src/ds1307.h:17:5: note:   candidate expects 2 arguments, 6 provided
lib/ds1307/src/ds1307.h:12:7: note: constexpr DateTime::DateTime(const DateTime&)
 class DateTime {
       ^
lib/ds1307/src/ds1307.h:12:7: note:   candidate expects 1 argument, 6 provided
lib/ds1307/src/ds1307.h:12:7: note: constexpr DateTime::DateTime(DateTime&&)
lib/ds1307/src/ds1307.h:12:7: note:   candidate expects 1 argument, 6 provided
/src/rtc_1307lib_dnw.cpp: In function 'void loop()':

/src/rtc_1307lib_dnw.cpp:43:21: error: 'class DateTime' has no member named 'year'
 void loop() {
                     ^


/src/rtc_1307lib_dnw.cpp:45:21: error: 'class DateTime' has no member named 'month'
 
                     ^


/src/rtc_1307lib_dnw.cpp:47:21: error: 'class DateTime' has no member named 'day'
   Serial1.print('/');
                     ^


/src/rtc_1307lib_dnw.cpp:49:21: error: 'class DateTime' has no member named 'hour'
   Serial1.print('/');
                     ^


/src/rtc_1307lib_dnw.cpp:51:21: error: 'class DateTime' has no member named 'minute'
   Serial1.print(' ');
                     ^


/src/rtc_1307lib_dnw.cpp:53:21: error: 'class DateTime' has no member named 'second'
   Serial1.print(':');
                     ^


/src/rtc_1307lib_dnw.cpp:57:21: error: 'class DateTime' has no member named 'unixtime'
   Serial1.println();
                     ^


/src/rtc_1307lib_dnw.cpp:59:21: error: 'class DateTime' has no member named 'unixtime'
   Serial1.print(" since midnight 1/1/1970 = ");
                     ^


/src/rtc_1307lib_dnw.cpp:63:23: error: 'class DateTime' has no member named 'unixtime'
   Serial1.println("d");
                       ^


/src/rtc_1307lib_dnw.cpp:66:24: error: 'class DateTime' has no member named 'year'
   DateTime future(now.unixtime() + 7 * 86400L + 30);
                        ^


/src/rtc_1307lib_dnw.cpp:68:24: error: 'class DateTime' has no member named 'month'
   Serial1.print(" now + 7d + 30s: ");
                        ^


/src/rtc_1307lib_dnw.cpp:70:24: error: 'class DateTime' has no member named 'day'
   Serial1.print('/');
                        ^


/src/rtc_1307lib_dnw.cpp:72:24: error: 'class DateTime' has no member named 'hour'
   Serial1.print('/');
                        ^


/src/rtc_1307lib_dnw.cpp:74:24: error: 'class DateTime' has no member named 'minute'
   Serial1.print(' ');
                        ^


/src/rtc_1307lib_dnw.cpp:76:24: error: 'class DateTime' has no member named 'second'
   Serial1.print(':');
                        ^


make[1]: *** [../build/target/user/platform-6src/rtc_1307lib_dnw.o] Error 1

Polling that DS3231 is trivial, the libraries are “much ado about nothing.”

If I were to do what you are trying to do, I may do it like this (untested) method:

#define DS3231_ADDR 0x68  //<<<<<<<<<, check this

uint8_t binaryCodedDecimalToBinary (uint8_t val)
{
  return val - 6 * (val >> 4);
}

time_t getTimeDS3231()
{
  struct tm t;
  // make I2C request
  Wire.beginTransmission(DS3231_ADDR);
  Wire.write((byte)0);
  Wire.endTransmission();
  // read I2C data
  Wire.requestFrom(DS3231_ADDR, 7);
  t.tm_sec = binaryCodedDecimalToBinary(Wire.read() & 0x7F);
  t.tm_min = binaryCodedDecimalToBinary(Wire.read());
  t.tm_hour = binaryCodedDecimalToBinary(Wire.read());
  (void)Wire.read();  //day of week not needed in time_t struct
  t.tm_mday = binaryCodedDecimalToBinary(Wire.read());
  t.tm_mon = binaryCodedDecimalToBinary(Wire.read());
  t.tm_year = binaryCodedDecimalToBinary(Wire.read()) + 2000;  //this may need to be reduced by 1900 for the time_t epoch
  t.tm_isdst = 0;
  time_t t_of_day = mktime(&t);
  return t_of_day;
}

void setup(void)
{
  Serial.begin(9600);
  Wire.begin(DS3231_ADDR); // ...edited to add this...
}

void loop(void)
{
  static uint32_t lastMilllis = 0;
  if(millis() - lastMilllis >= 1000)
  {
    SINGLE_THREADED_BLOCK()
    {
      Time.setTime(getTimeDS3231());
      Serial.print(Time.timeStr());
    }
    lastMilllis += 1000;
  }
}

It should print out your RTC’s clock each second. SINGLE_THREADED_BLOCK would be my way to explicitly show you are attempting to make sure that your Photon doesn’t get reconnected to WiFi and update the RTC between reading the time and setting the clock/printing the time. :wink:

This assumes your RTC is set and this would need some error checking…

1 Like

Cool, thanks! I'll give it a go and report back :slight_smile:

1 Like

How did this code work for you?