From: Matheus Afonso Martins Moreira Date: Sun, 8 Sep 2024 16:41:52 +0000 (-0300) Subject: Merge PR #470 - implement automatic DST toggling X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=ac5bf8cfce67cdb5662aeea618c2eb9511f0d190;p=sensor-watch.git Merge PR #470 - implement automatic DST toggling Implements logic to automatically offset daylight saving time settings when calculating timezone offsets. This should make the DST functions work automatically with no need for user input in most cases. Reviewed-by: Matheus Afonso Martins Moreira GitHub-Pull-Request: https://github.com/joeycastillo/Sensor-Watch/pull/470 --- ac5bf8cfce67cdb5662aeea618c2eb9511f0d190 diff --cc movement/movement.c index 81e1b3c,60e9106..ba21a4e --- a/movement/movement.c +++ b/movement/movement.c @@@ -105,31 -96,11 +106,36 @@@ of debounce time #define MOVEMENT_DEFAULT_LED_DURATION 1 #endif +// Default to no set location latitude +#ifndef MOVEMENT_DEFAULT_LATITUDE +#define MOVEMENT_DEFAULT_LATITUDE 0 +#endif + +// Default to no set location longitude +#ifndef MOVEMENT_DEFAULT_LONGITUDE +#define MOVEMENT_DEFAULT_LONGITUDE 0 +#endif + +// Default to no set birthdate year +#ifndef MOVEMENT_DEFAULT_BIRTHDATE_YEAR +#define MOVEMENT_DEFAULT_BIRTHDATE_YEAR 0 +#endif + +// Default to no set birthdate month +#ifndef MOVEMENT_DEFAULT_BIRTHDATE_MONTH +#define MOVEMENT_DEFAULT_BIRTHDATE_MONTH 0 +#endif + +// Default to no set birthdate day +#ifndef MOVEMENT_DEFAULT_BIRTHDATE_DAY +#define MOVEMENT_DEFAULT_BIRTHDATE_DAY 0 +#endif + + // Default to having DST get set + #ifndef MOVEMENT_DEFAULT_DST_ACTIVE + #define MOVEMENT_DEFAULT_DST_ACTIVE true + #endif + #if __EMSCRIPTEN__ #include #endif @@@ -323,6 -247,31 +286,31 @@@ static inline void _movement_disable_fa } } + static bool _check_and_act_on_daylight_savings(void) { + if (!movement_state.settings.bit.dst_active) return false; + watch_date_time date_time = watch_rtc_get_date_time(); + // No need for all of the unix time calculations for times not at the beginning or end of the hour - if (date_time.unit.minute > 1 && date_time.unit.minute < 59) return false; ++ if (date_time.unit.minute > 1 && date_time.unit.minute < 59) return false; + uint8_t dst_result = get_dst_status(date_time); + bool dst_skip_rolling_back = get_dst_skip_rolling_back(); + + if (dst_skip_rolling_back && (dst_result == DST_ENDED)) { + clear_dst_skip_rolling_back(); + } + else if (dst_result == DST_ENDING && !dst_skip_rolling_back) { + date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; + watch_rtc_set_date_time(date_time); + set_dst_skip_rolling_back(); + return true; + } + else if (dst_result == DST_STARTING) { + date_time.unit.hour = (date_time.unit.hour + 1) % 24; - watch_rtc_set_date_time(date_time); ++ watch_rtc_set_date_time(date_time); + return true; + } + return false; + } + static void _movement_handle_background_tasks(void) { for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { // For each face, if the watch face wants a background task... @@@ -546,11 -480,19 +541,25 @@@ void app_init(void) movement_state.settings.bit.to_interval = MOVEMENT_DEFAULT_TIMEOUT_INTERVAL; movement_state.settings.bit.le_interval = MOVEMENT_DEFAULT_LOW_ENERGY_INTERVAL; movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION; + movement_state.location.bit.latitude = MOVEMENT_DEFAULT_LATITUDE; + movement_state.location.bit.longitude = MOVEMENT_DEFAULT_LONGITUDE; + movement_state.birthdate.bit.year = MOVEMENT_DEFAULT_BIRTHDATE_YEAR; + movement_state.birthdate.bit.month = MOVEMENT_DEFAULT_BIRTHDATE_MONTH; + movement_state.birthdate.bit.day = MOVEMENT_DEFAULT_BIRTHDATE_DAY; + movement_state.settings.bit.dst_active = MOVEMENT_DEFAULT_DST_ACTIVE; + + #ifdef MAKEFILE_TIMEZONE + timezone_offsets = dst_occurring(watch_rtc_get_date_time()) ? movement_timezone_dst_offsets : movement_timezone_offsets; + for (int i = 0; i < NUM_TIME_ZONES; i++) { + if (timezone_offsets[i] == MAKEFILE_TIMEZONE) { + movement_state.settings.bit.time_zone = i; + break; + } + } + #else + movement_state.settings.bit.time_zone = 35; // Atlantic Time as default + #endif ++ movement_state.light_ticks = -1; movement_state.alarm_ticks = -1; movement_state.next_available_backup_register = 4; diff --cc movement/movement_config.h index abceacf,46e1d2e..566ea3e --- a/movement/movement_config.h +++ b/movement/movement_config.h @@@ -95,20 -95,11 +95,27 @@@ const watch_face_t watch_faces[] = */ #define MOVEMENT_DEFAULT_LED_DURATION 1 +/* The latitude and longitude used for the wearers location + * Set signed values in 1/100ths of a degree + */ +#define MOVEMENT_DEFAULT_LATITUDE 0 +#define MOVEMENT_DEFAULT_LONGITUDE 0 + +/* The wearers birthdate + * Valid values: + * Year: 1 - 4095 + * Month: 1 - 12 + * Day: 1 - 31 + */ +#define MOVEMENT_DEFAULT_BIRTHDATE_YEAR 0 +#define MOVEMENT_DEFAULT_BIRTHDATE_MONTH 0 +#define MOVEMENT_DEFAULT_BIRTHDATE_DAY 0 + + /* Set if using DST + * Valid values are: + * false: Don't allow the watch to use DST + * true: Allow the watch to use DST + */ + #define MOVEMENT_DEFAULT_DST_ACTIVE true + #endif // MOVEMENT_CONFIG_H_ diff --cc movement/watch_faces/complication/countdown_face.c index f585ebc,04dc592..825595e --- a/movement/watch_faces/complication/countdown_face.c +++ b/movement/watch_faces/complication/countdown_face.c @@@ -69,30 -68,18 +69,32 @@@ static inline void button_beep(movement watch_buzzer_play_note(BUZZER_NOTE_C7, 50); } -static void start(countdown_state_t *state, movement_settings_t *settings) { +static void schedule_countdown(countdown_state_t *state, movement_settings_t *settings) { + watch_date_time now = watch_rtc_get_date_time(); + int16_t tz = get_tz_offset(settings, now); - // Calculate the new state->now_ts but don't update it until we've updated the target - - state->mode = cd_running; - state->now_ts = watch_utility_date_time_to_unix_time(now, tz); - state->target_ts = watch_utility_offset_timestamp(state->now_ts, state->hours, state->minutes, state->seconds); ++ // Calculate the new state->now_ts but don't update it until we've updated the target - + // avoid possible race where the old target is compared to the new time and immediately triggers - uint32_t new_now = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), get_tz_offset(settings)); ++ uint32_t new_now = watch_utility_date_time_to_unix_time(now, tz); + state->target_ts = watch_utility_offset_timestamp(new_now, state->hours, state->minutes, state->seconds); + state->now_ts = new_now; - watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings)); + watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, tz); - movement_schedule_background_task(target_dt); - watch_set_indicator(WATCH_INDICATOR_BELL); + movement_schedule_background_task_for_face(state->watch_face_index, target_dt); +} + +static void auto_repeat(countdown_state_t *state, movement_settings_t *settings) { + movement_play_alarm(); + load_countdown(state); + schedule_countdown(state, settings); } +static void start(countdown_state_t *state, movement_settings_t *settings) { + state->mode = cd_running; + schedule_countdown(state, settings); +} + + + static void draw(countdown_state_t *state, uint8_t subsecond) { char buf[16]; @@@ -203,12 -177,10 +205,12 @@@ void countdown_face_activate(movement_s countdown_state_t *state = (countdown_state_t *)context; if(state->mode == cd_running) { watch_date_time now = watch_rtc_get_date_time(); - state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings)); + state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings, now)); - watch_set_indicator(WATCH_INDICATOR_BELL); + watch_set_indicator(WATCH_INDICATOR_SIGNAL); } watch_set_colon(); + if(state->repeat) + watch_set_indicator(WATCH_INDICATOR_BELL); movement_request_tick_frequency(1); quick_ticks_running = false; diff --cc movement/watch_faces/complication/planetary_time_face.c index 7e7ac6c,836ada6..1245cc6 --- a/movement/watch_faces/complication/planetary_time_face.c +++ b/movement/watch_faces/complication/planetary_time_face.c @@@ -37,7 -37,7 +37,7 @@@ // STATIC FUNCTIONS AND CONSTANTS ///////////////////////////////////////////// /** @brief Planetary rulers in the Chaldean order from slowest to fastest -- * @details Planetary rulers in the Chaldean order from slowest to fastest: ++ * @details Planetary rulers in the Chaldean order from slowest to fastest: * Jupiter, Mars, Sun, Venus, Mercury, Moon */ static const char planets[7][3] = {"Sa", "Ju", "Ma", "So", "Ve", "Me", "Lu"}; // Latin @@@ -150,7 -151,7 +151,7 @@@ static void _planetary_solar_phase(move // calculate sunrise and sunset of current day in decimal hours after midnight sun_rise_set(scratch_time.unit.year + WATCH_RTC_REFERENCE_YEAR, scratch_time.unit.month, scratch_time.unit.day, lon, lat, &sunrise, &sunset); -- ++ // calculate sunrise and sunset UNIX timestamps sunrise_epoch = midnight_epoch + sunrise * 3600; sunset_epoch = midnight_epoch + sunset * 3600; @@@ -191,7 -192,7 +192,7 @@@ state->phase_end = sunrise_epoch; } -- // calculate the duration of a planetary second during this solar phase ++ // calculate the duration of a planetary second during this solar phase // and convert to Hertz so we can call a faster tick rate state->freq = (1 / ((double)( state->phase_end - state->phase_start ) / 43200)); } @@@ -206,12 -207,12 +207,13 @@@ static void _planetary_time(movement_ev double night_hour_count = 0.0; uint8_t weekday, planet, planetary_hour; double hour_duration, current_hour, current_minute, current_second; + bool set_leading_zero = false; + watch_date_time date_time = watch_rtc_get_date_time(); watch_set_colon(); // get current time and convert to UTC - state->scratch = watch_utility_date_time_convert_zone(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60, 0); - state->scratch = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0); ++ state->scratch = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0); // when current phase ends calculate the next phase if ( watch_utility_date_time_to_unix_time(state->scratch, 0) >= state->phase_end ) { @@@ -261,14 -259,12 +263,14 @@@ if ( state->ruler == 0 ) strncpy(ruler, planets[planet], 3); if ( state->ruler == 1 ) strncpy(ruler, planetes[planet], 3); if ( state->ruler == 2 ) strncpy(ruler, " ", 3); -- ++ // display planetary time with ruler of the hour or ruler of the day if ( state->day_ruler ) sprintf(buf, "%s d%2d%02d%02d", ruler, state->scratch.unit.hour, state->scratch.unit.minute, state->scratch.unit.second); else sprintf(buf, "%s h%2d%02d%02d", ruler, state->scratch.unit.hour, state->scratch.unit.minute, state->scratch.unit.second); -- ++ watch_display_string(buf, 0); + if (set_leading_zero) + watch_display_string("0", 4); if ( state->ruler == 2 ) _planetary_icon(planet); @@@ -301,7 -297,7 +303,7 @@@ void planetary_time_face_activate(movem #endif planetary_time_state_t *state = (planetary_time_state_t *)context; -- ++ // calculate phase _planetary_solar_phase(settings, state); } diff --cc movement/watch_faces/settings/set_time_face.c index d50d24b,1b19df8..0b70575 --- a/movement/watch_faces/settings/set_time_face.c +++ b/movement/watch_faces/settings/set_time_face.c @@@ -135,8 -134,7 +128,9 @@@ bool set_time_face_loop(movement_event_ return movement_default_loop_handler(event, settings); } - char buf[11]; + char buf[13]; + bool set_leading_zero = false; ++ if (current_page < 3) { watch_set_colon(); if (settings->bit.clock_mode_24h) { diff --cc movement/watch_faces/settings/set_time_hackwatch_face.c index 75bc7bb,44ae04e..6e67808 --- a/movement/watch_faces/settings/set_time_hackwatch_face.c +++ b/movement/watch_faces/settings/set_time_hackwatch_face.c @@@ -132,10 -134,11 +132,11 @@@ bool set_time_hackwatch_face_loop(movem } break; } - if (current_page != 2) // Do not set time when we are at seconds, it was already set previously + if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously watch_rtc_set_date_time(date_time_settings); + } break; - + case EVENT_ALARM_LONG_UP://Setting seconds on long release switch (current_page) { case 2: // second @@@ -171,11 -179,10 +172,16 @@@ if (settings->bit.time_zone > 40) settings->bit.time_zone = 0; break; } ++ + if (date_time_settings.unit.day > days_in_month(date_time_settings.unit.month, date_time_settings.unit.year + WATCH_RTC_REFERENCE_YEAR)) + date_time_settings.unit.day = 1; - if (current_page != 2) // Do not set time when we are at seconds, it was already set previously ++ + if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously watch_rtc_set_date_time(date_time_settings); + } ++ //TODO: Do not update whole RTC, just what we are changing ++ break; case EVENT_TIMEOUT: movement_move_to_face(0);