Time value error during cold boot

Finally, I discover why my code sometime work and sometime behave strangely.
My code is rely on the Time() value from the Core. I understand it base on Core providing the value. So when the Setup() is called, the Time could be incorrect, due to WiFi is not established.
Is this a correct assumption ?
Is this is the case, when I would know Time () is correct ?

Below is the result of my test. I am using HTML to monitor the event

void setup()
{
Time.zone(-4);
Spark.variable("systemState",&systemState, INT); // System STATE
msg = "STATE_INIT-";
msg +=Time.timeStr();
Spark.publish(systemStateEvt, msg);
}

In cold boot - unplug USB power

STATE_INIT-Wed Dec 31 20:00:12 1969

In warm boot - press "reset"

STATE_INIT-Sat Sep 13 17:43:05 2014

Yep when running the setup loop the time probably wont be set… unless its a very long setup! i added a test to see if the unix time was > 1400000 which means we are after the time when i wrote the program so the time must be set. not the prettiest and wont work once time machines are invented

2 Likes

Which SYSTEM_MODE are you using?

I had not change the SYSTEM_MODE. So it should in Auto.
Now, I put in a kind of patch but it works.

void setup()
{
unsigned long t1;

Time.zone(-4);

t1 = millis(); // Get system time in ms
while (Time.year() < 2014) // At least this year
{
SPARK_WLAN_Loop(); // Wait
if ((millis()-t1) > 60000) // for 60 seconds
break;
}

Spark.variable("systemState",&systemState, INT); // System STATE
msg = "STATE_INIT-";
msg +=Time.timeStr();
Spark.publish(systemStateEvt, msg);
}

I will wait up to 60 seconds before I exit the setup. Since my program depends on a correct date-time in order to perform real time schedule. This works most of the time.... reason I said that is, I base on the Spark.publish event that I receive.

What I have discovered during my test cases :

  1. If unplug and plug back (with 1 minute) - Spark event was received during Setup () function
  2. If unplug and wait a while (over few minutes) - Spark event NOT receive during Setup () function

The receiving end is my HTML program running on PC. I had noticed this behavior for a while but until now I notice this pattern. Hope this will help you to debug the problem.

What happens if you call this in setup?

Spark.syncTime();

Had tried but does not work. How could I confirm the Core had established with Cloud when Setup() is called ? I use below code to validate but result even worse, Spark event is not received.

setup()
{
Spark.syncTime(); // sync time to Cloud
Time.zone(-4); // Eastern time
Serial.begin(9600); // UART setup

t1 = millis();                      // Get system time in ms
    IPAddress remoteIP={62,116,130,8};
    while (1)
    {
        if (WiFi.ready()==false)
        {
            SPARK_WLAN_Loop();          // Wait
        }
        else
        {
            i = WiFi.ping(remoteIP);    // TCP OK
            if (i)                      // Yes
            {
                Serial.println("IP available");
                break;                  // Exit the check
            }
        }
        if ((millis()-t1) > 60000)      // Check for 60 seconds max
        {
            Serial.println("Setup Timeout");
            break;                      //
        }
    }
    Serial.println("Setup Continue");
}

Spark.variable("systemState",&systemState, INT); // System STATE
msg = "STATE_INIT-";
msg +=Time.timeStr();
Spark.publish(systemStateEvt, msg);
}

Does Spark.connected() return true even though you are not connected? That would be a bug for sure.

The WiFi.ready() function doesn’t tell you the cloud is ready, just that the TI CC3000 has an address etc. and the cloud has been started (or is off).

1 Like

I change the code to following and Time() will be wrong too

     Spark.connect();

     while (Spark.connected()==false)
    {
        SPARK_WLAN_Loop();              // Wait
        if ((millis()-t1) > 60000)      // Check for 60 seconds max
        {
            Serial.println("Setup Timeout");
            break;                      //
        }
    }

Maybe try something like this?

setup() {
    while (! Time.second() ) {
        SPARK_WLAN_Loop();
    }
}

I feel the core should expose local events for things like cloud connect/disconnect so that user apps can respond to state changes. The same mechanism could be used to announce that time synchronization has occurred, so your app just has to wait for that event.

1 Like

Right on, I believe that is what missing now. Using existing API does not seems to provide sufficient status of the Core connection status to the Cloud. Previously, I had complained about missing event and/or fail to connect TCPClient.
I suspect, this is what had happened.

  1. Spark.publish(event)
  2. TCPClient.connect

This sequence always failed in my code. Now, I put a delay between #1 and #2 or reverse the order, then it is OK.

Even I am using the Spark.connected() to check whether it is connected to Spark Cloud. Still not giving the status whether it had received the Cloud RTC or ready to connect for TCPClient.

In the NTP-based time library that I wrote before Spark. time.now() was available, I have a public flag called “hasSynced” as well as the last sync time “lastNTPTime” for just this type of problem.

Due to the asynchronous nature of cloud start up and requests, a Boolean flag for this seems more appropriate to me since you are likely to just poll until success anyway.

Does Spark code has something like this ? This would do the trick.

OK, I put together a test code to prove the Spark.connected() does not indicate that I could use the TCPClient.
I have to put the delay(5000); otherwise it will failed. Initially I use serial before and it sometimes OK, this is because when u open the terminal, it may pass 5 seconds already.
Also, I disable the last case which use WiFi.Ping, after this is called, all Spark Cloud access will failed. The IP is "spark.io"

Call the function during setup() will able to show the result.

void CloudConnectCheck (void)
{
TCPClient client; // Client
int i;
unsigned long t1;

t1 = millis();                          // Get system time in ms
pinMode(D5, INPUT);                     // D5 - TEST pin
if (digitalRead(D5)==HIGH)
{
    pinMode(D0,OUTPUT);                 // D0
    pinMode(D1,OUTPUT);                 // D1
    pinMode(D2,OUTPUT);                 // D1
    digitalWrite(D0, LOW);              // Turn OFF
    digitalWrite(D1, LOW);              // Turn OFF
    digitalWrite(D2, LOW);              // Turn OFF

#if 1
while (Spark.connected()==false)
{
SPARK_WLAN_Loop(); // Wait
if ((millis()-t1) > 60000) // Check for 60 seconds max
{
digitalWrite(D0, HIGH); // Turn ON
break; //
}
}
#endif
#if 1
if ((millis()-t1) < 60000) // Check for 60 seconds max
{
delay(5000); //***** Without delay does not work
if (client.connect("api.wunderground.com", 80)==true)
digitalWrite(D1, HIGH); // Turn ON - OK
else
digitalWrite(D2, HIGH); // Turn ON

        client.flush();
        client.stop();
    }        

**#endif
#if 0
//
if ((millis()-t1) < 60000) // Check for 60 seconds max
{
IPAddress remoteIP={62,116,130,8};
i = WiFi.ping(remoteIP); // TCP check
if (i) // Yes
digitalWrite(D1, HIGH); // Turn ON - OK
else
digitalWrite(D2, HIGH); // Turn ON
}
#endif
}
}