B4R Library rESP8266rtc .. a Real Time Clock

Starchild

Active Member
Licensed User
** Now also supports ESP-32 modules **

I created this library as a software based Real Time Clock.
You don't need any additional hardware modules.
It does NOT run any special background code to keep the RTC alive.
It can generate Alarm Events at required Date/Times.
It can be calibrated from your own web based internet UTC time source using it's built in GetUTC function. (see post #7)
It also contains several functions to simplify the manipulation of date/times as seconds.
It gets it's timing by calibrating the millis() function available from Arduino.
Generated Alarm Events are managed by the B4R Scheduler class.

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region
 
Sub Process_Globals
   Public Serial1 As Serial
   Private wifi As ESP8266WiFi
   Private DT(8) As Byte
   Private rtc As ESP8266rtc
End Sub
 
Private Sub AppStart
   Serial1.Initialize(115200)
   Log("AppStart")
 
   If wifi.Connect2("your ssid","your password") Then   'change to your network SSID (use Connect2 if a password is required).
       Log("Connected to wireless network.")
 
       rtc.Initialize("rtc_Alarm",True)
 
       'I have provided my own "url.php" as an example only.
       'you must create your own as per the details in the post for v1-04
       err = rtc.GetUTC(DT,"www.starchild.com.au","/utc.php"))
 
       If err <> 0 Then
               Log("GetUTC failed: ",err)
       End If
 
       rtc.SetClock(DT,8,0)   'offset for Western Australia. UTC +08:00
       Log(rtc.ReadClock(DT))
       Log("RTC: ",DT(0),",",DT(1),",",DT(2),",",DT(3),",",DT(4),",",DT(5),",",DT(6),",",DT(7))
 
        rtc.SetAlarm(1,rtc.Sec2DT(rtc.DT2Sec(DT)+10))
        rtc.SetAlarm(2,rtc.Sec2DT(rtc.DT2Sec(DT)+5))
        rtc.SetAlarm(3,rtc.Sec2DT(rtc.DT2Sec(DT)+15))
        rtc.SetAlarm(9,rtc.Sec2DT(rtc.DT2Sec(DT+rtc.SECONDS_1MINUTE))
        rtc.SetAlarm(5,rtc.ThisTime(6,30,0))   'set alarm for 6:30am (within the next 24hrs)
     Else
       Log("Failed to connect.")
    End If
 
End Sub
 
private Sub rtc_Alarm(index As Byte)
    If index=0 Then
        'tick every second
        rtc.ReadClock(DT)
        Log("RTC: ",rtc.ShortDOW(DT),", ",rtc.ShortDate(DT),", ",rtc.Time24(DT))
        Return
    End If
    Log("AlarmEvent:  ",index)
End Sub

Notes: My testing over several days showed a loss of 1 to 2 sec per day. The RTC could be set (SetClock) every week or so from the GetUTC() function if it is required to maintain accuracy. As the Arduino Millis() function can only count continuously for about 40days the RTC should be set at least once a month.

Now updated to v1.05
See post below for details.
 

Attachments

Last edited:

Starchild

Active Member
Licensed User
I have updated the rESP8266rtc library to version 1.01
It can be downloaded from the top post.

New Functions:
ShortDate .. returns a string formatted with a simple date.
Time12 .. returns a string formatted with a 12 hour time (with am/pm suffix)
Time24 .. returns a string formatted with a 24 hour time (includes seconds)
SECONDS_1WEEK .. constant for 1 week as seconds value
date/time array now returns day-of-week field in formerly reserved byte for functions ReadClock and Sec2DT.

Bug fix:
resolved issue in converting between seconds and date/time array.

--------------
 
Last edited:

Starchild

Active Member
Licensed User
I have updated the rESP8266rtc library to version 1.02
It can be downloaded from the top post.
New Functions:
ShortDOW .. returns a string formatted with a 3 character day-of-week name. (ie. "Mon", or "Tue", etc.)
 

Starchild

Active Member
Licensed User
New update for rESP8266rtc library, now v1.04
The download in the top post has been updated.

As reported by "janderkan" the time server TimeAPI.org is dead.

The library function "GetUTC()" has been rewritten to allow your own time source to be accessed over the internet.

New function:
... rtc.GetUTC(DT() as byte, Host as string, Url as string)

The example code in the top post has been updated to use this new function with my own "utc.php" URL file.
You can use my site to do testing but you must set up your own time source on your own web site.

Note: I will be deleting my utc.php URL from my web site in the near future, so don't rely on it.

I have attached the zip "time source url.zip" containing the PHP script file "utc.php" for you to place on your own web site.
 

Attachments

Last edited:

Kevin

Well-Known Member
Licensed User
I'm using this handy library in my project and love the ability to set alarms.

From what I can tell, there isn't a built-in method for setting an alarm simply as a time. For example, to set an alarm for the next occurrence of 00:30. So if it is currently before 00:30, the alarm would be set to today's date @ 00:30. If it is after 00:30, then it would be set to tomorrow's date @ 00:30.

I'm trying to work out a little sub where I can pass a time to it (00:30) and have it return a DT object that would represent the next occurrence of this time. With this object, I would then set an alarm with using something like rtc.SetAlarm(1,MyDT)

I have ideas on how I could do it, but I feel like there is probably a much easier way than what I am thinking. I am trying to follow some examples based on general Google searches but the examples use methods not available to me in B4R.
 

Kevin

Well-Known Member
Licensed User
Update: This is what I came up with in case anyone is interested. I have tested when the requested time has not yet occurred but have not had a chance to test when the requested time has passed. I think the math is right. I'm heading out the door but will test more thoroughly when I have a chance.

Edit: I left it running overnight and confirmed this morning that the alarm event triggered where I had it set (on the next day), so this code does work. There may be a more efficient way, but it does work.

B4X:
Private Sub MyDT (HHMM As String) As Byte(8) ' Example:  "02:00", 24 hour format
    Dim Result(8) As Byte
    Dim bc As ByteConverter
    Dim HH, MM, RequestedTimeInSeconds As Long
    Dim cHH, cMM, cSS, CurrentTimeInSeconds As Long
 
    Dim n As Byte = 0
    For Each s() As Byte In bc.Split(HHMM, ":")
        Select n
            Case 0
                HH = bc.StringFromBytes(s)
            Case 1
                MM = bc.StringFromBytes(s)
        End Select
        n = n + 1
    Next
    RequestedTimeInSeconds = (HH * 3600) + (MM * 60)
 
    rtc.ReadClock(DT)
    Dim CT As String = rtc.Time24(DT)
    Dim n As Byte = 0
    For Each s() As Byte In bc.Split(CT, ":")
        Select n
            Case 0
                cHH = bc.StringFromBytes(s)
            Case 1
                cMM = bc.StringFromBytes(s)
            Case 2
                cSS = bc.StringFromBytes(s)
        End Select
        n = n + 1
    Next
 
    CurrentTimeInSeconds = (cHH * 3600) + (cMM * 60) + cSS
 
    If RequestedTimeInSeconds > CurrentTimeInSeconds Then 'Return a DT object for today at requested time
        Result = DT
        Result(4) = HH 'Hour
        Result(5) = MM 'Min
        Result(6) = 0  'Sec
        Return Result
    Else 'Return a DT object for tomorrow at requested time
        Dim Offset As Long = 86400 - (CurrentTimeInSeconds - RequestedTimeInSeconds)
        Result = rtc.Sec2DT (rtc.DT2Sec(DT) + Offset)
        Return Result
    End If
 
    ' Example:  rtc.SetAlarm(1, MyDT ("00:30"))

End Sub
 
Last edited:

Starchild

Active Member
Licensed User
I'm using this handy library in my project and love the ability to set alarms.

From what I can tell, there isn't a built-in method for setting an alarm simply as a time. For example, to set an alarm for the next occurrence of 00:30. So if it is currently before 00:30, the alarm would be set to today's date @ 00:30. If it is after 00:30, then it would be set to tomorrow's date @ 00:30.

I'm trying to work out a little sub where I can pass a time to it (00:30) and have it return a DT object that would represent the next occurrence of this time. With this object, I would then set an alarm with using something like rtc.SetAlarm(1,MyDT)

I have ideas on how I could do it, but I feel like there is probably a much easier way than what I am thinking. I am trying to follow some examples based on general Google searches but the examples use methods not available to me in B4R.
Sorry for my delay in my reply.
Good to see you have come up with a solution.

For me, I would want to handle date/time values as an 8 byte array, as in the example. (strings are difficult to manipulate, and memory inefficient with B4R coding)
In this case the time bytes for hour/minute/second (of the alarm) can be numerically tested to determine if the required alarm time is before the current time (a couple of IF statements) and if so, then adding seconds for 1 day to the alarm date/time value (as seconds). Then use this new date/time value to set the alarm event.

Hope this helps.
 

Kevin

Well-Known Member
Licensed User
I appreciate the feedback. I'm trying to wrap my head around working with bytes. At some point I may revisit this code in order to do it more efficiently. I'm getting very close to finally being finished with the programming aspect and hope to put it to actual use soon.

I appreciate the time library. It is very useful in my project. :)
 

Starchild

Active Member
Licensed User
New update for rESP8266rtc library, now v1.05
The download in the top post has been updated.

This library can now also be used for the ESP-32 modules.

Thanks to Kevin's request above, I have added the following function.

... rtc.ThisTime(Hour,Minute,Seconds) .. returns date/time within the next 24 hours.

example:
rtc.SetAlarm(5,rtc.ThisTime(6,30,0))
'if current time is 10am, then it sets alarm for 6:30am tomorrow, but
'if current time is 5am, then it sets alarm for 6:30am later this morning.
 
Last edited:
Top