Time Zones in Inky Frame PicoW micropython

Hi all. I’m using an Inky Frame 5.7" with the PicoW just recently ordered. I’m working on getting the Inky Frame to simply wake up once an hour, fetch an image, display it, and then go back to sleep. As an optimisation, I’m trying not to do any work at all during the wee hours of the morning. No need to update the display between 11pm and 7am. This means I need my Inky Frame to know local time.

My code is in a public repository, here. I assume inky_frame.set_time() sets the clock to GMT. That’s would be logical. I’m calculating timezone simply as -18000 seconds, since that’s my difference (America/New_York time zone). So it seems to me that if tz_seconds = -18000, then this should be a reasonable way to get local time:

year, month, day, hour, minute, second, dow, _ = time.localtime(time.time() + tz_seconds)`

Lines 41-46 of my file display the time at the top of the display.

It seems to me like the difference is USB power versus battery power. When it’s plugged into my laptop (macOS) and I’m running in thonny, I use the green ▶︎ button to run main.py interactively. The time shows up wrong in that case. I run it at 22:15 local time, and the Inky Frame displays 17:15. That’s GMT -10, which is a double correction of what it’s meant to be. When I run on battery power, the time is right. It displays 22:15 on the Inky Frame when it’s 22:15 local time.

I wonder if something about thonny transmits time zone information to the micropython environment on the PicoW, and thus my code in that case is double-correcting the time zone.

Any ideas? It is frustrating to code when the system behaves differently with thonny than it does without.

You wondering is correct; thonny “helpfully” sets the time to the time on your computer.

If you use time.gmtime() instead of time.localtime() you should(*) get, well, the UTC time instead, and then you can safely add your correction to that.

(*) this rather assumes that thonny correctly sets the timezone, which I haven’t personally tested…

1 Like

Yes, Thonny sets the time based on what its set to on the Host device. My main Windows PC, that I do most of my coding on, is set to local time / my time zone. Thats the time that gets set on the Pico I’m coding on from Thonny.

When working with a mcu and you are not living on a small island in the North Sea, you should fetch your time from worldtimeapi.org. They give you your local-time and you don’t need to do the maths yourself. Which will always be wrong half of a year anyhow due to things like DST and things like leap-seconds. And your code will run everywhere in the world without change.

Thanks to both of you. That was what I needed to find the trick. If you go into Thonny’s Interpreter preferences, it has two options:

  • Synchronize device’s real time clock
  • Use local time in real time clock

Since I’m trying to use NTP to set up my clock, and I need it to behave on USB the same way it would behave on battery, I unchecked both of these options. I disconnected the battery and USB so my Inky Frame would lose its mind 😀 and then I re-ran my code from the “play” button in Thonny. It behaved as I expected.

This was super helpful because I found out that I was getting an OSError exception ETIMEDOUT sometimes on the inky_frame.set_time() call. I wasn’t catching that exception and I wasn’t retrying, so things crashed there.

Thanks for pointing me in the right direction!

I appreciate the idea, but using that API makes my solution dependent on that web service. If it is unreachable, unavailable, or if they change their business model and stop offering that API for free, my device doesn’t work. NTP, on the other hand, runs on my local wifi router, so if I want to make my solution totally Internet-optional, I can.

I know that time zones can be complicated, but my situation isn’t. Consider what goes wrong if my calculation is off by an hour: I’m still updating 18 out of 24 hours a day, but maybe my first update is 06:00 or 08:00 instead of 07:00. And my last update is 21:00 or 23:00 instead of 22:00. I don’t care about that error condition more than I care about the battery use to reach out to an Internet-connected HTTPS URL and the fragility that would create in my application.

It’s not a bad suggestion, and if time mattered more here, I’d totally do that. But it doesn’t really matter to me that my device’s sleep interval might be off by an hour. If I’m lucky, the US might get rid of daylight savings time in my lifetime and then I really won’t care.

You wrote about a public repository, so I thought you wanted to create code that will be of interest to people somewhere else in the world (with a different offset).

Your point about worldtimeapi.org is totally valid. They have a free service and it is not very reliable. For that reason I implemented a clone that runs on my local Pi-server: GitHub - bablokb/py-localtime-api: Simplistic Server providing local-time in json-format (replacement for worldtimeapi.org)

I did. It should be usable by lots of people. If my code uses an API (remote or local) to get time converted to the local time zone, the service will guess, based on the person’s IP address, what their local time zone is. The internet, like time zones, is complicated. There are lots of reasons why estimating time zone by IP address will sometimes be wrong. So to use the API I have to write the code that calls an API, and I have to write some manual override options in case the API guesses wrong for a particular person.

Alternatively, I can just force the user to change a line in the config to indicate what time zone they want and invoke the API with a hard-wired time zone. Once I’m down that road, I can also just force them to put the offset in hours from GMT that they want and do simple add/subtract. We’ll be off by an hour half the year, unless they change that line twice a year. It’s just a tradeoff.

Seems to me that the right way to do it is to meet in the middle. Invoke that API once in a while (once a day?) to figure out if DST has kicked in. Record the result on the SD card, and do simple math the rest of the day. Of the 365 times we will do this algorithm every year, only 2 will result in changes. The best would be to calculate the date/time of the next DST change, cache that on the SD, and don’t call the wide-area API at all, unless it’s the right day of the year to do that.

It seems like a lot of code to write for a small thing, but making it automatic might be worth it. I’m glad we had this conversation. I didn’t know about that API.

Yep. To save power, I only turn on the wifi on the pico once in a while to update the secondary RTC. The RTC in the InkyFrames is very good, actually, they should run a whole year with the precision you aim at.

Another tip: you don’t need the SD for caching, the Pico also has non-volatile memory.