Syncing the RTC

In this example we will be using the GPRSbee module to connect to the SODAQ time server in order to retrieve the current date and time stamp for the purpose of updating the internal Real Time Clock (RTC) on the SODAQ Mbili board.

If you navigate your browser to the SODAQ time server at: http://time.sodaq.net/ you will see a numeric value shown in the upper left hand corner of the screen. This value represents the current UTC time, specified in seconds since the start of Epoch time (00:00:00 01/01/1970). Here this value is retrieved and used to update the DS3231 RTC time stamp.

Required Components

  • SODAQ Mbili Board
  • 0.5W Solar Panel
  • 1aH Battery Pack
  • GPRSbee Module
  • MicroSim

Required Libraries

  • Wire
  • Sodaq_DS3231
  • GPRSbee

Library Installation

The Wire Library comes pre-installed with the Arduino IDE, and so there is no need to download or install it. The Sodaq_DS3231 and the GPRSbeeВ libraries are included with the SODAQ Mbili files that you have already installed.

If necessary, refer to Section 2 of the Getting Started guide for details on where to download from and how to install the SODAQ Mbili files.

Hardware Setup

You should refer to the board diagram, the Grove sockets page, and the GPRSbee Connection for additional information.

  1. First, install the GPRSbee module into the Bee socket.
  2. Then, using the wiring diagram for the Switched Power Method, plug the 1A LiPo battery and GPRSbee power connectors into their sockets.
  3. Next, plug the 0.5W solar panel into its socket.

Turn on the SODAQ Mbili board, compile and upload the following sketch from the Arduino IDE onto the SODAQ Mbili board. Leave the USB cable plugged in and open the Serial Monitor (Ctrl-Shift-M) and ensure that it is set to the 9600 baud rate.

After you open the Serial Monitor (Ctrl-Shift-M), you should see output similar to this:

Note: If the current time stamp of the RTC is within about 30 seconds of the retrieved time stamp, the RTC will not be updated and you will not see the second line of output.

Sketch Code

#include <Wire.h>
#include <Sodaq_DS3231.h>
#include <GPRSbee.h>

#define APN "internet"
#define APN_USERNAME ""
#define APN_PASSWORD ""

#define TIME_URL "time.sodaq.net"
#define TIME_ZONE 0.0
#define TIME_ZONE_SEC (TIME_ZONEВ * 3600)

void setup() 
{
    //Start Serial for serial monitor
    Serial.begin(9600);
 
    //Start Serial1 the Bee port
    Serial1.begin(9600);
  
    //Intialise the GPRSbee
    gprsbee.init(Serial1, BEECTS, BEEDTR);
  
    //Uncomment the line below to debug the GPRSbee with the serial monitor
    //gprsbee.setDiag(Serial);
  
    //This is required for the Switched Power method
    gprsbee.setPowerSwitchedOnOff(true);
  
    //Sync time
    syncRTCwithServer();
  
    //Print out new date/time
    Serial.println(getDateTime());
}

void loop() 
{
}

void syncRTCwithServer()
{
    char buffer[20];
   
    if (gprsbee.doHTTPGET(APN, APN_USERNAME, APN_PASSWORD, TIME_URL, buffer, sizeof(buffer)))
    {
        Serial.println("HTTP GET: " + String(buffer)); 
         
        //Convert the time stamp to unsigned long
        char *ptr;
        uint32_t newTs = strtoul(buffer, &ptr, 0);
  
        // Add the timezone difference plus a few seconds 
        // to compensate for transmission and processing delay
        newTs += 3 + TIME_ZONE_SEC;
 
        // If conversion was successful
        if (ptr != buffer) 
        {
            //Get the old time stamp
            uint32_t oldTs = rtc.now().getEpoch();
            int32_t diffTs = abs(newTs - oldTs);

            //If time is more than 30s off, update
            if (diffTs > 30) 
            {
                //Display old and new time stamps
                Serial.print("Updating RTC, old=" + String(oldTs));
                Serial.println(" new=" + String(newTs));

                //Update the rtc
                rtc.setEpoch(newTs);
            }
        }
    }
}

String getDateTime()
{
     String dateTimeStr;
  
    //Create a DateTime object from the current time
    DateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));

    //Convert it to a String
    dt.addToString(dateTimeStr);
  
    return dateTimeStr;  
}

Sketch Code Breakdown

Library Includes

Here the necessary library files are included in the sketch using the #include compiler directive.

#include <Wire.h>
#include <Sodaq_DS3231.h>
#include <GPRSbee.h>

Globals

