vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.95k stars 723 forks source link

getNetworkTime returns 1939 datetime at rare occations #620

Open dlyckelid opened 2 years ago

dlyckelid commented 2 years ago

[X ] I have read the Troubleshooting section of the ReadMe

What type of issues is this?

[ ] Request to support a new module

[ ] Bug or problem compiling the library [ X ] Bug or issue with library functionality (ie, sending data over TCP/IP) [ ] Question or request for help

What are you working with?

Modem: SIMCOM 7080G Main processor board: ESP32 TinyGSM version: 11.1

Scenario, steps to reproduce

I do timesynchronization like this:

int year3 = 0;
int month3 = 0;
int day3 = 0;
int hour3 = 0;
int min3 = 0;
int sec3 = 0;
float timezone = 0;
if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,&timezone))
{
    DateTime currentTime = DateTime(year3, month3, day3, hour3, min3, sec3);
    DebugService::Information("Timezone", String(timezone));
    return currentTime.unixtime() - long(timezone * 3600);
}
return 0;

Expected result

I expect to get the current time adjusted for timezone

Actual result

On rare occations (I have 30+ devices now running 24/7 and this has happend 3 times that I have witnessed) I get a datetime that tells that the TimeZone is 0 (Should be 1) and that the year is 1939. I do timesynchronization every minute and when this happens it is from startup and then every timesync until the modem is restarted. I have only have this happend once on a device that I was connected to and could watch the print out from the device.

Debug and AT command log

I have not been able to reproduce this in a debug environment, it just happends rarely and random.

Does anyone have any idea where this can originate from? Is it my code, the modem, the network or TinyGSM library?

star297 commented 2 years ago

Not really a bug, more characteristic of mobile network.

Try this: I use it to re sync the ESP32 RTC timer once a day. I found some network operators are a but slow to give time so I try every few minutes until successful. But don't call this in rapid succession, if you don't get it straight away, wait several seconds before trying again otherwise the ESP could get upset and reset or the network cell will block you for a while.
I'm using SIM7600 and SIM70xx

int getGSMTIME()
{
  if (ModemDetected) {
    //Serial.printf("GSM Time: %s\n", modem.getGSMDateTime(DATE_FULL).c_str());
    int     GSMyear = 0;
    int     GSMmonth = 0;
    int     GSMdate = 0;
    int     GSMhours = 0;
    int     GSMminutes = 0;
    int     GSMseconds = 0;
    float   GSMtimezone = 0;
    time_t  GSMUTCtime = 0;

    if (modem.getNetworkTime(&GSMyear, &GSMmonth, &GSMdate, &GSMhours, &GSMminutes, &GSMseconds, &GSMtimezone))
    {
      struct tm s;
      s.tm_sec  = (GSMseconds);
      s.tm_min  = (GSMminutes);
      s.tm_hour = (GSMhours);
      s.tm_mday = (GSMdate);
      s.tm_mon  = (GSMmonth - 1);
      s.tm_year = (GSMyear - 1900);
      GSMUTCtime   = mktime(&s);
      if (DEBUG) {
        Serial.printf("GSM Time:    %s",  ctime(&GSMUTCtime));
      }

      if (setSystemTime) {                  //  set system time if requested
        if (GSMUTCtime > 1615155060) {      //  check for valid time, not 1939!
          setenv("TZ", "CET-0CET-0,M3.5.0/02:00:00,M10.5.0/03:00:00", 1);
          tzset();
          struct timeval tv;
          memset(&tv, 0, sizeof(struct timeval));
          tv.tv_sec = GSMUTCtime;
          settimeofday(&tv, NULL);
          setSystemTime = 0;
        }
        return 1;
      }
    }
    return 0;
  }
}
mathieucarbou commented 6 months ago

To work with DST, we have to do a mix between both code and install the time with UTC0 and then switched to the wanted TZ.

