[Submission] Real Time Clock Library for Spark

I have a new Real Time Clock library for Spark available that I hope everybody will find useful until the :spark: team gives us access to the on-chip RTC. This library provides a real-time clock function by getting the current time from an NTP server and then using the millis() function to add to that initial time. The base NTP time is updated periodically so the clock does not drift much. In my testing, the clock is accurate to within one second of real time.

The library is available here: https://github.com/bkobkobko/SparkCoreLibraries

The library obeys the NTP kiss-of-death and tries to back-off when a NTP server complains you are using it too much. The NTP update rate is once per hour by default but you can set this to as low as five minutes. In my testing, once per hour or once per day are good choices. The library uses pool.ntp.org so that no single host gets over used. For those of you with your own online hosts, If you can contribute a host to be in the NTP pool, everyone would benefit!

The library provides time and date values as unsigned integers like other time libraries, but also provides a nice selection of Arduino String return values. You can get both 12- and 24-hour formats. This makes it super simple to build up your own time formats! The library also handles time zones and daylight savings time for the US and European rules. You can, of course, turn off daylight savings time and set the time zone to zero, if you need to.

For those of you looking for a time and date stamp for your sensor data, you will find two pre-formatted Strings, one with time zone taken in to account and one that returns UTC or Zulu time, which I recommend. See the example program for details.

There is a sample program in the git, but here’s a simple example using Arduino Strings to give you the flavor of it:

unsigned long currentTime = rtc.now();
String timeStr;
timeStr += rtc.hour12String(currentTime);
timeStr += ":";
timeStr += rtc.minuteString(currentTime);
timeStr += ":";
timeStr += rtc.secondString(currentTime);	
timeStr += " ";	
timeStr += rtc.AMPMString(currentTime);

timeStr would then have a value something like “12:09:58 PM” since the strings provide nice leading-zeros.

I am sure there will be bugs! Please feel free to post me here or put in a git issue. There is not a lot of doc right now, but I am slowly writing something up.

Have fun!

18 Likes

Great work, can’t wait to try this out!

2 Likes

I have incorporated this library into my project this evening.

Only tweak I made was to #include “application.h” from within SparkTime.h as I compile locally.

Works really well - many thanks @bko

2 Likes

I added the line

#include "application.h" 

Now that the WebIDE does not preprocess included library files.

2 Likes

Hi Everybody,

Since it is going to be Daylight Savings Time starting on Sunday in the US, I tested the DST code in SparkTime again to make sure it was ready and it worked great, so hopefully your clock will Spring forward if you have US DST turned on. If you are in the parts of the US that don’t use DST (Hi Arizona!) then you can turn it off with:

  rtc.setUseDST(false);

If you are in Europe, your DST starts later. You can do:

  rtc.setUseDST(true); //default
  rts.setUseEuroDSTRule(true);

Your UTC timestamp will not be effected by DST at all.

  unsigned long currentTime = rtc.now();
  String myString = rtc.ISODateUTCString(currentTime);
2 Likes

So that is why my clock is showing 1 hour false (GMT +1 zone) :smile:

Wonder why I can’t compile the latest https://github.com/bkobkobko/SparkCoreLibraries
getting error that I have not seen before:

In file included from …/inc/spark_wiring.h:30:0,
from …/inc/application.h:31,
from SparkTime.h:4,
from SparkTime.cpp:31:
…/…/core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning “Defaulting to Release Build” [-Wcpp]
In file included from …/inc/spark_wiring.h:30:0,

HI @mippen

Sorry about Europe not being the default for DST. You can do this:

    rtc.setUseDST(true); //default
    rts.setUseEuroDSTRule(true);

Tell me more about the error you are getting--I have not seen it. I have compiled \ the library recently in both the webIDE and locally.

This part below:

is a warning that you currently get anytime you compile, but warnings are not shown in the webIDE unless there is also an error somewhere. This confusing warning is getting cleared up soon.

Was there also an error displayed? I would like to run this down. Thanks!

Fellow user @Coffee found a bug in my SparkTime library for European Daylight Savings Time. The bug was it was going to use the US end date for DST instead of the Euro date.

The bug should be fixed now in my latest master on github.

I recently added the Spark-ported Adafruit libraries for the i2c seven-segment backpack there as well since some folks here wanted them.

Please feel free to let me know when you find bugs! Either here or on github are both fine.

I “solved” the issue with the time by using a european server for getting the time.
Seems to work… lets find out in a couple of weeks when our daylight saving comes.

The other issue disappeared when I removed unused files in my project.
I have my own header file that I have not started to use yet. Have not been a problem until now.
Somehow it reacts on the file but removing it solved that problem.