Here we specify the Access Point Name (APN), APN Username, and APN Password for the network that the GPRSbee will connect to. You will need to change these APN values to those required by your specific network. Next we specify the URL for the time server which will return the current UTC time stamp. You can modify TIME_ZONE to reflect your current time zone, specified in hours (or part hours) +/- relative to UTC.

#define APN "internet"
#define APN_USERNAME ""
#define APN_PASSWORD ""

#define TIME_URL "time.sodaq.net"
#define TIME_ZONE 0.0
#define TIME_ZONE_SEC (TIME_ZONE * 3600)

setup()

On the SODAQ Mbili board, the serial connection to the PC is connected to the first serial port which is accessed through the Serial object, and the Bee socket is connected to the second serial port which is accessed through the Serial1 object.

We start with initializing both Serial and Serial1 with calls to Serial.begin(). We then initialize the GPRSbee module using the methodВ gprsbee.init(). The three parameters passed to this method include: the Serial object that the GPRSbee module is connected to, the CTS pin (BEECTS), and the power pin (BEEDTR).

We must also make a call to gprsbee.setPowerSwitchedOnOff(), passing the argument true. This instructs the GPRSbee library to use the Switched Power Method. (The method that we wired the GPRSbee and battery for in the Hardware Setup section.)

Next we call the user defined method syncRTCwithServer() which retrieves the current time stamp from the server and updates the RTC. Finally, we print the updatedВ date and time using aВ reading from the RTC.

void setup() 
{
    //Start Serial for serial monitor
    Serial.begin(9600);
  
    //Start Serial1 the Bee port
    Serial1.begin(9600);
    
    //Intialise the GPRSbee
    gprsbee.init(Serial1, BEECTS, BEEDTR);
 
    //Uncomment the line below to debug the GPRSbee with the serial monitor
    //gprsbee.setDiag(Serial);
  
    //This is required for the Switched Power method
    gprsbee.setPowerSwitchedOnOff(true);
   
    //Sync time
    syncRTCwithServer();
 
   //Print out new date/time
    Serial.println(getDateTime());
}

loop()

The code in this sketch attempts to synchronize the RTC once when the setup() method is called. No further code is executed and so the loop() method is empty.

void loop() 
{
}

syncRTCwithServer()

Here we attempt a HTTP GET request with the gprsbee.doHTTPGET() passing the parameters for the APN, APN_USERNAME, APN_PASSWORD, the URL, a return buffer and the size of that return buffer. If the HTTP GET request was successful, we then output the returned data (stored in buffer) to the Serial Monitor.

The returned data is an ASCII time stamp specifying  the number of seconds in Epoch time. We then convert the value to an unsigned long integer (using strtoul()) and add both the timezone seconds as well as a few additional seconds to compensate for any transmission and processing delays.

If the conversion was successful, we then check if the old time stamp from the RTC is more than 30 seconds different from the new time stamp from the time server. If so, we then display both the old and new time stamps in the Serial Monitor and then update the RTC with the new time stamp using the method rtc.setEpoch().

void syncRTCwithServer()
{
    char buffer[20];
  
    if (gprsbee.doHTTPGET(APN, APN_USERNAME, APN_PASSWORD, TIME_URL, buffer, sizeof(buffer))) 
    {
       Serial.println("HTTP GET: " + String(buffer)); 
     
        //Convert the time stamp to unsigned long
        char *ptr;
        uint32_t newTs = strtoul(buffer, &ptr, 0);

        //Add the timezone difference plus a few seconds 
        //to compensate for transmission and processing delay
        newTs += 3 + TIME_ZONE_SEC;
  
        //If conversion was successful
        if (ptr != buffer) 
        {
            //Get the old time stamp
            uint32_t oldTs = rtc.now().getEpoch();
            int32_t diffTs = abs(newTs - oldTs);

            //If time is more than 30s off, update
            if (diffTs > 30) 
            {
                //Display old and new time stamps
                Serial.print("Updating RTC, old=" + String(oldTs));
                Serial.println(" new=" + String(newTs));

                //Update the rtc
                rtc.setEpoch(newTs);
             }
        }
    }
}

getDateTime()

Here we return a Date & Time reading from the RTC in a String format. First a DateTime object is constructed using a time reading from the DS3231 RTC. This is then converted into a String using the method DateTime.addToString() the result of which is then returned from this method.

String getDateTime()
{
     String dateTimeStr;
  
    //Create a DateTime object from the current time
    DateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));

    //Convert it to a String
    dt.addToString(dateTimeStr);
  
    return dateTimeStr;  
}