example:

    struct tm t = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    float timezone = 0;
    if (_timeState == ModemTimeState::MODEM_TIME_SYNCING && !_modem.getGSMDateTime(TinyGSMDateTimeFormat::DATE_FULL).startsWith("80/01/06") && _modem.getNetworkTime(&t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &timezone)) {
      // +CCLK: "24/04/02,13:39:57+08 (dst, gmt+1, so 11:39 gmt)
      t.tm_year -= 1900;
      t.tm_mon -= 1;

      Mycila::Logger.debug(TAG, "t.tm_year: %d", t.tm_year);
      Mycila::Logger.debug(TAG, "t.tm_mon: %d", t.tm_mon);
      Mycila::Logger.debug(TAG, "t.tm_mday: %d", t.tm_mday);
      Mycila::Logger.debug(TAG, "t.tm_hour: %d", t.tm_hour);
      Mycila::Logger.debug(TAG, "t.tm_min: %d", t.tm_min);
      Mycila::Logger.debug(TAG, "t.tm_sec: %d", t.tm_sec);

      // unix time
      struct timeval now = {mktime(&t) - static_cast<int>(timezone * 3600.0), 0};
      Mycila::Logger.debug(TAG, "now.tv_sec: %d", now.tv_sec);

      // install the time
      setenv("TZ", "UTC0", 1);
      tzset();
      settimeofday(&now, nullptr);

      // change timezone
      setenv("TZ", _timeZoneInfo.c_str(), 1);
      tzset();

      Mycila::Logger.info(TAG, "getLocalStr(): %s", Mycila::Time::getLocalStr().c_str());
      Mycila::Logger.info(TAG, "getISO8601Str(): %s", Mycila::Time::getISO8601Str().c_str());
      Mycila::Logger.info(TAG, "getUnixTime(): %d", Mycila::Time::getUnixTime());
      if (!Mycila::Time::getLocalStr().isEmpty()) {
        _timeState = ModemTimeState::MODEM_TIME_SYNCED;
        _state = MODEM_READY;
      }
    }

output:

D        12266 modemTask  (1) MODEM      >> AT+CCLK?
D        12272 modemTask  (1) MODEM      << 
D        12273 modemTask  (1) MODEM      << +CCLK: "24/04/02,15:19:20+08"
D        12274 modemTask  (1) MODEM      << 
D        12275 modemTask  (1) MODEM      << OK
D        12275 modemTask  (1) MODEM      t.tm_year: 124
D        12276 modemTask  (1) MODEM      t.tm_mon: 3
D        12277 modemTask  (1) MODEM      t.tm_mday: 2
D        12277 modemTask  (1) MODEM      t.tm_hour: 15
D        12277 modemTask  (1) MODEM      t.tm_min: 19
D        12277 modemTask  (1) MODEM      t.tm_sec: 20
D        12277 modemTask  (1) MODEM      now.tv_sec: 1712063960
I        12278 modemTask  (1) MODEM      getLocalStr(): 2024-04-02 15:19:20
I        12279 modemTask  (1) MODEM      getISO8601Str(): 2024-04-02T13:19:20Z
I        12281 modemTask  (1) MODEM      getUnixTime(): 1712063960
star297 commented 6 months ago

We found GSM time would vary between site locations and operators. Some would be UTC0, others would be local time of the tower location. Gave up and used GPS as that's always UTC0 everywhere.

mathieucarbou commented 6 months ago

We found GSM time would vary between site locations and operators

I just ran into this issue 😒

Decezaris commented 4 months ago

I am using SIMCOM A7670SA and I think there is not a pattern of error codes... if you get the AT commands of this module, you can see in the table the error code and descriptions (for this module the method ShowNTPError() does not make sense). As solution before get the date you can do:

while (modem.NTPServerSync("pool.ntp.org", 0) != 0) {
    Serial.println("Try to sync ntp")
}

const char* dt = modem.getGSMDateTime(DATE_FULL).c_str();

image