ESP8266 with ReadyMail.h and TLS: issue reading DS3231

Using the example AutoClient.ino from .../examples/Network/AutoClient/AutoClient.ino from the ReadyMail library I succesfully send emails from my TLS mailserver to my Gmail account.
All requirements for TLS and for ESP8266 when using this library (including those mentioned in the ReadyMail discussion group) are met.

But when I add a DS3231 module that is correctly programmed to current time and date I get 0:00:00 0/0/0 for time and date in the serial monitor.
Checking and rechecking the DS3231 after and before use result always in correct time and date.

Edit: the code to read the DS3231 works well in other applications where the ReadyMail code is not used.

What could be wrong, or how to solve this?

Below:

  1. output serial monitor
  2. code
Connecting to Wi-Fi.................
Connected with IP: 192.168.1.194

ReadyMail, version 0.3.6
ReadyMail[smtp][1] Connecting to "webreus.email" via port 587...
ReadyMail[smtp][2] Sending greeting...
ReadyMail[smtp][3] Starting TLS...
ReadyMail[smtp][3] Performing TLS handshake...
ReadyMail[smtp][3] TLS handshake done
ReadyMail[smtp][2] Sending greeting...
ReadyMail[smtp][2] Service is ready
ReadyMail[smtp][5] Authenticating...
ReadyMail[smtp][5] The client is authenticated successfully
ReadyMail[smtp][11] Sending Email...
ReadyMail[smtp][11] Sending envelope...
ReadyMail[smtp][12] Sending headers...
ReadyMail[smtp][14] Sending multipart content (alternative)...
ReadyMail[smtp][14] Sending text/plain body...
ReadyMail[smtp][14] Sending text/html body...
ReadyMail[smtp][14] The Email is sent successfully
DS3231 successfull

0:00:00 0/0/0
/**
   The example to send simple text message using ReadyClient class which port can be changed at run time.
   For proper network/SSL client and port selection, please see http://bit.ly/437GkRA
*/
#include <Wire.h>
#include <Arduino.h>
// #include <WiFi.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>

#define ENABLE_SMTP
#define ENABLE_DEBUG
#define READYMAIL_DEBUG_PORT Serial
#define USE_ESP_SSLCLIENT

#if defined(USE_ESP_SSLCLIENT)
#include <ESP_SSLClient.h>
#else
#include <NetworkClientSecure.h>
#endif

#if defined(USE_ESP_SSLCLIENT)
#define READYCLIENT_SSL_CLIENT ESP_SSLClient
#define READYCLIENT_TYPE_1 // TYPE 1 when using ESP_SSLClient
#else
#define READYCLIENT_SSL_CLIENT NetworkClientSecure
#define READYCLIENT_TYPE_2 // TYPE 2 when using NetworkClientSecure
#endif

#include <ReadyMail.h>

#define SMTP_HOST "_______"
#define AUTHOR_EMAIL "_______"
#define AUTHOR_PASSWORD "_______"
#define RECIPIENT_EMAIL "_______"
#define WIFI_SSID "_______"
#define WIFI_PASSWORD "_______"

#if defined(USE_ESP_SSLCLIENT)
WiFiClient basic_client;
ESP_SSLClient ssl_client;
#else
NetworkClientSecure ssl_client;
#endif

ReadyClient rClient(ssl_client);
SMTPClient smtp(rClient);

boolean ds3231Check = true; // DS3231 check
#define alarmPin LED_BUILTIN // GPIO2
#define DS3231_I2C_ADDRESS 0x68
byte zero = 0x00; // workaround for issue #527

// For more information, see https://bit.ly/44g9Fuc
void smtpCb(SMTPStatus status)
{
  if (status.progress.available)
    ReadyMail.printf("ReadyMail[smtp][%d] Uploading file %s, %d %% completed\n", status.state,
                     status.progress.filename.c_str(), status.progress.value);
  else
    ReadyMail.printf("ReadyMail[smtp][%d]%s\n", status.state, status.text.c_str());
}

void sendEmail(int port)
{
  smtp.connect(SMTP_HOST, port, smtpCb);
  if (!smtp.isConnected())
    return;

  smtp.authenticate(AUTHOR_EMAIL, AUTHOR_PASSWORD, readymail_auth_password);
  if (!smtp.isAuthenticated())
    return;

  SMTPMessage msg;
  msg.headers.add(rfc822_subject, "DS3231 + ReadyMAil test via port " + String(port));
  msg.headers.add(rfc822_from, "ReadyMail <" + String(AUTHOR_EMAIL) + ">");
  msg.headers.add(rfc822_to, "User <" + String(RECIPIENT_EMAIL) + ">");

  String bodyText = "DS3231 test";
  msg.text.body(bodyText);
  msg.html.body("<html><body><div style=\"color:#cc0066;\">" + bodyText + "</div></body></html>");
  msg.timestamp = 1746013620;
  smtp.send(msg);
}

