From 2dfeb381e43eba59bd44285dafe29ab2020dbbd3 Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Wed, 2 Jul 2025 12:43:01 +0200 Subject: [PATCH] Add timezone setting --- .../assets/imageview.py | 1 - .../assets/settings.py | 22 +- internal_filesystem/lib/localPTZtime.py | 319 ++++++++++++ internal_filesystem/lib/mpos/info.py | 2 +- internal_filesystem/lib/mpos/time.py | 48 +- internal_filesystem/lib/mpos/timezones.py | 465 ++++++++++++++++++ internal_filesystem/lib/mpos/ui/__init__.py | 7 +- 7 files changed, 856 insertions(+), 8 deletions(-) create mode 100644 internal_filesystem/lib/localPTZtime.py create mode 100644 internal_filesystem/lib/mpos/timezones.py diff --git a/internal_filesystem/apps/com.micropythonos.imageview/assets/imageview.py b/internal_filesystem/apps/com.micropythonos.imageview/assets/imageview.py index 5f286d63..f269c0b2 100644 --- a/internal_filesystem/apps/com.micropythonos.imageview/assets/imageview.py +++ b/internal_filesystem/apps/com.micropythonos.imageview/assets/imageview.py @@ -1,6 +1,5 @@ import gc import os -import time from mpos.apps import Activity import mpos.ui diff --git a/internal_filesystem/builtin/apps/com.micropythonos.settings/assets/settings.py b/internal_filesystem/builtin/apps/com.micropythonos.settings/assets/settings.py index f840b4cf..960053c1 100644 --- a/internal_filesystem/builtin/apps/com.micropythonos.settings/assets/settings.py +++ b/internal_filesystem/builtin/apps/com.micropythonos.settings/assets/settings.py @@ -2,6 +2,7 @@ from mpos.apps import Activity, ActivityNavigator, Intent import mpos.config import mpos.ui +import mpos.time # Used to list and edit all settings: class SettingsActivity(Activity): @@ -37,10 +38,10 @@ class SettingsActivity(Activity): {"title": "Light/Dark Theme", "key": "theme_light_dark", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Light", "light"), ("Dark", "dark")]}, {"title": "Theme Color", "key": "theme_primary_color", "value_label": None, "cont": None, "placeholder": "HTML hex color, like: EC048C", "ui": "dropdown", "ui_options": theme_colors}, {"title": "Restart to Bootloader", "key": "boot_mode", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Normal", "normal"), ("Bootloader", "bootloader")]}, # special that doesn't get saved + {"title": "Timezone", "key": "timezone", "value_label": None, "cont": None, "ui": "dropdown", "ui_options": self.get_timezone_tuples(), "changed_callback": lambda : mpos.time.refresh_timezone_preference()}, # This is currently only in the drawer but would make sense to have it here for completeness: #{"title": "Display Brightness", "key": "display_brightness", "value_label": None, "cont": None, "placeholder": "A value from 0 to 100."}, # Maybe also add font size (but ideally then all fonts should scale up/down) - #{"title": "Timezone", "key": "timezone", "value_label": None, "cont": None, "placeholder": "Example: Europe/Prague"}, ] def onCreate(self): @@ -59,6 +60,7 @@ class SettingsActivity(Activity): # Create settings entries screen.clean() for setting in self.settings: + #print(f"setting {setting.get('title')} has changed_callback {setting.get('changed_callback')}") # Container for each setting setting_cont = lv.obj(screen) setting_cont.set_width(lv.pct(100)) @@ -91,6 +93,10 @@ class SettingsActivity(Activity): intent.putExtra("setting", setting) self.startActivity(intent) + @staticmethod + def get_timezone_tuples(): + return [(tz, tz) for tz in mpos.time.get_timezones()] + # Used to edit one setting: class SettingActivity(Activity): @@ -109,6 +115,7 @@ class SettingActivity(Activity): def onCreate(self): setting = self.getIntent().extras.get("setting") + #print(f"onCreate changed_callback: {setting.get('changed_callback')}") settings_screen_detail = lv.obj() settings_screen_detail.set_style_pad_all(mpos.ui.pct_of_display_width(2), 0) settings_screen_detail.set_flex_flow(lv.FLEX_FLOW.COLUMN) @@ -146,7 +153,12 @@ class SettingActivity(Activity): elif ui and ui == "dropdown" and ui_options: self.dropdown = lv.dropdown(settings_screen_detail) self.dropdown.set_width(lv.pct(100)) - options_with_newlines = "\n".join(f"{option[0]} ({option[1]})" for option in ui_options) + options_with_newlines = "" + for option in ui_options: + if option[0] != option[1]: + options_with_newlines += (f"{option[0]} ({option[1]})\n") + else: # don't show identical options + options_with_newlines += (f"{option[0]}\n") self.dropdown.set_options(options_with_newlines) # select the right one: for i, (option_text, option_value) in enumerate(ui_options): @@ -282,8 +294,14 @@ class SettingActivity(Activity): new_value = self.textarea.get_text() else: new_value = "" + old_value = self.prefs.get_string(setting["key"]) editor = self.prefs.edit() editor.put_string(setting["key"], new_value) editor.commit() setting["value_label"].set_text(new_value if new_value else "(not set)") + changed_callback = setting.get("changed_callback") + #print(f"changed_callback: {changed_callback}") + if changed_callback and old_value != new_value: + print(f"Setting {setting['key']} changed from {old_value} to {new_value}, calling changed_callback...") + changed_callback() self.finish() diff --git a/internal_filesystem/lib/localPTZtime.py b/internal_filesystem/lib/localPTZtime.py new file mode 100644 index 00000000..5a701884 --- /dev/null +++ b/internal_filesystem/lib/localPTZtime.py @@ -0,0 +1,319 @@ +#! /usr/bin/env python3 +""" + Method to convert time - in seconds passed since Unix epoch - from GMT time zone to given time zone expressed in Posix Time Zone format. + + :author: Roberto Bellingeri + :copyright: Copyright 2023 - NetGuru + :license: GPL +""" + +""" + Changelog: + + 0.0.1 + initial release + 0.0.2 + changed returned format + 0.0.3 + fixed bug in leap year calculation +""" + +__version__ = "0.0.3" + + +import time +import re + +def checkptz(ptz_string: str): + """ + Check if the format of the string complies with what is described here: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + Only for testing purposes: on MicroPython always return 'None'. + + Parameters: + ptz_string (str): String in Posix Time Zone format + + Returns: + bool: Test result + """ + ptz_string = _normalize(ptz_string) + + result = None + + if hasattr(re, 'fullmatch'): # re.fullmatch() is not defined in MicroPython + check_re = r"^" + check_re += r"[^:\d+-]{3,}" # std name + check_re += r"[+-]?\d{1,2}(?::\d{1,2}){0,2}" # std offset + + check_re += r"(?:" # dst zone begin + check_re += r"[^:\d+-,]{3,}" # dst name + check_re += r"(?:" # dst offset begin + check_re += r"(?:[+-]?\d{1,2}(?::\d{1,2}){0,2})?" # dst offset time, can be omitted + check_re += r"(?:,(?:J\d{1,3}|\d{1,3}|M(?:[1-9]|1[0-2])\.[1-5]\.[0-6])(?:\/\d{1,2}(?::\d{1,2}){0,2})?){2}" #dst start/end date - time can be omitted + check_re += r")" # dst offset end + check_re += r")?" # dst zone finish, can be omitted + + check_re += r"$" + + #print(check_re) + + if (re.fullmatch(check_re,ptz_string) == None): # type: ignore + result = False + else: + result = True + + return result + + +def tztime(timestamp: float, ptz_string: str): + """ + Converts a time expressed in seconds in struct_time style 9-tuple according to the time zone provided in Posix Time Zone format + + Parameters: + timestamp (float): Time in second + ptz_string (str): Time zone in Posix format + + Returns: + struct_time style tuple: + * ``year`` + * ``month`` + * ``mday`` + * ``hour`` + * ``minute`` + * ``second`` + * ``weekday`` + * ``yearday`` + * ``isdst`` + """ + return _timecalc(timestamp, ptz_string)[:9] + + +def tziso(timestamp: float, ptz_string: str, zone_designator = True): + """ + Return an ISO 8601 date and time string according to the time zone provided in Posix Time Zone format + + Parameters: + timestamp (float): Time in second + ptz_string (str): Time Zone in Posix format + zone_designator (bool): Insert zone designator in returned string - default: True + + Returns: + string: ISO 8601 date and time string + """ + tx = _timecalc(timestamp, ptz_string) + + stx = f"{tx[0]}-{tx[1]:02d}-{tx[2]:02d}T{tx[3]:02d}:{tx[4]:02d}:{tx[5]:02d}" + if (zone_designator == True): + if (tx[9] != 0): + stx += f"{(tx[9] // 3600):+03d}" + + mins = abs(tx[9]) % 3600 + if (mins != 0): + stx += ":" + f"{(mins // 60):02d}" + else: + stx += "Z" + + return stx + + +def _timecalc(timestamp: float, ptz_string: str): + """ + Converts a time expressed in seconds in 10-tuple according to the time zone provided in Posix Time Zone format + + Parameters: + timestamp (float): Time in second + ptz_string (str): Time zone in Posix format + zone_designator (bool): Insert zone designator in returned string - default: True + + Returns: + tuple: + * ``year`` + * ``month`` + * ``mday`` + * ``hour`` + * ``minute`` + * ``second`` + * ``weekday`` + * ``yearday`` + * ``isdst`` + * ``utcoffset`` + """ + ptz_string = _normalize(ptz_string) + + std_offset_seconds = 0 + dst_offset_seconds = 0 + tot_offset_seconds = 0 + is_dst = False + + ptz_parts = ptz_string.split(",") + + #offsetHours = re.split(r"[^\d\+\-\:]+", ptz_parts[0]) + offsetHours = re.compile(r"[^\d\+\-\:]+").split(ptz_parts[0]) # re.compile() is used for MicroPython compatibility + offsetHours = list(filter(None, offsetHours)) + #print(offsetHours) + + if (len(offsetHours) > 0): + + std_offset_seconds = - _hours2secs(offsetHours[0]) + + if (len(offsetHours)>1): + dst_offset_seconds = _hours2secs(offsetHours[1]) + else: + dst_offset_seconds = 3600 + + #print("timestamp:\t" + str(int(timestamp))) + + if (len(ptz_parts)==3): + year = time.gmtime(int(timestamp))[0] + dst_start = _parseposixtransition(ptz_parts[1], year) + dst_end = _parseposixtransition(ptz_parts[2], year) + + if (dst_start < dst_end): #northern hemisphere + if ((timestamp + std_offset_seconds) < dst_start): + is_dst = False + tot_offset_seconds = std_offset_seconds + elif ((timestamp + std_offset_seconds + dst_offset_seconds) < dst_end): + is_dst = True + tot_offset_seconds = std_offset_seconds + dst_offset_seconds + else: + is_dst = False + tot_offset_seconds = std_offset_seconds + else: # southern hemisphere + if ((timestamp + std_offset_seconds + dst_offset_seconds) < dst_end): + is_dst = True + tot_offset_seconds = std_offset_seconds + dst_offset_seconds + elif ((timestamp + std_offset_seconds) < dst_start): + is_dst = False + tot_offset_seconds = std_offset_seconds + else: + is_dst = True + tot_offset_seconds = std_offset_seconds + dst_offset_seconds + + #print("dstOffset:\t" + str(dst_offset_seconds)) + #print("dstStart:\t" + str(dst_start) + "\t" + str(time.gmtime(dst_start))) + #print("dstEnd: \t" + str(dst_end) + "\t" + str(time.gmtime(dst_end))) + + else: + tot_offset_seconds = std_offset_seconds + + timemod = timestamp + tot_offset_seconds + + t = time.gmtime(int(timemod)) + + tx = (t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], int(is_dst), tot_offset_seconds) + + return tx + + +def _normalize(ptz_string: str): + """ + Return simple normalization of PTZ string + + Parameters: + ptz_string (str): PTZ string + + Returns: + str: Normalized PTZ string + """ + ptz_string = ptz_string.upper() + ptz_string = re.compile(r"\<[^\>]*\>").sub("DUMMY",ptz_string) # For what appear to be non-standard strings like "<+11>-11<+12>,M10.1.0,M4.1.0/3" + + return ptz_string + + +def _parseposixtransition(transition: str, year: int): + """ + Returns the moment of the transition from std to dst and vice-versa + + Parameters: + transition (str): Part of Posix Time Zone string related to the transition + year (int): The year + + Returns: + float: Time adjusted + """ + parts = transition.split('/') + seconds = 0 + tr = 0 + + if (len(parts) == 2): + seconds = _hours2secs(parts[1]) + + else: + seconds = 2 * 3600 + + + if (transition[0] == "M"): + # 'Mm.n.d' format. + + date_parts = parts[0][1:].split('.') + if (len(date_parts)==3): + month = int(date_parts[0]) # month from '1' to '12' + week_of_month = int(date_parts[1]) # week number from '1' to '5'. '5' always the last. + day_of_week = int(date_parts[2]) # day of week - 0:Sunday 1:Monday 2:Tuesday 3:Wednesday 4:Thursday 5:Friday 6:Saturday + + base_year = 1970 + base_year_1st_day = 4 # the first day of the year 1970 was Thursday + + month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + if ((((year % 4) == 0) and ((year % 100) != 0)) or (year % 400) == 0): + month_days[1] = 29 + + # calculate the number of days since 1/1/base_year + days_since_base_date = (year - base_year) * 365 + + for y in range(base_year, year): + if ((((y % 4) == 0) and ((y % 100) != 0)) or (y % 400) == 0): + days_since_base_date += 1 + + days_since_base_date += sum(month_days[:month - 1]) + + # calculate the day of the week for the first day of month + first_day_of_month = (days_since_base_date + base_year_1st_day) % 7 + + # calculate the day of the month + day_of_month = 1 + (week_of_month - 1) * 7 + (day_of_week - first_day_of_month) % 7 + + if day_of_month > month_days[month - 1]: + day_of_month -= 7 + + tr = time.mktime((year, month, day_of_month, 0, 0, 0, 0, 0, 0)) + + elif (transition[0] == "J"): + # 'Jn' format. Counting from 1 to 365, and February 29 is never counted. + + day_num = int(parts[0][1:]) + if (((((year % 4) == 0) and ((year % 100) != 0)) or (year % 400) == 0) and (day_num > (31 + 28))): # after February 28 in leap years + day_num += 1 + tr = time.mktime((year,1,1,0,0,0,0,0,0)) + ((day_num - 1) * 86400) + + else: + # 'n' format. Counting from zero to 364, or to 365 in leap years. + + day_num = int(parts[0]) + tr = time.mktime((year,1,1,0,0,0,0,0,0)) + (day_num * 86400) + + return tr + seconds + + +def _hours2secs(hours: str): + """ + Convert hours string in seconds + + Parameters: + hours (str): Hours in format 00[:00][:00] + + Returns: + int: seconds + """ + seconds = 0 + + hours_parts = hours.split(':') + + if (len(hours_parts)>0): + seconds = int(hours_parts[0]) * 3600 + if (len(hours_parts)>1): + seconds += int(hours_parts[1]) * 60 + if (len(hours_parts)>2): + seconds += int(hours_parts[2]) + + return seconds diff --git a/internal_filesystem/lib/mpos/info.py b/internal_filesystem/lib/mpos/info.py index 1a18bce9..453a3d5e 100644 --- a/internal_filesystem/lib/mpos/info.py +++ b/internal_filesystem/lib/mpos/info.py @@ -1 +1 @@ -CURRENT_OS_VERSION = "0.0.8" +CURRENT_OS_VERSION = "0.0.9" diff --git a/internal_filesystem/lib/mpos/time.py b/internal_filesystem/lib/mpos/time.py index 24a7c016..6b385b2e 100644 --- a/internal_filesystem/lib/mpos/time.py +++ b/internal_filesystem/lib/mpos/time.py @@ -1,4 +1,10 @@ import time +import mpos.config +from mpos.timezones import TIMEZONE_MAP + +import localPTZtime + +timezone_preference = None def epoch_seconds(): import sys @@ -16,6 +22,46 @@ def sync_time(): try: print('Syncing time with', ntptime.host) ntptime.settime() # Fetch and set time (in UTC) - print('Time synced successfully') + print("Time sync'ed successfully") + refresh_timezone_preference() # if the time was sync'ed, then it needs refreshing except Exception as e: print('Failed to sync time:', e) + +def refresh_timezone_preference(): + global timezone_preference + prefs = mpos.config.SharedPreferences("com.micropythonos.settings") + timezone_preference = prefs.get_string("timezone") + if not timezone_preference: + timezone_preference = "Etc/GMT" # Use a default value so that it doesn't refresh every time the time is requested + +def localtime(): + global timezone_preference + if not timezone_preference: # if it's the first time, then it needs refreshing + refresh_timezone_preference() + ptz = timezone_to_posix_time_zone(timezone_preference) + t = time.time() + return localPTZtime.tztime(t, ptz) + +def timezone_to_posix_time_zone(timezone): + """ + Convert a timezone name to its POSIX timezone string. + + Args: + timezone (str or None): Timezone name (e.g., 'Africa/Abidjan') or None. + + Returns: + str: POSIX timezone string (e.g., 'GMT0'). Returns 'GMT0' if timezone is None or not found. + """ + if timezone is None or timezone not in TIMEZONE_MAP: + return "GMT0" + return TIMEZONE_MAP[timezone] + +def get_timezones(): + """ + Get a list of all available timezone names. + + Returns: + list: List of timezone names (e.g., ['Africa/Abidjan', 'Africa/Accra', ...]). + """ + return sorted(TIMEZONE_MAP.keys()) # even though they are defined alphabetical, the order isn't maintained in MicroPython + diff --git a/internal_filesystem/lib/mpos/timezones.py b/internal_filesystem/lib/mpos/timezones.py new file mode 100644 index 00000000..57191a40 --- /dev/null +++ b/internal_filesystem/lib/mpos/timezones.py @@ -0,0 +1,465 @@ +# Converted from zones.csv using csv_to_py.py + +TIMEZONE_MAP = { + "Africa/Abidjan": "GMT0", + "Africa/Accra": "GMT0", + "Africa/Addis_Ababa": "EAT-3", + "Africa/Algiers": "CET-1", + "Africa/Asmara": "EAT-3", + "Africa/Bamako": "GMT0", + "Africa/Bangui": "WAT-1", + "Africa/Banjul": "GMT0", + "Africa/Bissau": "GMT0", + "Africa/Blantyre": "CAT-2", + "Africa/Brazzaville": "WAT-1", + "Africa/Bujumbura": "CAT-2", + "Africa/Cairo": "EET-2EEST,M4.5.5/0,M10.5.4/24", + "Africa/Casablanca": "<+01>-1", + "Africa/Ceuta": "CET-1CEST,M3.5.0,M10.5.0/3", + "Africa/Conakry": "GMT0", + "Africa/Dakar": "GMT0", + "Africa/Dar_es_Salaam": "EAT-3", + "Africa/Djibouti": "EAT-3", + "Africa/Douala": "WAT-1", + "Africa/El_Aaiun": "<+01>-1", + "Africa/Freetown": "GMT0", + "Africa/Gaborone": "CAT-2", + "Africa/Harare": "CAT-2", + "Africa/Johannesburg": "SAST-2", + "Africa/Juba": "CAT-2", + "Africa/Kampala": "EAT-3", + "Africa/Khartoum": "CAT-2", + "Africa/Kigali": "CAT-2", + "Africa/Kinshasa": "WAT-1", + "Africa/Lagos": "WAT-1", + "Africa/Libreville": "WAT-1", + "Africa/Lome": "GMT0", + "Africa/Luanda": "WAT-1", + "Africa/Lubumbashi": "CAT-2", + "Africa/Lusaka": "CAT-2", + "Africa/Malabo": "WAT-1", + "Africa/Maputo": "CAT-2", + "Africa/Maseru": "SAST-2", + "Africa/Mbabane": "SAST-2", + "Africa/Mogadishu": "EAT-3", + "Africa/Monrovia": "GMT0", + "Africa/Nairobi": "EAT-3", + "Africa/Ndjamena": "WAT-1", + "Africa/Niamey": "WAT-1", + "Africa/Nouakchott": "GMT0", + "Africa/Ouagadougou": "GMT0", + "Africa/Porto-Novo": "WAT-1", + "Africa/Sao_Tome": "GMT0", + "Africa/Tripoli": "EET-2", + "Africa/Tunis": "CET-1", + "Africa/Windhoek": "CAT-2", + "America/Adak": "HST10HDT,M3.2.0,M11.1.0", + "America/Anchorage": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Anguilla": "AST4", + "America/Antigua": "AST4", + "America/Araguaina": "<-03>3", + "America/Argentina/Buenos_Aires": "<-03>3", + "America/Argentina/Catamarca": "<-03>3", + "America/Argentina/Cordoba": "<-03>3", + "America/Argentina/Jujuy": "<-03>3", + "America/Argentina/La_Rioja": "<-03>3", + "America/Argentina/Mendoza": "<-03>3", + "America/Argentina/Rio_Gallegos": "<-03>3", + "America/Argentina/Salta": "<-03>3", + "America/Argentina/San_Juan": "<-03>3", + "America/Argentina/San_Luis": "<-03>3", + "America/Argentina/Tucuman": "<-03>3", + "America/Argentina/Ushuaia": "<-03>3", + "America/Aruba": "AST4", + "America/Asuncion": "<-04>4<-03>,M10.1.0/0,M3.4.0/0", + "America/Atikokan": "EST5", + "America/Bahia": "<-03>3", + "America/Bahia_Banderas": "CST6", + "America/Barbados": "AST4", + "America/Belem": "<-03>3", + "America/Belize": "CST6", + "America/Blanc-Sablon": "AST4", + "America/Boa_Vista": "<-04>4", + "America/Bogota": "<-05>5", + "America/Boise": "MST7MDT,M3.2.0,M11.1.0", + "America/Cambridge_Bay": "MST7MDT,M3.2.0,M11.1.0", + "America/Campo_Grande": "<-04>4", + "America/Cancun": "EST5", + "America/Caracas": "<-04>4", + "America/Cayenne": "<-03>3", + "America/Cayman": "EST5", + "America/Chicago": "CST6CDT,M3.2.0,M11.1.0", + "America/Chihuahua": "CST6", + "America/Costa_Rica": "CST6", + "America/Creston": "MST7", + "America/Cuiaba": "<-04>4", + "America/Curacao": "AST4", + "America/Danmarkshavn": "GMT0", + "America/Dawson": "MST7", + "America/Dawson_Creek": "MST7", + "America/Denver": "MST7MDT,M3.2.0,M11.1.0", + "America/Detroit": "EST5EDT,M3.2.0,M11.1.0", + "America/Dominica": "AST4", + "America/Edmonton": "MST7MDT,M3.2.0,M11.1.0", + "America/Eirunepe": "<-05>5", + "America/El_Salvador": "CST6", + "America/Fortaleza": "<-03>3", + "America/Fort_Nelson": "MST7", + "America/Glace_Bay": "AST4ADT,M3.2.0,M11.1.0", + "America/Godthab": "<-02>2<-01>,M3.5.0/-1,M10.5.0/0", + "America/Goose_Bay": "AST4ADT,M3.2.0,M11.1.0", + "America/Grand_Turk": "EST5EDT,M3.2.0,M11.1.0", + "America/Grenada": "AST4", + "America/Guadeloupe": "AST4", + "America/Guatemala": "CST6", + "America/Guayaquil": "<-05>5", + "America/Guyana": "<-04>4", + "America/Halifax": "AST4ADT,M3.2.0,M11.1.0", + "America/Havana": "CST5CDT,M3.2.0/0,M11.1.0/1", + "America/Hermosillo": "MST7", + "America/Indiana/Indianapolis": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Knox": "CST6CDT,M3.2.0,M11.1.0", + "America/Indiana/Marengo": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Petersburg": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Tell_City": "CST6CDT,M3.2.0,M11.1.0", + "America/Indiana/Vevay": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Vincennes": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Winamac": "EST5EDT,M3.2.0,M11.1.0", + "America/Inuvik": "MST7MDT,M3.2.0,M11.1.0", + "America/Iqaluit": "EST5EDT,M3.2.0,M11.1.0", + "America/Jamaica": "EST5", + "America/Juneau": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Kentucky/Louisville": "EST5EDT,M3.2.0,M11.1.0", + "America/Kentucky/Monticello": "EST5EDT,M3.2.0,M11.1.0", + "America/Kralendijk": "AST4", + "America/La_Paz": "<-04>4", + "America/Lima": "<-05>5", + "America/Los_Angeles": "PST8PDT,M3.2.0,M11.1.0", + "America/Lower_Princes": "AST4", + "America/Maceio": "<-03>3", + "America/Managua": "CST6", + "America/Manaus": "<-04>4", + "America/Marigot": "AST4", + "America/Martinique": "AST4", + "America/Matamoros": "CST6CDT,M3.2.0,M11.1.0", + "America/Mazatlan": "MST7", + "America/Menominee": "CST6CDT,M3.2.0,M11.1.0", + "America/Merida": "CST6", + "America/Metlakatla": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Mexico_City": "CST6", + "America/Miquelon": "<-03>3<-02>,M3.2.0,M11.1.0", + "America/Moncton": "AST4ADT,M3.2.0,M11.1.0", + "America/Monterrey": "CST6", + "America/Montevideo": "<-03>3", + "America/Montreal": "EST5EDT,M3.2.0,M11.1.0", + "America/Montserrat": "AST4", + "America/Nassau": "EST5EDT,M3.2.0,M11.1.0", + "America/New_York": "EST5EDT,M3.2.0,M11.1.0", + "America/Nipigon": "EST5EDT,M3.2.0,M11.1.0", + "America/Nome": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Noronha": "<-02>2", + "America/North_Dakota/Beulah": "CST6CDT,M3.2.0,M11.1.0", + "America/North_Dakota/Center": "CST6CDT,M3.2.0,M11.1.0", + "America/North_Dakota/New_Salem": "CST6CDT,M3.2.0,M11.1.0", + "America/Nuuk": "<-02>2<-01>,M3.5.0/-1,M10.5.0/0", + "America/Ojinaga": "CST6CDT,M3.2.0,M11.1.0", + "America/Panama": "EST5", + "America/Pangnirtung": "EST5EDT,M3.2.0,M11.1.0", + "America/Paramaribo": "<-03>3", + "America/Phoenix": "MST7", + "America/Port-au-Prince": "EST5EDT,M3.2.0,M11.1.0", + "America/Port_of_Spain": "AST4", + "America/Porto_Velho": "<-04>4", + "America/Puerto_Rico": "AST4", + "America/Punta_Arenas": "<-03>3", + "America/Rainy_River": "CST6CDT,M3.2.0,M11.1.0", + "America/Rankin_Inlet": "CST6CDT,M3.2.0,M11.1.0", + "America/Recife": "<-03>3", + "America/Regina": "CST6", + "America/Resolute": "CST6CDT,M3.2.0,M11.1.0", + "America/Rio_Branco": "<-05>5", + "America/Santarem": "<-03>3", + "America/Santiago": "<-04>4<-03>,M9.1.6/24,M4.1.6/24", + "America/Santo_Domingo": "AST4", + "America/Sao_Paulo": "<-03>3", + "America/Scoresbysund": "<-02>2<-01>,M3.5.0/-1,M10.5.0/0", + "America/Sitka": "AKST9AKDT,M3.2.0,M11.1.0", + "America/St_Barthelemy": "AST4", + "America/St_Johns": "NST3:30NDT,M3.2.0,M11.1.0", + "America/St_Kitts": "AST4", + "America/St_Lucia": "AST4", + "America/St_Thomas": "AST4", + "America/St_Vincent": "AST4", + "America/Swift_Current": "CST6", + "America/Tegucigalpa": "CST6", + "America/Thule": "AST4ADT,M3.2.0,M11.1.0", + "America/Thunder_Bay": "EST5EDT,M3.2.0,M11.1.0", + "America/Tijuana": "PST8PDT,M3.2.0,M11.1.0", + "America/Toronto": "EST5EDT,M3.2.0,M11.1.0", + "America/Tortola": "AST4", + "America/Vancouver": "PST8PDT,M3.2.0,M11.1.0", + "America/Whitehorse": "MST7", + "America/Winnipeg": "CST6CDT,M3.2.0,M11.1.0", + "America/Yakutat": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Yellowknife": "MST7MDT,M3.2.0,M11.1.0", + "Antarctica/Casey": "<+08>-8", + "Antarctica/Davis": "<+07>-7", + "Antarctica/DumontDUrville": "<+10>-10", + "Antarctica/Macquarie": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Antarctica/Mawson": "<+05>-5", + "Antarctica/McMurdo": "NZST-12NZDT,M9.5.0,M4.1.0/3", + "Antarctica/Palmer": "<-03>3", + "Antarctica/Rothera": "<-03>3", + "Antarctica/Syowa": "<+03>-3", + "Antarctica/Troll": "<+00>0<+02>-2,M3.5.0/1,M10.5.0/3", + "Antarctica/Vostok": "<+05>-5", + "Arctic/Longyearbyen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Asia/Aden": "<+03>-3", + "Asia/Almaty": "<+05>-5", + "Asia/Amman": "<+03>-3", + "Asia/Anadyr": "<+12>-12", + "Asia/Aqtau": "<+05>-5", + "Asia/Aqtobe": "<+05>-5", + "Asia/Ashgabat": "<+05>-5", + "Asia/Atyrau": "<+05>-5", + "Asia/Baghdad": "<+03>-3", + "Asia/Bahrain": "<+03>-3", + "Asia/Baku": "<+04>-4", + "Asia/Bangkok": "<+07>-7", + "Asia/Barnaul": "<+07>-7", + "Asia/Beirut": "EET-2EEST,M3.5.0/0,M10.5.0/0", + "Asia/Bishkek": "<+06>-6", + "Asia/Brunei": "<+08>-8", + "Asia/Chita": "<+09>-9", + "Asia/Choibalsan": "<+08>-8", + "Asia/Colombo": "<+0530>-5:30", + "Asia/Damascus": "<+03>-3", + "Asia/Dhaka": "<+06>-6", + "Asia/Dili": "<+09>-9", + "Asia/Dubai": "<+04>-4", + "Asia/Dushanbe": "<+05>-5", + "Asia/Famagusta": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Asia/Gaza": "EET-2EEST,M3.4.4/50,M10.4.4/50", + "Asia/Hebron": "EET-2EEST,M3.4.4/50,M10.4.4/50", + "Asia/Ho_Chi_Minh": "<+07>-7", + "Asia/Hong_Kong": "HKT-8", + "Asia/Hovd": "<+07>-7", + "Asia/Irkutsk": "<+08>-8", + "Asia/Jakarta": "WIB-7", + "Asia/Jayapura": "WIT-9", + "Asia/Jerusalem": "IST-2IDT,M3.4.4/26,M10.5.0", + "Asia/Kabul": "<+0430>-4:30", + "Asia/Kamchatka": "<+12>-12", + "Asia/Karachi": "PKT-5", + "Asia/Kathmandu": "<+0545>-5:45", + "Asia/Khandyga": "<+09>-9", + "Asia/Kolkata": "IST-5:30", + "Asia/Krasnoyarsk": "<+07>-7", + "Asia/Kuala_Lumpur": "<+08>-8", + "Asia/Kuching": "<+08>-8", + "Asia/Kuwait": "<+03>-3", + "Asia/Macau": "CST-8", + "Asia/Magadan": "<+11>-11", + "Asia/Makassar": "WITA-8", + "Asia/Manila": "PST-8", + "Asia/Muscat": "<+04>-4", + "Asia/Nicosia": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Asia/Novokuznetsk": "<+07>-7", + "Asia/Novosibirsk": "<+07>-7", + "Asia/Omsk": "<+06>-6", + "Asia/Oral": "<+05>-5", + "Asia/Phnom_Penh": "<+07>-7", + "Asia/Pontianak": "WIB-7", + "Asia/Pyongyang": "KST-9", + "Asia/Qatar": "<+03>-3", + "Asia/Qyzylorda": "<+05>-5", + "Asia/Riyadh": "<+03>-3", + "Asia/Sakhalin": "<+11>-11", + "Asia/Samarkand": "<+05>-5", + "Asia/Seoul": "KST-9", + "Asia/Shanghai": "CST-8", + "Asia/Singapore": "<+08>-8", + "Asia/Srednekolymsk": "<+11>-11", + "Asia/Taipei": "CST-8", + "Asia/Tashkent": "<+05>-5", + "Asia/Tbilisi": "<+04>-4", + "Asia/Tehran": "<+0330>-3:30", + "Asia/Thimphu": "<+06>-6", + "Asia/Tokyo": "JST-9", + "Asia/Tomsk": "<+07>-7", + "Asia/Ulaanbaatar": "<+08>-8", + "Asia/Urumqi": "<+06>-6", + "Asia/Ust-Nera": "<+10>-10", + "Asia/Vientiane": "<+07>-7", + "Asia/Vladivostok": "<+10>-10", + "Asia/Yakutsk": "<+09>-9", + "Asia/Yangon": "<+0630>-6:30", + "Asia/Yekaterinburg": "<+05>-5", + "Asia/Yerevan": "<+04>-4", + "Atlantic/Azores": "<-01>1<+00>,M3.5.0/0,M10.5.0/1", + "Atlantic/Bermuda": "AST4ADT,M3.2.0,M11.1.0", + "Atlantic/Canary": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Cape_Verde": "<-01>1", + "Atlantic/Faroe": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Madeira": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Reykjavik": "GMT0", + "Atlantic/South_Georgia": "<-02>2", + "Atlantic/Stanley": "<-03>3", + "Atlantic/St_Helena": "GMT0", + "Australia/Adelaide": "ACST-9:30ACDT,M10.1.0,M4.1.0/3", + "Australia/Brisbane": "AEST-10", + "Australia/Broken_Hill": "ACST-9:30ACDT,M10.1.0,M4.1.0/3", + "Australia/Currie": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Darwin": "ACST-9:30", + "Australia/Eucla": "<+0845>-8:45", + "Australia/Hobart": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Lindeman": "AEST-10", + "Australia/Lord_Howe": "<+1030>-10:30<+11>-11,M10.1.0,M4.1.0", + "Australia/Melbourne": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Perth": "AWST-8", + "Australia/Sydney": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Europe/Amsterdam": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Andorra": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Astrakhan": "<+04>-4", + "Europe/Athens": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Belgrade": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Berlin": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Bratislava": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Brussels": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Bucharest": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Budapest": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Busingen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Chisinau": "EET-2EEST,M3.5.0,M10.5.0/3", + "Europe/Copenhagen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Dublin": "IST-1GMT0,M10.5.0,M3.5.0/1", + "Europe/Gibraltar": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Guernsey": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Helsinki": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Isle_of_Man": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Istanbul": "<+03>-3", + "Europe/Jersey": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Kaliningrad": "EET-2", + "Europe/Kiev": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Kirov": "MSK-3", + "Europe/Lisbon": "WET0WEST,M3.5.0/1,M10.5.0", + "Europe/Ljubljana": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/London": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Luxembourg": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Madrid": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Malta": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Mariehamn": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Minsk": "<+03>-3", + "Europe/Monaco": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Moscow": "MSK-3", + "Europe/Oslo": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Paris": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Podgorica": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Prague": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Riga": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Rome": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Samara": "<+04>-4", + "Europe/San_Marino": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Sarajevo": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Saratov": "<+04>-4", + "Europe/Simferopol": "MSK-3", + "Europe/Skopje": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Sofia": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Stockholm": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Tallinn": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Tirane": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Ulyanovsk": "<+04>-4", + "Europe/Uzhgorod": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Vaduz": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vatican": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vienna": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vilnius": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Volgograd": "MSK-3", + "Europe/Warsaw": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Zagreb": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Zaporozhye": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Zurich": "CET-1CEST,M3.5.0,M10.5.0/3", + "Indian/Antananarivo": "EAT-3", + "Indian/Chagos": "<+06>-6", + "Indian/Christmas": "<+07>-7", + "Indian/Cocos": "<+0630>-6:30", + "Indian/Comoro": "EAT-3", + "Indian/Kerguelen": "<+05>-5", + "Indian/Mahe": "<+04>-4", + "Indian/Maldives": "<+05>-5", + "Indian/Mauritius": "<+04>-4", + "Indian/Mayotte": "EAT-3", + "Indian/Reunion": "<+04>-4", + "Pacific/Apia": "<+13>-13", + "Pacific/Auckland": "NZST-12NZDT,M9.5.0,M4.1.0/3", + "Pacific/Bougainville": "<+11>-11", + "Pacific/Chatham": "<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45", + "Pacific/Chuuk": "<+10>-10", + "Pacific/Easter": "<-06>6<-05>,M9.1.6/22,M4.1.6/22", + "Pacific/Efate": "<+11>-11", + "Pacific/Enderbury": "<+13>-13", + "Pacific/Fakaofo": "<+13>-13", + "Pacific/Fiji": "<+12>-12", + "Pacific/Funafuti": "<+12>-12", + "Pacific/Galapagos": "<-06>6", + "Pacific/Gambier": "<-09>9", + "Pacific/Guadalcanal": "<+11>-11", + "Pacific/Guam": "ChST-10", + "Pacific/Honolulu": "HST10", + "Pacific/Kiritimati": "<+14>-14", + "Pacific/Kosrae": "<+11>-11", + "Pacific/Kwajalein": "<+12>-12", + "Pacific/Majuro": "<+12>-12", + "Pacific/Marquesas": "<-0930>9:30", + "Pacific/Midway": "SST11", + "Pacific/Nauru": "<+12>-12", + "Pacific/Niue": "<-11>11", + "Pacific/Norfolk": "<+11>-11<+12>,M10.1.0,M4.1.0/3", + "Pacific/Noumea": "<+11>-11", + "Pacific/Pago_Pago": "SST11", + "Pacific/Palau": "<+09>-9", + "Pacific/Pitcairn": "<-08>8", + "Pacific/Pohnpei": "<+11>-11", + "Pacific/Port_Moresby": "<+10>-10", + "Pacific/Rarotonga": "<-10>10", + "Pacific/Saipan": "ChST-10", + "Pacific/Tahiti": "<-10>10", + "Pacific/Tarawa": "<+12>-12", + "Pacific/Tongatapu": "<+13>-13", + "Pacific/Wake": "<+12>-12", + "Pacific/Wallis": "<+12>-12", + "Etc/GMT": "GMT0", + "Etc/GMT-0": "GMT0", + "Etc/GMT-1": "<+01>-1", + "Etc/GMT-2": "<+02>-2", + "Etc/GMT-3": "<+03>-3", + "Etc/GMT-4": "<+04>-4", + "Etc/GMT-5": "<+05>-5", + "Etc/GMT-6": "<+06>-6", + "Etc/GMT-7": "<+07>-7", + "Etc/GMT-8": "<+08>-8", + "Etc/GMT-9": "<+09>-9", + "Etc/GMT-10": "<+10>-10", + "Etc/GMT-11": "<+11>-11", + "Etc/GMT-12": "<+12>-12", + "Etc/GMT-13": "<+13>-13", + "Etc/GMT-14": "<+14>-14", + "Etc/GMT0": "GMT0", + "Etc/GMT+0": "GMT0", + "Etc/GMT+1": "<-01>1", + "Etc/GMT+2": "<-02>2", + "Etc/GMT+3": "<-03>3", + "Etc/GMT+4": "<-04>4", + "Etc/GMT+5": "<-05>5", + "Etc/GMT+6": "<-06>6", + "Etc/GMT+7": "<-07>7", + "Etc/GMT+8": "<-08>8", + "Etc/GMT+9": "<-09>9", + "Etc/GMT+10": "<-10>10", + "Etc/GMT+11": "<-11>11", + "Etc/GMT+12": "<-12>12", + "Etc/UCT": "UTC0", + "Etc/UTC": "UTC0", + "Etc/Greenwich": "GMT0", + "Etc/Universal": "UTC0", + "Etc/Zulu": "UTC0", +} diff --git a/internal_filesystem/lib/mpos/ui/__init__.py b/internal_filesystem/lib/mpos/ui/__init__.py index 8d8aff78..4e369b3a 100644 --- a/internal_filesystem/lib/mpos/ui/__init__.py +++ b/internal_filesystem/lib/mpos/ui/__init__.py @@ -3,6 +3,7 @@ import utime # for timing calls import lvgl as lv import mpos.apps import mpos.battery_voltage +import mpos.time import mpos.wifi from mpos.ui.anim import WidgetAnimator @@ -189,9 +190,9 @@ def create_notification_bar(): # Update time import time def update_time(timer): - hours = time.localtime()[3] - minutes = time.localtime()[4] - seconds = time.localtime()[5] + hours = mpos.time.localtime()[3] + minutes = mpos.time.localtime()[4] + seconds = mpos.time.localtime()[5] time_label.set_text(f"{hours:02d}:{minutes:02d}:{seconds:02d}") can_check_network = False