Cloudschedule time mismatch between cloud and app

My issue is that in IoT Remote Cloudschedule time is not matching with what the Android app (V 1.1.3(83)) is sending to cloud. My timezone is Europe/Helsinki in the app. Board is Arduino Nano 33 IoT.

Here is log from Download historic data:
2022-12-17T10:40:13.35Z,{"frm": 1671318000, "to": 0, "len": 3600, "msk": 0}

From here I can see that log is showing times in UTC (2022-12-17T10:40). But the start time in log 1671318000=GMT : Saturday, 17th December 2022, 23.00 is not what it should be. I mean there is now "correct time", but wrong time zone.

See below snip how it looks in app.

image
Edit: So to be more precise: Set Job Starting at: is 23:00 Europe/Helsinki. But command log of what is sent to cloud is GMT 23:00!!!!

And what is really worst is that this time difference seems to be random. Mostly it is 2 hours, but then suddenly it changes to 1 hour and then another day back to 2 hours. So this is driving me crazy since the purpose of this is to start and stop house heating to get it done during low cost hours for electricity.

// Servo - Version: Latest 
#include <Servo.h>

/* 
  Sketch generated by the Arduino IoT Cloud Thing "MLP"
  https://create.arduino.cc/cloud/things/eea042b0-1aad-4253-8e68-ad9f475ceb86 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  int mLPmanualLevel;
  CloudSchedule mLPcontrolTime;
  bool mLPonOff;
  bool mLPonTimer;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"

int servoPin = 9;
int servoMin = 0;
int servoMax = 179;
int servoStatus = 0;

Servo MLPservo;

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 
  
  MLPservo.attach(servoPin);
  MLPservo.write(servoMin);

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  pinMode(LED_BUILTIN, OUTPUT);
  mLPmanualLevel = 0;
  mLPonOff = 0;
  mLPonTimer = 0;
}

void loop() {
  ArduinoCloud.update();
  // Your code here 
  
  Serial.print(mLPonTimer);
  Serial.print("----");
  Serial.println(mLPcontrolTime.isActive());
  delay(1000);
  
  if (mLPonTimer) {
    if (mLPcontrolTime.isActive()) {
     // whenever the job is "active", turn on the LED and servo to max
    digitalWrite(LED_BUILTIN, HIGH);
    servoStatus = servoMax;
    MLPservo.write(servoStatus);
    mLPmanualLevel = servoMax;
}   else {
    // whenever the job is "not active", turn off the LED and servo to min
    digitalWrite(LED_BUILTIN, LOW);
    servoStatus=servoMin;
    MLPservo.write(servoStatus);
    mLPmanualLevel = servoMin;
}

}

}

/*
  Since MLPcontrolManual is READ_WRITE variable, onMLPcontrolManualChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMLPcontrolManualChange()  {
  // Add your code here to act upon MLPcontrolManual change
}

/*
  Since LEDonoff is READ_WRITE variable, onLEDonoffChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onLEDonoffChange()  {
  // Add your code here to act upon LEDonoff change
    digitalWrite(LED_BUILTIN, HIGH);
    delay(5000);
    digitalWrite(LED_BUILTIN, LOW);
  
}

/*
  Since MLPcontrolTime is READ_WRITE variable, onMLPcontrolTimeChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMLPcontrolTimeChange()  {
  // Add your code here to act upon MLPcontrolTime change
  mLPonTimer = 1;
  digitalWrite(LED_BUILTIN, HIGH);
  delay(5000);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.print(mLPonTimer);
  Serial.println("---onMLPcontrolTimeChange triggered");
}


/*
  Since MLPonOfff is READ_WRITE variable, onMLPonOffChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMLPonOffChange()  {
  // Add your code here to act upon MLPonOfff change
   if (mLPonOff) {
    MLPservo.write(mLPmanualLevel);
    mLPonTimer = 0;
    Serial.print(mLPonTimer);
    Serial.println("---onMLPonOffChange triggered on");
} else {
    mLPonTimer = 0;
    MLPservo.write(servoMin);
    mLPmanualLevel = 0;
    Serial.print(mLPonTimer);
    Serial.println("---onMLPonOffChange triggered off and servo to zero");  
}
}

/*
  Since MLPonTimer is READ_WRITE variable, onMLPonTimerChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMLPonTimerChange()  {
  // Add your code here to act upon MLPonTimer change
  if (mLPonTimer) {
    MLPservo.write(servoMin);
    mLPmanualLevel = servoMin;
    mLPonOff = 0;
  }
    Serial.print(mLPonTimer);
    Serial.println("---onMLPonTimerChange triggered");
}

/*
  Since MLPmanualLevel is READ_WRITE variable, onMLPmanualLevelChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMLPmanualLevelChange()  {
  // Add your code here to act upon MLPmanualLevel change
  if (mLPonOff) {
    MLPservo.write(mLPmanualLevel);
    mLPonTimer = 0;
    Serial.print("onMLPmanualLevelChange triggered to a value ");
    Serial.println(mLPmanualLevel);
}   
}

Thanks for the report @hrjones, we are going to check it internally.

Do you experience any issues using the standard web UI? Is it a problem related only to IoT Cloud Remote mobile application?

@hrjones I've double-checked your message, it is correct that you see 23:00 in historical data since we send the time like it is the board timezone.

The board itself calculates its own timezone, and if local time = 23:00 then the schedule should start (so at 21.00 GMT, according to your timezone).

My understanding is that the schedule does not start at 23:00 GMT+2. When does it start?

Hi,
I will do some troubleshooting later today (evening local time). Anyway my feeling is that I have had problems with start time when developing the SW.

Anyway yesterday evening I scheduled a new start around 23:30 EET and set it to start 22:00 in scheduler to get it effectively starting at 00:00 for 8 hours. So I anticipated the two hour difference in actual start. But what happened was that the scheduler started immediately, which indicates that yesterday the time difference was only 1 hour. I need to check from logs, if this is right. But if you can see my logs, then you can probably also see what happened.

So if my original report was that if I schedule to start at 23:00 GMT+2, it will start at GMT+0. But as I mentioned above, so yesterday my impression (I will confirm this later) was that it started GMT+1. And this is really the big pain, since at the moment I have zero trust on scheduler start time.

Edit: I got the log from yesterday evening. According to it schedule start was at
2022-12-20T21:24:28.395Z,{"frm": 1671573600, "to": 0, "len": 28800, "msk": 0}
where unix time converts to:
GMT : Tuesday, December 20, 2022 10:00:00 PM
Your time zone : Wednesday, December 21, 2022 12:00:00 AM [GMT+02:00]

So meaning no randomness here. It behaved logically (with 2 hours difference) wrong. So I have to request it to start at 22:00 to get it starting at 24:00 (or 00:00 next day).

What if the project used a properly setup RTC module for time? That way a dependency of Jims Time and Ricks Time is irrelevant. Instead use your time.

I considered that first also, but the availability for Arduino RTC modules was very bad last spring when I started this project. And the cloud seemed to offer a perfect solution. Also I cloud is handy for setting the timer. And I still have hope that this issue is solvable. There is probably some small glitch between Arduino cloud and operating system or something else, I just need help (thanks @eclipse1985) to solve it.

If using a ESP32 just set the internal RTC in setup().

What may be happening is with each connection to the cloudy thing a connection is made to a server in some country with some time zone. The next connection to the cloudy thingy may not be the same server in the same time zone.

I don't think it is that since I am sending to cloud from app scheduler request wrongly! So cloud does what I request it in the message sent. But why do I request it wrong, that is the question. Since in the app window I have Europe/Helsinki, but still I send "randomly" shifted time requests to cloud.

I initiated test now. Scheduler asked to start at 14:00 Europe/Helsinki 21/12/2022 from Desktop . Request sent 13:23 current local time (EET). I will report when it kicks in.

The mobile app is updated and is showing the same start time. Duration is 8 hours.

Can you please also add

Serial.println(ArduinoCloud.getLocalTime());

to your loop()? So we can check what's the board current time, timezone included.

I will. You will get it by tomorrow. This requires some efforts.

Scheduler set from desktop to start at 14:00 Europe/Helsinki started at 14:00 EET! This is how it should work. So based on this one test, the issue is related to mobile app.

I am running further tests to compare Desk top and Mobile.

Edit 1:
Desk top 14:27 EET -> Scheduler 14:30, Duration 5 -> Worked as expected.
Mobile 14:33 EET -> Scheduler 14:35, Duration 5 -> Not working (time shift 2 hours may be??? Just noting that Desk top is showing this same time 14:35/5, so Desk top and Mobile are synched).

@eclipse1985 Is the getLocalTime still needed?

Edit 2:
14:48 EET Now the scheduler is on!?!?!? It is set to turn on 14:35 for 5 min. So in no way it should be on now.

Edit 3:
14:52 EET Scheduler turned off! So if Duration was right then it turned on 14:47 vs 14:35 (sorry I missed this since I am monitoring the changes from desk top). So we have here 12 min difference.

@eclipse1985 Is the getLocalTime still needed?

Yes, please, we need to check if the board's local time is correct or if there are some time shifts.
Also, what kind of device are you using exactly?

Samsung S21+ 5G (SM-G996B/DS), Android 13.

New test:
Mobile 16:07 EET Scheduler 16:15, 15 min -> turned on 16:29 (so 14 min delay, but not 1 hour or 2 hours as I reported earlier). This makes me doubt my issue reporting details....

I mapped now two earlier tests to logs:

Mobile 14:33 EET -> Scheduler 14:35, Duration 5 -> Scheduler turned on 14:47 (12 min delay)
2022-12-21T12:33:11.49Z,{"frm": 1671633300, "to": 0, "len": 300, "msk": 0}
2022-12-21T12:33:18.504Z,{"frm": 1671633300, "to": 0, "len": 300, "msk": 0}
Unix time converted:
GMT : Wednesday, December 21, 2022 2:35:00 PM
Your time zone : Wednesday, December 21, 2022 4:35:00 PM [GMT+02:00]

Mobile 16:07 EET Scheduler 16:15, 15 min -> turned on 16:29 (14 min delay)
2022-12-21T14:07:50.25Z,{"frm": 1671639300, "to": 0, "len": 900, "msk": 0}
2022-12-21T14:07:57.749Z,{"frm": 1671639300, "to": 0, "len": 900, "msk": 0}
Unix time converted:
GMT : Wednesday, December 21, 2022 4:15:00 PM
Your time zone : Wednesday, December 21, 2022 6:15:00 PM GMT+02:00

So now both tests logs confirm that there is 2 hours difference in requested times sent to cloud compared to mobile app, but then there is "only" 12min and 14 min experienced delays in activation...

@hrjones does resetting the board fix the delay? I suspect the RTC is drifting.

@hrjones as said the 2 hours difference is correct because the Scheduler widget sends time as it is. It's up to the board to decide when that time should apply, according to its timezone.

The thing that is not correct is the 12-14 min drift which may depend on the specific Arduino board you are using. What kind of Arduino board are you using?

Board is Arduino NANO 33 IoT.

I will reset the board when I add the requested line to code. Let see what time it has.

Serial.println(ArduinoCloud.getLocalTime());

Just one thing that I don't see in my code anything that would set board time? I mean my understanding has been that in order for the code to work, I need to be continuously connected to the cloud? And that mLPcontrolTime.isActive() is checking scheduler value from the cloud? So in that way I would not have RTC, at least I would not need it. But I will do now the test with getLocalTime.

0----0---0
0----0---0
0---onMLPonOffChange triggered off and servo to zero
1---onMLPcontrolTimeChange triggered
1---onMLPonTimerChange triggered
1----0---1671653765 (ArduinoCloud.getLocalTime() printed this unix time!!)

Started around 20:18 EET (8:18PM)

GMT : Wednesday, December 21, 2022 8:16:05 PM
Your time zone : Wednesday, December 21, 2022 10:16:05 PM GMT+02:00

So to me looks like board time is GMT time. Two minute difference can be just noting the time wrong from my part.

@eclipse1985 one more comment. Remember my Desk top test. It works perfectly and starts spot on (=less than 1 min difference from expected)

Desk top 14:27 EET -> Scheduler 14:30, Duration 5 -> Worked as expected.
2022-12-21T12:33:11.49Z,{"frm": 1671633300, "to": 0, "len": 300, "msk": 0}
GMT : Wednesday, December 21, 2022 2:30:00 PM
Your time zone : Wednesday, December 21, 2022 4:30:00 PM [GMT+02:00]

Tested now with Desk top after restarting the board and delay was 20 sec. So in practice no delay.

Hmm, now tested with Mobile app and delay was around 36 sec. So @pennam and @eclipse1985 may be you were right that it had to do with board time and resetting board solved the issue.

Is there a way to prevent the board time from drifting? Like synching it from the cloud?

And I still wonder why I earlier had Desk top set up working but Mobile app setting was incorrect? Or was this just an illusion...

I tested today again and looks like the time creep from yesterday (23:38 EET) is 2 min 37 sec! I will check again tomorrow.

Ok, I found this article which says that Arduino clock drifts about 15min per week, which is in the order of magnitude that I saw over one day. This would mean that the cloud scheduler is totally useless unless there is some way to keep the clock synched from the cloud. So I keep looking for it.

https://arduino.stackexchange.com/questions/27/how-do-i-get-an-accurate-time

Hi @hrjones i've digged a little bit more in this issue, and the main reason the RTC of the Nano33IoT is drifting is because the board lacks of the external 32kHz oscillator. Furthermore i'm investigating a possible bad interaction between RTC and Watchdog.

In the meanwhile i've prepared a patch that forces an RTC sync every 24h, this should limit the drift to about 60 seconds. If you want to give it a try you can find the library here:

I think is also a good idea to temporarly disable the watchdog in your sketch, this can be done changing this line ArduinoIoTCloud/ArduinoIoTCloud-Basic.ino at 7dd93ad9bedbd290aed04329c357f9e08702beb0 · arduino-libraries/ArduinoIoTCloud · GitHub

from
ArduinoCloud.begin(ArduinoIoTPreferredConnection);

to
ArduinoCloud.begin(ArduinoIoTPreferredConnection, false);