void setup()
{
  Serial.begin(115200);
  Serial.println();
  delay(250);
  Serial.println(__FILE__);
  Serial.println("              ");
  Serial.println("ESP8266_ReadyMail_AutoClient_1a");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  pinMode(alarmPin, OUTPUT); // GPIO2

  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(300);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

#if defined(USE_ESP_SSLCLIENT)
  ssl_client.setClient(&basic_client);
#endif

  ssl_client.setInsecure();
  ssl_client.setBufferSizes(1024, 1024);  // https://github.com/mobizt/ReadyMail/discussions/12#discussioncomment-14573152

  Serial.println("ReadyMail, version " + String(READYMAIL_VERSION));

  rClient.addPort(587, readymail_protocol_tls);
  sendEmail(587); // STARTTLS
  delay(2000);

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  delay(100);
  if (minute < 61)
  {
    Serial.println(F("DS3231 successfull"));
    for (int x = 0; x < 20; x++) {
      digitalWrite(alarmPin, LOW);   // set the LED on
      delay(50);              // wait ms
      digitalWrite(alarmPin, HIGH);    // set the LED off
      delay(50);              // wait ms
    }
    delay(500);
  }
  Serial.println();
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(F(":"));
  if (minute < 10)
  {
    Serial.print(F("0"));
  }
  Serial.print(minute, DEC);
  Serial.print(F(":"));
  if (second < 10)
  {
    Serial.print(F("0"));
  }
  Serial.print(second, DEC);
  Serial.print(F(" "));
  Serial.print(dayOfMonth, DEC);
  Serial.print(F("/"));
  Serial.print(month, DEC);
  Serial.print(F("/"));
  Serial.println(year, DEC);
  Serial.flush();
  delay(1000);
}

void readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}

void loop()
{
}

No. Why do you need a DS3231 RTC module when you have an internet connected ESP8266 that can synchronize time via NTP? You don't need that RTC to keep time.

Because my hardware is equipped for it. And because I like to know the reason for this issue.

Let's strip it down then and just try to read the DS3231 with the same logic. What does this sketch output?

#include <Arduino.h>
#include <Wire.h>

#define alarmPin LED_BUILTIN // GPIO2
#define DS3231_I2C_ADDRESS 0x68

void setup() {
  Serial.begin(115200);
  Serial.println();
  Wire.begin();
}

void readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}

void loop()
{
  byte second = 0, minute = 0, hour = 0, dayOfWeek = 0, dayOfMonth = 0, month = 0, year = 0;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  delay(100);
  if (minute < 61)
  {
    Serial.println(F("DS3231 successfull"));
    for (int x = 0; x < 20; x++) {
      digitalWrite(alarmPin, LOW);   // set the LED on
      delay(50);              // wait ms
      digitalWrite(alarmPin, HIGH);    // set the LED off
      delay(50);              // wait ms
    }
    delay(500);
  }
  Serial.println();
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(F(":"));
  if (minute < 10)
  {
    Serial.print(F("0"));
  }
  Serial.print(minute, DEC);
  Serial.print(F(":"));
  if (second < 10)
  {
    Serial.print(F("0"));
  }
  Serial.print(second, DEC);
  Serial.print(F(" "));
  Serial.print(dayOfMonth, DEC);
  Serial.print(F("/"));
  Serial.print(month, DEC);
  Serial.print(F("/"));
  Serial.println(year, DEC);
  Serial.flush();
  delay(1000);
}

Wait a second. There's no Wire.begin() in your sketch. I've edited the sketch to add it in setup(). Did you use Wire.begin() with special SCL and SDA pins that are non-default?

1 Like

@maxgerhardt Great find!!! Thank you for your patience!

No, just

  Wire.begin(4, 5);         // I2C 4 = SDA, 5 = SCL

And indeed, I am currently looking at bypassing the DS3231. Thank you for your advice.

You can install the official NTPClient library from Arduino, that makes it extremely easy to sync time periodically, in the correct timezone, and checking for a successfull sync:

The ESP8266 core also has an example of using a raw UDP socket to do NTP, but it's more involved:

https://github.com/esp8266/Arduino/blob/3.1.2/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino

1 Like

@maxgerhardt Thanks for those references.

In the examples I do not see a way to extract date (dayOfWeek, dayOfMonth, month, year).
How to do in the NTPClient.h library?

It does have day of the week via getDay() as 0 to 6 (0 is Sunday)

But, wow, really no way to get the day of the month, month and year. You would have to use getEpochTime() to get the Unix timestamp (seconds since January 1st 1970) then use localtime() function to decode it into the full date. How cumbersome.

A PR to add missing functions has been stuck for years with no change. https://github.com/arduino-libraries/NTPClient/pull/94

I'd actually change my recommendation to use the library "Time" by PaulStoffregen, that gives you TimeLib.h and the full range of functions

The above is a full NTP example for ESP8266 using the "Time" library. Better use that.

1 Like

@maxgerhardt I read your comment above here just now, and I posted a similar question on this forum a half hour earlier. I will try and delete that post and use your answer given here.

No...

No...

ESP8266 core comes with NTP time library already built-in. No need to install or use any other library!

2 Likes

Cool, then actually you only need configTime(). Didn't know that API was implemented like in ESP32.

1 Like