Its really easy to use and conveniant, but I think there might be a problem??
I am building an alarm clock project and got an Adafruit lcd and your library.
Im getting a Red SOS (panic) of 8 flashes. How much RAM does it uses ???
I mean … I cannot believe that my almost-empty project with 2 library
(second lib: https://github.com/pkourany/Adafruit_SSD1306)

Hi @jflecool2

RAM is really tight right now. I have suggested to the Spark team the looking at base RAM usage should be a goal. Many folks have found out that they cannot use both TCP and UDP at the same time, even without SparkTime or other libraries.

SparkTime uses about 800 bytes and UDP uses another 700, so together they take around 1500 bytes.

The Adafruit library has a memory buffer for the all the display pixels and so that also takes some RAM. How much RAM depends on which display size you have.

Now that some real-time clock code is moving into the core firmware, this library is going to become less and less relevant as the core firmware has more features. So far, the core firmware has not addressed daylight-savings time and the easy to use Strings, and the core RTC is not done yet, but is close.

If there are features you are not using, feel free to edit them out! I hope to reduce the memory footprint too since I have built some clocks too.

Quick update: I did some experiments this morning and found I can push some things around in the code and dramatically reduce the RAM requirements for SparkTIme. I will try to push out an update to my github tonight.

2 Likes

Thanks for taking some time to answer me. It’s appreciated.
But even with that: 1500 bytes (1.5 kb) is ~7.5% of the ram. It’s still FAR away from the 20kb.
And no, there is no new without delete in my code… How can I compile individual object (c++ to .o) and mesure the ram usage of it ? (like coffee mesured in this thread: https://community.spark.io/t/spark-core-not-booting-after-flashing-my-big-firmware/3329/17

Hi @jflecool2

The 20kb is shared with all the Spark code so you really don't have but around 4k for your firmware, and using TCP or UDP eats into that as well.

If you want more visibility, you should move to doing local builds instead of using the webIDE. The output that coffee showed is the default makefile output when building locally which is a good start--just remember everything in data and bss ends up in RAM.

Once you build locally there are other ways to zoom in on what is taking up your RAM using the nm tool.

OK I have updated my github:

The change was to move the fancy strings outside the class completely–none of the other ways of declaring these ensured they ended up only in flash. This reduced the RAM footprint from 712 bytes to 148 bytes in my local build. My testing is ongoing but it is working great so far.

Please let me know here on the forum or via github issues if you have problems.

2 Likes

Hello @bko I’m new to the sparkcore.
Thank you for your library.
My project consists in turning on and off a lamp with the relay shield at specific hours.

I added the libraries and wrote my script but I have some errorst that I don’t understand.

My code is:

// This #include statement was automatically added by the Spark IDE.
#include "lib1.h"
int lamp = D0;
void setup() {
pinMode (lamp,OUTPUT);
digitalWrite(lamp,LOW);
rtc.setUseEuroDSTRule(true);
}
void loop() {
    
unsigned long currentTime = rtc.now();
String timeStr;
timeStr += rtc.hour12String(currentTime);
timeStr += ":";
timeStr += rtc.minuteString(currentTime);
timeStr += ":";
timeStr += rtc.secondString(currentTime);	
timeStr += " ";	
timeStr += rtc.AMPMString(currentTime);
if (timeStr=="05:00:00 AM"){
digitalWrite(lamp,HIGH);
}
if(timeStr=="06:50:00 AM"){
digitalWrite(lamp,LOW);
}
}

The errors I have are:

In file included from ../inc/spark_wiring.h:30:0,
from ../inc/application.h:31,
from alarm.cpp:2:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
alarm.cpp: In function 'void setup()':
alarm.cpp:12:1: error: 'rtc' was not declared in this scope
alarm.cpp: In function 'void loop()':
alarm.cpp:18:29: error: 'rtc' was not declared in this scope
make: *** [alarm.o] Error 1

What do you think about this errors?
Is it possible to have a full example script on how use the library maybe?

Also, is there a way to ahce like a serial monitor in order to see wich hour “rtc.now()” returns?

Thank you very much for your support.

PS: It is my first “difficiult” request in the forum so I hope to have given all the information you need.

HI @schvic

You are missing the global setup code that goes before the setup() function.

UDP UDPClient;
SparkTime rtc;

If you look in my github there is a timentemp.cpp example using an Adafruit LED and SparkTimeExample.cpp that uses the serial port. Unless you need the String for something else, you could compare the numeric time. With your current code, if you boot the core after 5am but before 6:50, the lamp with not be on, so you can write a more complicated if statement that would cover those times.


if (rtc.hour(currentTime)==5) {  //all of the 5am hour
    digitalWrite(lamp,HIGH);
} else if (rtc.hour(currentTime)==6 && rtc.minute(currentTime)<50) { // from 6:00 to 6:49:59
    digitalWrite(lamp,HIGH);
} else {
    digitalWrite(lamp,LOW);
}

On Arduino, you can read the last value your wrote to a digital pin but that is not working yet on Spark. It work soon and then you can see if the lamp is already on and maybe simplify the code some.

Thank you very much @bko. The thing that I don’t get is that if it is 5 AM or 5 PM there will be no difference if we don’t include the “PM” or “AM” parameter in the if statement.

I suppose code would be:

 if (rtc.hour(currentTime)==5 && rtc.AMPMString(currentTime)=="AM") {  //all of the 5am hour
    digitalWrite(lamp,HIGH);
} else if (rtc.hour(currentTime)==6 && rtc.minute(currentTime)<50 && rtc.AMPMString(currentTime)=="AM")) { // from 6:00 to 6:49:59
    digitalWrite(lamp,HIGH);
} else {
    digitalWrite(lamp,LOW);
}

What are your thoughts about this?

Again thank you for your support.

Hi @schvic

The rtc.hour() method returns the 24-hour time as integer value in the range 0 to 23. It is best used for control applications like yours.

If you want an Arduino String object to put on a display etc., then there are two methods, one for the 24-hour string called rtc.hourString() which returns “00”-“23” for European or military time or the 12-hour String called rtc.hour12String() which returns “01” to “12” and back to “01” for the normal US time.

Also, I don’t know why the core begins blinking RED when I upload my script.

What could be the problem in my code?