Skip to main content

ClockSync

Struct ClockSync 

Source
pub struct ClockSync { /* private fields */ }
Available on crate feature wifi and target_os=none only.
Expand description

Combines NTP synchronization with a local clock and tick events.

ClockSync does not emit ticks until the first successful sync (or a manual call to ClockSync::set_utc_time). Each tick includes how long it has been since the last successful sync.

§Example: WiFi + ClockSync logging

use device_envoy::{
    Error,
    Result,
    button::PressedTo,
    clock_sync::{ClockSync, ClockSyncStatic, ONE_SECOND, h12_m_s},
    flash_array::FlashArray,
    wifi_auto::fields::{TimezoneField, TimezoneFieldStatic},
    wifi_auto::{WifiAuto, WifiAutoEvent},
};
use defmt::info;

async fn run(
    spawner: embassy_executor::Spawner,
    p: embassy_rp::Peripherals,
) -> Result<(), device_envoy::Error> {
    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;

    static TIMEZONE_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
    let timezone_field = TimezoneField::new(&TIMEZONE_STATIC, timezone_flash_block);

    let wifi_auto = WifiAuto::new(
        p.PIN_23,
        p.PIN_24,
        p.PIN_25,
        p.PIN_29,
        p.PIO0,
        p.DMA_CH0,
        wifi_credentials_flash_block,
        p.PIN_13,
        PressedTo::Ground,
        "ClockSync",
        [timezone_field],
        spawner,
    )?;

    let (stack, _button) = wifi_auto
        .connect(|event| async move {
            match event {
                WifiAutoEvent::CaptivePortalReady => {
                    info!("WifiAuto: setup mode ready");
                }
                WifiAutoEvent::Connecting { .. } => {
                    info!("WifiAuto: connecting");
                }
                WifiAutoEvent::ConnectionFailed => {
                    info!("WifiAuto: connection failed");
                }
            }
            Ok(())
        })
        .await?;

    let offset_minutes = timezone_field
        .offset_minutes()?
        .ok_or(Error::MissingCustomWifiAutoField)?;
    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
    let clock_sync = ClockSync::new(
        &CLOCK_SYNC_STATIC,
        stack,
        offset_minutes,
        Some(ONE_SECOND),
        spawner,
    );

    loop {
        let tick = clock_sync.wait_for_tick().await;
        let (hours, minutes, seconds) = h12_m_s(&tick.local_time);
        info!(
            "Time {:02}:{:02}:{:02}, since sync {}s",
            hours,
            minutes,
            seconds,
            tick.since_last_sync.as_secs()
        );
    }
}

Implementations§

Source§

impl ClockSync

Source

pub const fn new_static() -> ClockSyncStatic

Create ClockSync resources.

Examples found in repository?
examples/clock_console.rs (line 92)
92    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
More examples
Hide additional examples
examples/clock_lcd.rs (line 74)
74    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
examples/clock_led12x4.rs (line 147)
147    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
examples/clock_led4.rs (line 125)
125    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
examples/clock_led8x12.rs (line 154)
154    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
examples/clock_servos.rs (line 123)
123    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
Source

pub fn new( clock_sync_static: &'static ClockSyncStatic, stack: &'static Stack<'static>, offset_minutes: i32, tick_interval: Option<Duration>, spawner: Spawner, ) -> Self

Create a ClockSync using an existing network stack.

See the ClockSync struct example for usage.

Examples found in repository?
examples/clock_console.rs (lines 93-99)
32async fn inner_main(spawner: Spawner) -> Result<Infallible> {
33    info!("Starting Console Clock with WiFi");
34
35    // Initialize RP2040 peripherals
36    let p = embassy_rp::init(Default::default());
37
38    // Use two blocks of flash storage: Wi-Fi credentials + timezone
39    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
40
41    // Define timezone field for captive portal
42    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
43    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
44
45    // Set up WiFi via captive portal
46    let wifi_auto = WifiAuto::new(
47        p.PIN_23,  // CYW43 power
48        p.PIN_24,  // CYW43 clock
49        p.PIN_25,  // CYW43 chip select
50        p.PIN_29,  // CYW43 data pin
51        p.PIO0,    // CYW43 PIO interface
52        p.DMA_CH0, // CYW43 DMA channel
53        wifi_credentials_flash_block,
54        p.PIN_13, // Reset button pin
55        PressedTo::Ground,
56        "www.picoclock.net",
57        [timezone_field],
58        spawner,
59    )?;
60
61    // Connect to WiFi
62    let (stack, _button) = wifi_auto
63        .connect(|event| async move {
64            match event {
65                WifiAutoEvent::CaptivePortalReady => {
66                    info!("Captive portal ready - connect to WiFi network");
67                }
68                WifiAutoEvent::Connecting {
69                    try_index,
70                    try_count,
71                } => {
72                    info!(
73                        "Connecting to WiFi (attempt {} of {})...",
74                        try_index + 1,
75                        try_count
76                    );
77                }
78                WifiAutoEvent::ConnectionFailed => {
79                    info!("WiFi connection failed!");
80                }
81            }
82            Ok(())
83        })
84        .await?;
85
86    info!("WiFi connected successfully!");
87
88    // Create ClockSync device with timezone from WiFi portal
89    let timezone_offset_minutes = timezone_field
90        .offset_minutes()?
91        .ok_or(Error::MissingCustomWifiAutoField)?;
92    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
93    let clock_sync = ClockSync::new(
94        &CLOCK_SYNC_STATIC,
95        stack,
96        timezone_offset_minutes,
97        Some(ONE_SECOND),
98        spawner,
99    );
100
101    info!("WiFi connected, entering event loop");
102
103    // Main event loop - log time on every tick
104    loop {
105        let tick = clock_sync.wait_for_tick().await;
106        let time_info = tick.local_time;
107        info!(
108            "Current time: {:04}-{:02}-{:02} {:02}:{:02}:{:02}",
109            time_info.year(),
110            u8::from(time_info.month()),
111            time_info.day(),
112            time_info.hour(),
113            time_info.minute(),
114            time_info.second(),
115        );
116    }
117}
More examples
Hide additional examples
examples/clock_lcd.rs (lines 75-81)
34async fn inner_main(spawner: Spawner) -> Result<Infallible> {
35    info!("Starting LCD Clock with WiFi");
36
37    // Initialize RP2040 peripherals
38    let p = embassy_rp::init(Default::default());
39
40    // Initialize CharLcd
41    static CHAR_LCD_STATIC: CharLcdStatic = CharLcd::new_static();
42    let char_lcd = CharLcd::new(&CHAR_LCD_STATIC, p.I2C0, p.PIN_5, p.PIN_4, spawner)?;
43
44    // Use two blocks of flash storage: Wi-Fi credentials + timezone
45    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
46
47    // Define timezone field for captive portal
48    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
49    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
50
51    // Set up WiFi via captive portal
52    let wifi_auto = WifiAuto::new(
53        p.PIN_23,  // CYW43 power
54        p.PIN_24,  // CYW43 clock
55        p.PIN_25,  // CYW43 chip select
56        p.PIN_29,  // CYW43 data pin
57        p.PIO0,    // CYW43 PIO interface
58        p.DMA_CH0, // CYW43 DMA channel
59        wifi_credentials_flash_block,
60        p.PIN_13, // Reset button pin
61        PressedTo::Ground,
62        "www.picoclock.net",
63        [timezone_field],
64        spawner,
65    )?;
66
67    // Connect to WiFi
68    let (stack, _button) = wifi_auto.connect(|_event| async move { Ok(()) }).await?;
69
70    // Create ClockSync device with timezone from WiFi portal
71    let timezone_offset_minutes = timezone_field
72        .offset_minutes()?
73        .ok_or(Error::MissingCustomWifiAutoField)?;
74    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
75    let clock_sync = ClockSync::new(
76        &CLOCK_SYNC_STATIC,
77        stack,
78        timezone_offset_minutes,
79        Some(ONE_SECOND),
80        spawner,
81    );
82
83    info!("Entering main event loop");
84
85    // Main orchestrator loop - owns LCD and displays the clock
86    loop {
87        let tick = clock_sync.wait_for_tick().await;
88        let time_info = tick.local_time;
89        let mut text = String::<64>::new();
90        let (hour12, am_pm) = if time_info.hour() == 0 {
91            (12, "AM")
92        } else if time_info.hour() < 12 {
93            (time_info.hour(), "AM")
94        } else if time_info.hour() == 12 {
95            (12, "PM")
96        } else {
97            #[expect(clippy::arithmetic_side_effects, reason = "hour guaranteed 13-23")]
98            {
99                (time_info.hour() - 12, "PM")
100            }
101        };
102        fmt::Write::write_fmt(
103            &mut text,
104            format_args!(
105                "{:2}:{:02}:{:02} {}\n{:04}-{:02}-{:02}",
106                hour12,
107                time_info.minute(),
108                time_info.second(),
109                am_pm,
110                time_info.year(),
111                u8::from(time_info.month()),
112                time_info.day()
113            ),
114        )
115        .map_err(|_| Error::FormatError)?;
116        char_lcd.write_text(text, 0).await;
117    }
118}
examples/clock_servos.rs (lines 124-130)
60async fn inner_main(spawner: Spawner) -> Result<Infallible> {
61    info!("Starting Wi-Fi servo clock (WifiAuto)");
62    let p = embassy_rp::init(Default::default());
63
64    // Use two blocks of flash storage: Wi-Fi credentials + timezone
65    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
66
67    // Define HTML to ask for timezone on the captive portal.
68    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
69    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
70
71    // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
72    let wifi_auto = WifiAuto::new(
73        p.PIN_23,  // CYW43 power
74        p.PIN_24,  // CYW43 clock
75        p.PIN_25,  // CYW43 chip select
76        p.PIN_29,  // CYW43 data pin
77        p.PIO0,    // CYW43 PIO interface
78        p.DMA_CH0, // CYW43 DMA channel
79        wifi_credentials_flash_block,
80        p.PIN_13, // Reset button pin
81        PressedTo::Ground,
82        "PicoServoClock", // Captive-portal SSID
83        [timezone_field],
84        spawner,
85    )?;
86
87    // Configure two servos for the display.
88    let bottom_servo = BottomServoPlayer::new(p.PIN_11, p.PWM_SLICE5, spawner)?;
89    let top_servo = TopServoPlayer::new(p.PIN_12, p.PWM_SLICE6, spawner)?;
90    let servo_display = ServoClockDisplay::new(bottom_servo, top_servo);
91
92    // Connect Wi-Fi, using the servos for status indications.
93    let servo_display_ref = &servo_display;
94    let (stack, button) = wifi_auto
95        .connect(|event| {
96            let servo_display_ref = servo_display_ref;
97            async move {
98                match event {
99                    WifiAutoEvent::CaptivePortalReady => {
100                        servo_display_ref.show_portal_ready().await;
101                    }
102                    WifiAutoEvent::Connecting { .. } => servo_display_ref.show_connecting().await,
103                    WifiAutoEvent::ConnectionFailed => {
104                        // No-op; portal remains visible on failure.
105                    }
106                }
107                Ok(())
108            }
109        })
110        .await?;
111
112    info!("WiFi connected");
113
114    // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
115    let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
116
117    // Read the timezone offset, an extra field that WiFi portal saved to flash.
118    let offset_minutes = timezone_field
119        .offset_minutes()?
120        .ok_or(Error::MissingCustomWifiAutoField)?;
121
122    // Create a ClockSync device that knows its timezone offset.
123    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
124    let clock_sync = ClockSync::new(
125        &CLOCK_SYNC_STATIC,
126        stack,
127        offset_minutes,
128        Some(ONE_MINUTE),
129        spawner,
130    );
131
132    // Start in HH:MM mode
133    let mut state = State::HoursMinutes { speed: 1.0 };
134    loop {
135        state = match state {
136            State::HoursMinutes { speed } => {
137                state
138                    .execute_hours_minutes(speed, &clock_sync, button_watch13, &servo_display)
139                    .await?
140            }
141            State::MinutesSeconds => {
142                state
143                    .execute_minutes_seconds(&clock_sync, button_watch13, &servo_display)
144                    .await?
145            }
146            State::EditOffset => {
147                state
148                    .execute_edit_offset(
149                        &clock_sync,
150                        button_watch13,
151                        &timezone_field,
152                        &servo_display,
153                    )
154                    .await?
155            }
156        };
157    }
158}
examples/clock_led8x12.rs (lines 155-161)
84async fn inner_main(spawner: Spawner) -> Result<Infallible> {
85    info!("Starting Wi-Fi 8x12 LED clock (rotated display)");
86    let p = embassy_rp::init(Default::default());
87
88    // Use two blocks of flash storage: Wi-Fi credentials + timezone
89    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
90
91    // Define HTML to ask for timezone on the captive portal.
92    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
93    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
94
95    // Set up Wifi via a captive portal.
96    let wifi_auto = WifiAuto::new(
97        p.PIN_23,  // CYW43 power
98        p.PIN_24,  // CYW43 clock
99        p.PIN_25,  // CYW43 chip select
100        p.PIN_29,  // CYW43 data pin
101        p.PIO0,    // CYW43 PIO interface
102        p.DMA_CH0, // CYW43 DMA channel
103        wifi_credentials_flash_block,
104        p.PIN_13, // Reset button pin (used only during WiFi setup)
105        PressedTo::Ground,
106        "www.picoclock.net", // Captive-portal SSID
107        [timezone_field],    // Custom fields to ask for
108        spawner,
109    )?;
110
111    // Set up the 8x12 LED display on GPIO4.
112    let led8x12 = Led8x12::new(p.PIN_4, p.PIO1, p.DMA_CH1, spawner)?;
113
114    // Connect Wi-Fi, using the LED panel for status.
115    let led8x12_ref = &led8x12;
116    let (stack, button) = wifi_auto
117        .connect(|event| {
118            let led8x12_ref = led8x12_ref;
119            async move {
120                match event {
121                    WifiAutoEvent::CaptivePortalReady => {
122                        info!("WiFi: captive portal ready, displaying JOIN");
123                        show_portal_ready(led8x12_ref).await?;
124                    }
125                    WifiAutoEvent::Connecting {
126                        try_index,
127                        try_count,
128                    } => {
129                        info!("WiFi: connecting (attempt {}/{})", try_index + 1, try_count);
130                        show_connecting(led8x12_ref, try_index, try_count).await?;
131                    }
132                    WifiAutoEvent::ConnectionFailed => {
133                        info!("WiFi: connection failed, displaying FAIL, device will reset");
134                        show_connection_failed(led8x12_ref).await?;
135                    }
136                }
137                Ok(())
138            }
139        })
140        .await?;
141
142    info!("WiFi: connected successfully, displaying DONE");
143    show_connected(&led8x12).await?;
144
145    // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
146    let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
147
148    // Read the timezone offset, an extra field that WiFi portal saved to flash.
149    let offset_minutes = timezone_field
150        .offset_minutes()?
151        .ok_or(Error::MissingCustomWifiAutoField)?;
152
153    // Create a clock synced over WiFi.
154    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
155    let clock_sync = ClockSync::new(
156        &CLOCK_SYNC_STATIC,
157        stack,
158        offset_minutes,
159        Some(ONE_MINUTE),
160        spawner,
161    );
162
163    // Start in HH:MM mode
164    let mut state = State::HoursMinutes { speed: 1.0 };
165    loop {
166        state = match state {
167            State::HoursMinutes { speed } => {
168                state
169                    .execute_hours_minutes(speed, &clock_sync, &button_watch13, &led8x12)
170                    .await?
171            }
172            State::MinutesSeconds => {
173                state
174                    .execute_minutes_seconds(&clock_sync, &button_watch13, &led8x12)
175                    .await?
176            }
177            State::EditOffset => {
178                state
179                    .execute_edit_offset(&clock_sync, &button_watch13, &timezone_field, &led8x12)
180                    .await?
181            }
182        };
183    }
184}
examples/clock_led12x4.rs (lines 148-154)
77async fn inner_main(spawner: Spawner) -> Result<Infallible> {
78    info!("Starting Wi-Fi 12x4 LED clock (WifiAuto)");
79    let p = embassy_rp::init(Default::default());
80
81    // Use two blocks of flash storage: Wi-Fi credentials + timezone
82    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
83
84    // Define HTML to ask for timezone on the captive portal.
85    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
86    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
87
88    // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
89    let wifi_auto = WifiAuto::new(
90        p.PIN_23,  // CYW43 power
91        p.PIN_24,  // CYW43 clock
92        p.PIN_25,  // CYW43 chip select
93        p.PIN_29,  // CYW43 data pin
94        p.PIO1,    // CYW43 PIO interface (swapped to show PIO not hardcoded)
95        p.DMA_CH0, // CYW43 DMA channel
96        wifi_credentials_flash_block,
97        p.PIN_13, // Reset button pin
98        PressedTo::Ground,
99        "www.picoclock.net", // Captive-portal SSID
100        [timezone_field],    // Custom fields to ask for
101        spawner,
102    )?;
103
104    // Set up the 12x4 LED display on GPIO3.
105    let led12x4 = Led12x4::new(p.PIN_3, p.PIO0, p.DMA_CH1, spawner)?;
106
107    // Connect Wi-Fi, using the LED panel for status.
108    let led12x4_ref = &led12x4;
109    let (stack, button) = wifi_auto
110        .connect(|event| {
111            let led12x4_ref = led12x4_ref;
112            async move {
113                match event {
114                    WifiAutoEvent::CaptivePortalReady => {
115                        info!("WiFi: captive portal ready, displaying JOIN");
116                        show_portal_ready(led12x4_ref).await?;
117                    }
118                    WifiAutoEvent::Connecting {
119                        try_index,
120                        try_count,
121                    } => {
122                        info!("WiFi: connecting (attempt {}/{})", try_index + 1, try_count);
123                        show_connecting(led12x4_ref, try_index, try_count).await?;
124                    }
125                    WifiAutoEvent::ConnectionFailed => {
126                        info!("WiFi: connection failed, displaying FAIL, device will reset");
127                        show_connection_failed(led12x4_ref).await?;
128                    }
129                }
130                Ok(())
131            }
132        })
133        .await?;
134
135    info!("WiFi: connected successfully, displaying DONE");
136    show_connected(&led12x4).await?;
137
138    // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
139    let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
140
141    // Read the timezone offset, an extra field that WiFi portal saved to flash.
142    let offset_minutes = timezone_field
143        .offset_minutes()?
144        .ok_or(Error::MissingCustomWifiAutoField)?;
145
146    // Create a ClockSync device that knows its timezone offset.
147    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
148    let clock_sync = ClockSync::new(
149        &CLOCK_SYNC_STATIC,
150        stack,
151        offset_minutes,
152        Some(ONE_MINUTE),
153        spawner,
154    );
155
156    // Start in HH:MM mode
157    let mut state = State::HoursMinutes { speed: 1.0 };
158    loop {
159        state = match state {
160            State::HoursMinutes { speed } => {
161                state
162                    .execute_hours_minutes(speed, &clock_sync, button_watch13, &led12x4)
163                    .await?
164            }
165            State::MinutesSeconds => {
166                state
167                    .execute_minutes_seconds(&clock_sync, button_watch13, &led12x4)
168                    .await?
169            }
170            State::EditOffset => {
171                state
172                    .execute_edit_offset(&clock_sync, button_watch13, &timezone_field, &led12x4)
173                    .await?
174            }
175        };
176    }
177}
examples/clock_led4.rs (lines 126-132)
45async fn inner_main(spawner: Spawner) -> Result<Infallible> {
46    info!("Starting Wi-Fi 4-digit clock (WifiAuto)");
47    let p = embassy_rp::init(Default::default());
48
49    // Use two blocks of flash storage: Wi-Fi credentials + timezone
50    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
51
52    // Define HTML to ask for timezone on the captive portal.
53    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
54    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
55
56    // Set up Wifi via a captive portal. The button pin is used to reset stored credentials.
57    let wifi_auto = WifiAuto::new(
58        p.PIN_23,  // CYW43 power
59        p.PIN_24,  // CYW43 clock
60        p.PIN_25,  // CYW43 chip select
61        p.PIN_29,  // CYW43 data pin
62        p.PIO0,    // CYW43 PIO interface
63        p.DMA_CH0, // CYW43 DMA channel
64        wifi_credentials_flash_block,
65        p.PIN_13, // Reset button pin
66        PressedTo::Ground,
67        "www.picoclock.net", // Captive-portal SSID
68        [timezone_field],    // Custom fields to ask for
69        spawner,
70    )?;
71
72    // Set up the LED4 display.
73    let cell_pins = OutputArray::new([
74        gpio::Output::new(p.PIN_1, Level::High),
75        gpio::Output::new(p.PIN_2, Level::High),
76        gpio::Output::new(p.PIN_3, Level::High),
77        gpio::Output::new(p.PIN_4, Level::High),
78    ]);
79
80    let segment_pins = OutputArray::new([
81        gpio::Output::new(p.PIN_5, Level::Low),
82        gpio::Output::new(p.PIN_6, Level::Low),
83        gpio::Output::new(p.PIN_7, Level::Low),
84        gpio::Output::new(p.PIN_8, Level::Low),
85        gpio::Output::new(p.PIN_9, Level::Low),
86        gpio::Output::new(p.PIN_10, Level::Low),
87        gpio::Output::new(p.PIN_11, Level::Low),
88        gpio::Output::new(p.PIN_12, Level::Low),
89    ]);
90
91    static LED4_STATIC: Led4Static = Led4::new_static();
92    let led4 = Led4::new(&LED4_STATIC, cell_pins, segment_pins, spawner)?;
93
94    // Connect Wi-Fi, using the clock display for status.
95    let led4_ref = &led4;
96    let (stack, button) = wifi_auto
97        .connect(|event| async move {
98            match event {
99                WifiAutoEvent::CaptivePortalReady => {
100                    led4_ref.write_text(['j', 'o', 'i', 'n'], BlinkState::BlinkingAndOn);
101                }
102                WifiAutoEvent::Connecting { .. } => {
103                    led4_ref.animate_text(circular_outline_animation(true));
104                }
105                WifiAutoEvent::ConnectionFailed => {
106                    led4_ref.write_text(['F', 'A', 'I', 'L'], BlinkState::BlinkingButOff);
107                }
108            }
109            Ok(())
110        })
111        .await?;
112
113    led4.write_text(['D', 'O', 'N', 'E'], BlinkState::Solid);
114    info!("WiFi connected");
115
116    // Convert the Button from WifiAuto into a ButtonWatch for background monitoring
117    let button_watch13 = ButtonWatch13::from_button(button, spawner)?;
118
119    // Read the timezone offset, an extra field that WiFi portal saved to flash.
120    let offset_minutes = timezone_field
121        .offset_minutes()?
122        .ok_or(Error::MissingCustomWifiAutoField)?;
123
124    // Create a ClockSync device that knows its timezone offset.
125    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
126    let clock_sync = ClockSync::new(
127        &CLOCK_SYNC_STATIC,
128        stack,
129        offset_minutes,
130        Some(ONE_MINUTE),
131        spawner,
132    );
133
134    // Start in HH:MM mode
135    let mut state = State::HoursMinutes { speed: 1.0 };
136    loop {
137        state = match state {
138            State::HoursMinutes { speed } => {
139                state
140                    .execute_hours_minutes(speed, &clock_sync, button_watch13, &led4)
141                    .await?
142            }
143            State::MinutesSeconds => {
144                state
145                    .execute_minutes_seconds(&clock_sync, button_watch13, &led4)
146                    .await?
147            }
148            State::EditOffset => {
149                state
150                    .execute_edit_offset(&clock_sync, button_watch13, &timezone_field, &led4)
151                    .await?
152            }
153        };
154    }
155}
Source

pub async fn wait_for_tick(&self) -> ClockSyncTick

Wait for and return the next tick after sync.

See the ClockSync struct example for usage.

Examples found in repository?
examples/clock_servos.rs (line 185)
171    async fn execute_hours_minutes(
172        self,
173        speed: f32,
174        clock_sync: &ClockSync,
175        button_watch13: &ButtonWatch13,
176        servo_display: &ServoClockDisplay,
177    ) -> Result<Self> {
178        clock_sync.set_speed(speed).await;
179        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180        servo_display.show_hours_minutes(hours, minutes).await;
181        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182        loop {
183            match select(
184                button_watch13.wait_for_press_duration(),
185                clock_sync.wait_for_tick(),
186            )
187            .await
188            {
189                // Button pushes
190                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192                        return Ok(Self::MinutesSeconds);
193                    }
194                    (PressDuration::Short, _) => {
195                        return Ok(Self::HoursMinutes { speed: 1.0 });
196                    }
197                    (PressDuration::Long, _) => {
198                        return Ok(Self::EditOffset);
199                    }
200                },
201                // Clock tick
202                Either::Second(tick) => {
203                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
204                    servo_display.show_hours_minutes(hours, minutes).await;
205                }
206            }
207        }
208    }
209
210    async fn execute_minutes_seconds(
211        self,
212        clock_sync: &ClockSync,
213        button_watch13: &ButtonWatch13,
214        servo_display: &ServoClockDisplay,
215    ) -> Result<Self> {
216        clock_sync.set_speed(1.0).await;
217        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218        servo_display.show_minutes_seconds(minutes, seconds).await;
219        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220        loop {
221            match select(
222                button_watch13.wait_for_press_duration(),
223                clock_sync.wait_for_tick(),
224            )
225            .await
226            {
227                // Button pushes
228                Either::First(PressDuration::Short) => {
229                    return Ok(Self::HoursMinutes {
230                        speed: FAST_MODE_SPEED,
231                    });
232                }
233                Either::First(PressDuration::Long) => {
234                    return Ok(Self::EditOffset);
235                }
236                // Clock tick
237                Either::Second(tick) => {
238                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239                    servo_display.show_minutes_seconds(minutes, seconds).await;
240                }
241            }
242        }
243    }
More examples
Hide additional examples
examples/clock_led8x12.rs (line 209)
197    async fn execute_hours_minutes(
198        self,
199        speed: f32,
200        clock_sync: &ClockSync,
201        button_watch13: &ButtonWatch13,
202        led8x12: &Led8x12,
203    ) -> Result<Self> {
204        clock_sync.set_speed(speed).await;
205        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206        show_hours_minutes(led8x12, hours, minutes).await?;
207        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208        loop {
209            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210                // Button pushes
211                Either::First(press_duration) => {
212                    info!(
213                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214                        press_duration,
215                        speed.to_bits()
216                    );
217                    match (press_duration, speed.to_bits()) {
218                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219                            info!("HoursMinutes -> MinutesSeconds");
220                            return Ok(Self::MinutesSeconds);
221                        }
222                        (PressDuration::Short, _) => {
223                            info!("HoursMinutes: Resetting speed to 1.0");
224                            return Ok(Self::HoursMinutes { speed: 1.0 });
225                        }
226                        (PressDuration::Long, _) => {
227                            info!("HoursMinutes -> EditOffset");
228                            return Ok(Self::EditOffset);
229                        }
230                    }
231                }
232                // Clock tick
233                Either::Second(tick_event) => {
234                    let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235                    show_hours_minutes(led8x12, hours, minutes).await?;
236                }
237            }
238        }
239    }
240
241    async fn execute_minutes_seconds(
242        self,
243        clock_sync: &ClockSync,
244        button_watch13: &ButtonWatch13,
245        led8x12: &Led8x12,
246    ) -> Result<Self> {
247        clock_sync.set_speed(1.0).await;
248        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249        show_minutes_seconds(led8x12, minutes, seconds).await?;
250        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251        loop {
252            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253                // Button pushes
254                Either::First(press_duration) => {
255                    info!(
256                        "MinutesSeconds: Button press detected: {:?}",
257                        press_duration
258                    );
259                    match press_duration {
260                        PressDuration::Short => {
261                            info!("MinutesSeconds -> HoursMinutes (fast)");
262                            return Ok(Self::HoursMinutes {
263                                speed: FAST_MODE_SPEED,
264                            });
265                        }
266                        PressDuration::Long => {
267                            info!("MinutesSeconds -> EditOffset");
268                            return Ok(Self::EditOffset);
269                        }
270                    }
271                }
272                // Clock tick
273                Either::Second(tick_event) => {
274                    let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275                    show_minutes_seconds(led8x12, minutes, seconds).await?;
276                }
277            }
278        }
279    }
examples/clock_led12x4.rs (line 204)
190    async fn execute_hours_minutes(
191        self,
192        speed: f32,
193        clock_sync: &ClockSync,
194        button_watch13: &ButtonWatch13,
195        led12x4: &Led12x4,
196    ) -> Result<Self> {
197        clock_sync.set_speed(speed).await;
198        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199        show_hours_minutes(led12x4, hours, minutes).await?;
200        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201        loop {
202            match select(
203                button_watch13.wait_for_press_duration(),
204                clock_sync.wait_for_tick(),
205            )
206            .await
207            {
208                // Button pushes
209                Either::First(press_duration) => {
210                    info!(
211                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212                        press_duration,
213                        speed.to_bits()
214                    );
215                    match (press_duration, speed.to_bits()) {
216                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217                            info!("HoursMinutes -> MinutesSeconds");
218                            return Ok(Self::MinutesSeconds);
219                        }
220                        (PressDuration::Short, _) => {
221                            info!("HoursMinutes: Resetting speed to 1.0");
222                            return Ok(Self::HoursMinutes { speed: 1.0 });
223                        }
224                        (PressDuration::Long, _) => {
225                            info!("HoursMinutes -> EditOffset");
226                            return Ok(Self::EditOffset);
227                        }
228                    }
229                }
230                // Clock tick
231                Either::Second(tick) => {
232                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
233                    show_hours_minutes(led12x4, hours, minutes).await?;
234                }
235            }
236        }
237    }
238
239    async fn execute_minutes_seconds(
240        self,
241        clock_sync: &ClockSync,
242        button_watch13: &ButtonWatch13,
243        led12x4: &Led12x4,
244    ) -> Result<Self> {
245        clock_sync.set_speed(1.0).await;
246        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247        show_minutes_seconds(led12x4, minutes, seconds).await?;
248        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249        loop {
250            match select(
251                button_watch13.wait_for_press_duration(),
252                clock_sync.wait_for_tick(),
253            )
254            .await
255            {
256                // Button pushes
257                Either::First(press_duration) => {
258                    info!(
259                        "MinutesSeconds: Button press detected: {:?}",
260                        press_duration
261                    );
262                    match press_duration {
263                        PressDuration::Short => {
264                            info!("MinutesSeconds -> HoursMinutes (fast)");
265                            return Ok(Self::HoursMinutes {
266                                speed: FAST_MODE_SPEED,
267                            });
268                        }
269                        PressDuration::Long => {
270                            info!("MinutesSeconds -> EditOffset");
271                            return Ok(Self::EditOffset);
272                        }
273                    }
274                }
275                // Clock tick
276                Either::Second(tick) => {
277                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278                    show_minutes_seconds(led12x4, minutes, seconds).await?;
279                }
280            }
281        }
282    }
examples/clock_led4.rs (line 190)
168    async fn execute_hours_minutes(
169        self,
170        speed: f32,
171        clock_sync: &ClockSync,
172        button_watch13: &ButtonWatch13,
173        led4: &Led4<'_>,
174    ) -> Result<Self> {
175        clock_sync.set_speed(speed).await;
176        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177        led4.write_text(
178            [
179                Self::tens_hours(hours),
180                Self::ones_digit(hours),
181                Self::tens_digit(minutes),
182                Self::ones_digit(minutes),
183            ],
184            BlinkState::Solid,
185        );
186        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187        loop {
188            match select(
189                button_watch13.wait_for_press_duration(),
190                clock_sync.wait_for_tick(),
191            )
192            .await
193            {
194                // Button pushes
195                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197                        return Ok(Self::MinutesSeconds);
198                    }
199                    (PressDuration::Short, _) => {
200                        return Ok(Self::HoursMinutes { speed: 1.0 });
201                    }
202                    (PressDuration::Long, _) => {
203                        return Ok(Self::EditOffset);
204                    }
205                },
206                // Clock tick
207                Either::Second(tick) => {
208                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
209                    led4.write_text(
210                        [
211                            Self::tens_hours(hours),
212                            Self::ones_digit(hours),
213                            Self::tens_digit(minutes),
214                            Self::ones_digit(minutes),
215                        ],
216                        BlinkState::Solid,
217                    );
218                }
219            }
220        }
221    }
222
223    async fn execute_minutes_seconds(
224        self,
225        clock_sync: &ClockSync,
226        button_watch13: &ButtonWatch13,
227        led4: &Led4<'_>,
228    ) -> Result<Self> {
229        clock_sync.set_speed(1.0).await;
230        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231        led4.write_text(
232            [
233                Self::tens_digit(minutes),
234                Self::ones_digit(minutes),
235                Self::tens_digit(seconds),
236                Self::ones_digit(seconds),
237            ],
238            BlinkState::Solid,
239        );
240        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241        loop {
242            match select(
243                button_watch13.wait_for_press_duration(),
244                clock_sync.wait_for_tick(),
245            )
246            .await
247            {
248                // Button pushes
249                Either::First(PressDuration::Short) => {
250                    return Ok(Self::HoursMinutes {
251                        speed: FAST_MODE_SPEED,
252                    });
253                }
254                Either::First(PressDuration::Long) => {
255                    return Ok(Self::EditOffset);
256                }
257                // Clock tick
258                Either::Second(tick) => {
259                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260                    led4.write_text(
261                        [
262                            Self::tens_digit(minutes),
263                            Self::ones_digit(minutes),
264                            Self::tens_digit(seconds),
265                            Self::ones_digit(seconds),
266                        ],
267                        BlinkState::Solid,
268                    );
269                }
270            }
271        }
272    }
examples/clock_console.rs (line 105)
32async fn inner_main(spawner: Spawner) -> Result<Infallible> {
33    info!("Starting Console Clock with WiFi");
34
35    // Initialize RP2040 peripherals
36    let p = embassy_rp::init(Default::default());
37
38    // Use two blocks of flash storage: Wi-Fi credentials + timezone
39    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
40
41    // Define timezone field for captive portal
42    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
43    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
44
45    // Set up WiFi via captive portal
46    let wifi_auto = WifiAuto::new(
47        p.PIN_23,  // CYW43 power
48        p.PIN_24,  // CYW43 clock
49        p.PIN_25,  // CYW43 chip select
50        p.PIN_29,  // CYW43 data pin
51        p.PIO0,    // CYW43 PIO interface
52        p.DMA_CH0, // CYW43 DMA channel
53        wifi_credentials_flash_block,
54        p.PIN_13, // Reset button pin
55        PressedTo::Ground,
56        "www.picoclock.net",
57        [timezone_field],
58        spawner,
59    )?;
60
61    // Connect to WiFi
62    let (stack, _button) = wifi_auto
63        .connect(|event| async move {
64            match event {
65                WifiAutoEvent::CaptivePortalReady => {
66                    info!("Captive portal ready - connect to WiFi network");
67                }
68                WifiAutoEvent::Connecting {
69                    try_index,
70                    try_count,
71                } => {
72                    info!(
73                        "Connecting to WiFi (attempt {} of {})...",
74                        try_index + 1,
75                        try_count
76                    );
77                }
78                WifiAutoEvent::ConnectionFailed => {
79                    info!("WiFi connection failed!");
80                }
81            }
82            Ok(())
83        })
84        .await?;
85
86    info!("WiFi connected successfully!");
87
88    // Create ClockSync device with timezone from WiFi portal
89    let timezone_offset_minutes = timezone_field
90        .offset_minutes()?
91        .ok_or(Error::MissingCustomWifiAutoField)?;
92    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
93    let clock_sync = ClockSync::new(
94        &CLOCK_SYNC_STATIC,
95        stack,
96        timezone_offset_minutes,
97        Some(ONE_SECOND),
98        spawner,
99    );
100
101    info!("WiFi connected, entering event loop");
102
103    // Main event loop - log time on every tick
104    loop {
105        let tick = clock_sync.wait_for_tick().await;
106        let time_info = tick.local_time;
107        info!(
108            "Current time: {:04}-{:02}-{:02} {:02}:{:02}:{:02}",
109            time_info.year(),
110            u8::from(time_info.month()),
111            time_info.day(),
112            time_info.hour(),
113            time_info.minute(),
114            time_info.second(),
115        );
116    }
117}
examples/clock_lcd.rs (line 87)
34async fn inner_main(spawner: Spawner) -> Result<Infallible> {
35    info!("Starting LCD Clock with WiFi");
36
37    // Initialize RP2040 peripherals
38    let p = embassy_rp::init(Default::default());
39
40    // Initialize CharLcd
41    static CHAR_LCD_STATIC: CharLcdStatic = CharLcd::new_static();
42    let char_lcd = CharLcd::new(&CHAR_LCD_STATIC, p.I2C0, p.PIN_5, p.PIN_4, spawner)?;
43
44    // Use two blocks of flash storage: Wi-Fi credentials + timezone
45    let [wifi_credentials_flash_block, timezone_flash_block] = FlashArray::<2>::new(p.FLASH)?;
46
47    // Define timezone field for captive portal
48    static TIMEZONE_FIELD_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
49    let timezone_field = TimezoneField::new(&TIMEZONE_FIELD_STATIC, timezone_flash_block);
50
51    // Set up WiFi via captive portal
52    let wifi_auto = WifiAuto::new(
53        p.PIN_23,  // CYW43 power
54        p.PIN_24,  // CYW43 clock
55        p.PIN_25,  // CYW43 chip select
56        p.PIN_29,  // CYW43 data pin
57        p.PIO0,    // CYW43 PIO interface
58        p.DMA_CH0, // CYW43 DMA channel
59        wifi_credentials_flash_block,
60        p.PIN_13, // Reset button pin
61        PressedTo::Ground,
62        "www.picoclock.net",
63        [timezone_field],
64        spawner,
65    )?;
66
67    // Connect to WiFi
68    let (stack, _button) = wifi_auto.connect(|_event| async move { Ok(()) }).await?;
69
70    // Create ClockSync device with timezone from WiFi portal
71    let timezone_offset_minutes = timezone_field
72        .offset_minutes()?
73        .ok_or(Error::MissingCustomWifiAutoField)?;
74    static CLOCK_SYNC_STATIC: ClockSyncStatic = ClockSync::new_static();
75    let clock_sync = ClockSync::new(
76        &CLOCK_SYNC_STATIC,
77        stack,
78        timezone_offset_minutes,
79        Some(ONE_SECOND),
80        spawner,
81    );
82
83    info!("Entering main event loop");
84
85    // Main orchestrator loop - owns LCD and displays the clock
86    loop {
87        let tick = clock_sync.wait_for_tick().await;
88        let time_info = tick.local_time;
89        let mut text = String::<64>::new();
90        let (hour12, am_pm) = if time_info.hour() == 0 {
91            (12, "AM")
92        } else if time_info.hour() < 12 {
93            (time_info.hour(), "AM")
94        } else if time_info.hour() == 12 {
95            (12, "PM")
96        } else {
97            #[expect(clippy::arithmetic_side_effects, reason = "hour guaranteed 13-23")]
98            {
99                (time_info.hour() - 12, "PM")
100            }
101        };
102        fmt::Write::write_fmt(
103            &mut text,
104            format_args!(
105                "{:2}:{:02}:{:02} {}\n{:04}-{:02}-{:02}",
106                hour12,
107                time_info.minute(),
108                time_info.second(),
109                am_pm,
110                time_info.year(),
111                u8::from(time_info.month()),
112                time_info.day()
113            ),
114        )
115        .map_err(|_| Error::FormatError)?;
116        char_lcd.write_text(text, 0).await;
117    }
118}
Source

pub fn now_local(&self) -> OffsetDateTime

Get the current local time without waiting for a tick.

Examples found in repository?
examples/clock_servos.rs (line 179)
171    async fn execute_hours_minutes(
172        self,
173        speed: f32,
174        clock_sync: &ClockSync,
175        button_watch13: &ButtonWatch13,
176        servo_display: &ServoClockDisplay,
177    ) -> Result<Self> {
178        clock_sync.set_speed(speed).await;
179        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180        servo_display.show_hours_minutes(hours, minutes).await;
181        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182        loop {
183            match select(
184                button_watch13.wait_for_press_duration(),
185                clock_sync.wait_for_tick(),
186            )
187            .await
188            {
189                // Button pushes
190                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192                        return Ok(Self::MinutesSeconds);
193                    }
194                    (PressDuration::Short, _) => {
195                        return Ok(Self::HoursMinutes { speed: 1.0 });
196                    }
197                    (PressDuration::Long, _) => {
198                        return Ok(Self::EditOffset);
199                    }
200                },
201                // Clock tick
202                Either::Second(tick) => {
203                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
204                    servo_display.show_hours_minutes(hours, minutes).await;
205                }
206            }
207        }
208    }
209
210    async fn execute_minutes_seconds(
211        self,
212        clock_sync: &ClockSync,
213        button_watch13: &ButtonWatch13,
214        servo_display: &ServoClockDisplay,
215    ) -> Result<Self> {
216        clock_sync.set_speed(1.0).await;
217        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218        servo_display.show_minutes_seconds(minutes, seconds).await;
219        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220        loop {
221            match select(
222                button_watch13.wait_for_press_duration(),
223                clock_sync.wait_for_tick(),
224            )
225            .await
226            {
227                // Button pushes
228                Either::First(PressDuration::Short) => {
229                    return Ok(Self::HoursMinutes {
230                        speed: FAST_MODE_SPEED,
231                    });
232                }
233                Either::First(PressDuration::Long) => {
234                    return Ok(Self::EditOffset);
235                }
236                // Clock tick
237                Either::Second(tick) => {
238                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239                    servo_display.show_minutes_seconds(minutes, seconds).await;
240                }
241            }
242        }
243    }
244
245    async fn execute_edit_offset(
246        self,
247        clock_sync: &ClockSync,
248        button_watch13: &ButtonWatch13,
249        timezone_field: &TimezoneField,
250        servo_display: &ServoClockDisplay,
251    ) -> Result<Self> {
252        info!("Entering edit offset mode");
253        clock_sync.set_speed(1.0).await;
254
255        // Show current hours and minutes
256        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257        servo_display
258            .show_hours_minutes_indicator(hours, minutes)
259            .await;
260        // Add a gentle wiggle on the bottom servo to signal edit mode.
261        const WIGGLE: [(u16, Duration); 2] = [
262            (80, Duration::from_millis(250)),
263            (100, Duration::from_millis(250)),
264        ];
265        servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267        // Get the current offset minutes from clock (source of truth)
268        let mut offset_minutes = clock_sync.offset_minutes();
269        info!("Current offset: {} minutes", offset_minutes);
270
271        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272        loop {
273            info!("Waiting for button press in edit mode");
274            match button_watch13.wait_for_press_duration().await {
275                PressDuration::Short => {
276                    info!("Short press detected - incrementing offset");
277                    // Increment the offset by 1 hour
278                    offset_minutes += 60;
279                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280                    if offset_minutes >= ONE_DAY_MINUTES {
281                        offset_minutes -= ONE_DAY_MINUTES;
282                    }
283                    clock_sync.set_offset_minutes(offset_minutes).await;
284                    info!("New offset: {} minutes", offset_minutes);
285
286                    // Update display (atomic already updated, can use now_local)
287                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288                    info!(
289                        "Updated time after offset change: {:02}:{:02}",
290                        hours, minutes
291                    );
292                    servo_display
293                        .show_hours_minutes_indicator(hours, minutes)
294                        .await;
295                    servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296                }
297                PressDuration::Long => {
298                    info!("Long press detected - saving and exiting edit mode");
299                    // Save to flash and exit edit mode
300                    timezone_field.set_offset_minutes(offset_minutes)?;
301                    info!("Offset saved to flash: {} minutes", offset_minutes);
302                    return Ok(Self::HoursMinutes { speed: 1.0 });
303                }
304            }
305        }
306    }
More examples
Hide additional examples
examples/clock_led8x12.rs (line 205)
197    async fn execute_hours_minutes(
198        self,
199        speed: f32,
200        clock_sync: &ClockSync,
201        button_watch13: &ButtonWatch13,
202        led8x12: &Led8x12,
203    ) -> Result<Self> {
204        clock_sync.set_speed(speed).await;
205        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206        show_hours_minutes(led8x12, hours, minutes).await?;
207        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208        loop {
209            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210                // Button pushes
211                Either::First(press_duration) => {
212                    info!(
213                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214                        press_duration,
215                        speed.to_bits()
216                    );
217                    match (press_duration, speed.to_bits()) {
218                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219                            info!("HoursMinutes -> MinutesSeconds");
220                            return Ok(Self::MinutesSeconds);
221                        }
222                        (PressDuration::Short, _) => {
223                            info!("HoursMinutes: Resetting speed to 1.0");
224                            return Ok(Self::HoursMinutes { speed: 1.0 });
225                        }
226                        (PressDuration::Long, _) => {
227                            info!("HoursMinutes -> EditOffset");
228                            return Ok(Self::EditOffset);
229                        }
230                    }
231                }
232                // Clock tick
233                Either::Second(tick_event) => {
234                    let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235                    show_hours_minutes(led8x12, hours, minutes).await?;
236                }
237            }
238        }
239    }
240
241    async fn execute_minutes_seconds(
242        self,
243        clock_sync: &ClockSync,
244        button_watch13: &ButtonWatch13,
245        led8x12: &Led8x12,
246    ) -> Result<Self> {
247        clock_sync.set_speed(1.0).await;
248        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249        show_minutes_seconds(led8x12, minutes, seconds).await?;
250        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251        loop {
252            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253                // Button pushes
254                Either::First(press_duration) => {
255                    info!(
256                        "MinutesSeconds: Button press detected: {:?}",
257                        press_duration
258                    );
259                    match press_duration {
260                        PressDuration::Short => {
261                            info!("MinutesSeconds -> HoursMinutes (fast)");
262                            return Ok(Self::HoursMinutes {
263                                speed: FAST_MODE_SPEED,
264                            });
265                        }
266                        PressDuration::Long => {
267                            info!("MinutesSeconds -> EditOffset");
268                            return Ok(Self::EditOffset);
269                        }
270                    }
271                }
272                // Clock tick
273                Either::Second(tick_event) => {
274                    let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275                    show_minutes_seconds(led8x12, minutes, seconds).await?;
276                }
277            }
278        }
279    }
280
281    async fn execute_edit_offset(
282        self,
283        clock_sync: &ClockSync,
284        button_watch13: &ButtonWatch13,
285        timezone_field: &TimezoneField,
286        led8x12: &Led8x12,
287    ) -> Result<Self> {
288        info!("Entering edit offset mode");
289        clock_sync.set_speed(1.0).await;
290
291        // Blink current hours and minutes with edit color accent.
292        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293        show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        loop {
301            info!("Waiting for button press in edit mode");
302            match button_watch13.wait_for_press_duration().await {
303                PressDuration::Short => {
304                    info!("Short press detected - incrementing offset");
305                    // Increment the offset by 1 hour
306                    offset_minutes += 60;
307                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308                    if offset_minutes >= ONE_DAY_MINUTES {
309                        offset_minutes -= ONE_DAY_MINUTES;
310                    }
311                    clock_sync.set_offset_minutes(offset_minutes).await;
312                    info!("New offset: {} minutes", offset_minutes);
313
314                    // Update display
315                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316                    info!(
317                        "Updated time after offset change: {:02}:{:02}",
318                        hours, minutes
319                    );
320                    show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321                }
322                PressDuration::Long => {
323                    info!("Long press detected - saving and exiting edit mode");
324                    // Save to flash and exit edit mode
325                    timezone_field.set_offset_minutes(offset_minutes)?;
326                    info!("Offset saved to flash: {} minutes", offset_minutes);
327                    return Ok(Self::HoursMinutes { speed: 1.0 });
328                }
329            }
330        }
331    }
examples/clock_led12x4.rs (line 198)
190    async fn execute_hours_minutes(
191        self,
192        speed: f32,
193        clock_sync: &ClockSync,
194        button_watch13: &ButtonWatch13,
195        led12x4: &Led12x4,
196    ) -> Result<Self> {
197        clock_sync.set_speed(speed).await;
198        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199        show_hours_minutes(led12x4, hours, minutes).await?;
200        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201        loop {
202            match select(
203                button_watch13.wait_for_press_duration(),
204                clock_sync.wait_for_tick(),
205            )
206            .await
207            {
208                // Button pushes
209                Either::First(press_duration) => {
210                    info!(
211                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212                        press_duration,
213                        speed.to_bits()
214                    );
215                    match (press_duration, speed.to_bits()) {
216                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217                            info!("HoursMinutes -> MinutesSeconds");
218                            return Ok(Self::MinutesSeconds);
219                        }
220                        (PressDuration::Short, _) => {
221                            info!("HoursMinutes: Resetting speed to 1.0");
222                            return Ok(Self::HoursMinutes { speed: 1.0 });
223                        }
224                        (PressDuration::Long, _) => {
225                            info!("HoursMinutes -> EditOffset");
226                            return Ok(Self::EditOffset);
227                        }
228                    }
229                }
230                // Clock tick
231                Either::Second(tick) => {
232                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
233                    show_hours_minutes(led12x4, hours, minutes).await?;
234                }
235            }
236        }
237    }
238
239    async fn execute_minutes_seconds(
240        self,
241        clock_sync: &ClockSync,
242        button_watch13: &ButtonWatch13,
243        led12x4: &Led12x4,
244    ) -> Result<Self> {
245        clock_sync.set_speed(1.0).await;
246        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247        show_minutes_seconds(led12x4, minutes, seconds).await?;
248        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249        loop {
250            match select(
251                button_watch13.wait_for_press_duration(),
252                clock_sync.wait_for_tick(),
253            )
254            .await
255            {
256                // Button pushes
257                Either::First(press_duration) => {
258                    info!(
259                        "MinutesSeconds: Button press detected: {:?}",
260                        press_duration
261                    );
262                    match press_duration {
263                        PressDuration::Short => {
264                            info!("MinutesSeconds -> HoursMinutes (fast)");
265                            return Ok(Self::HoursMinutes {
266                                speed: FAST_MODE_SPEED,
267                            });
268                        }
269                        PressDuration::Long => {
270                            info!("MinutesSeconds -> EditOffset");
271                            return Ok(Self::EditOffset);
272                        }
273                    }
274                }
275                // Clock tick
276                Either::Second(tick) => {
277                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278                    show_minutes_seconds(led12x4, minutes, seconds).await?;
279                }
280            }
281        }
282    }
283
284    async fn execute_edit_offset(
285        self,
286        clock_sync: &ClockSync,
287        button_watch13: &ButtonWatch13,
288        timezone_field: &TimezoneField,
289        led12x4: &Led12x4,
290    ) -> Result<Self> {
291        info!("Entering edit offset mode");
292        clock_sync.set_speed(1.0).await;
293
294        // Blink current hours and minutes with edit color accent.
295        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296        show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298        // Get the current offset minutes from clock (source of truth)
299        let mut offset_minutes = clock_sync.offset_minutes();
300        info!("Current offset: {} minutes", offset_minutes);
301
302        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303        loop {
304            info!("Waiting for button press in edit mode");
305            match button_watch13.wait_for_press_duration().await {
306                PressDuration::Short => {
307                    info!("Short press detected - incrementing offset");
308                    // Increment the offset by 1 hour
309                    offset_minutes += 60;
310                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311                    if offset_minutes >= ONE_DAY_MINUTES {
312                        offset_minutes -= ONE_DAY_MINUTES;
313                    }
314                    clock_sync.set_offset_minutes(offset_minutes).await;
315                    info!("New offset: {} minutes", offset_minutes);
316
317                    // Update display (atomic already updated, can use now_local)
318                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319                    info!(
320                        "Updated time after offset change: {:02}:{:02}",
321                        hours, minutes
322                    );
323                    show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324                }
325                PressDuration::Long => {
326                    info!("Long press detected - saving and exiting edit mode");
327                    // Save to flash and exit edit mode
328                    timezone_field.set_offset_minutes(offset_minutes)?;
329                    info!("Offset saved to flash: {} minutes", offset_minutes);
330                    return Ok(Self::HoursMinutes { speed: 1.0 });
331                }
332            }
333        }
334    }
examples/clock_led4.rs (line 176)
168    async fn execute_hours_minutes(
169        self,
170        speed: f32,
171        clock_sync: &ClockSync,
172        button_watch13: &ButtonWatch13,
173        led4: &Led4<'_>,
174    ) -> Result<Self> {
175        clock_sync.set_speed(speed).await;
176        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177        led4.write_text(
178            [
179                Self::tens_hours(hours),
180                Self::ones_digit(hours),
181                Self::tens_digit(minutes),
182                Self::ones_digit(minutes),
183            ],
184            BlinkState::Solid,
185        );
186        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187        loop {
188            match select(
189                button_watch13.wait_for_press_duration(),
190                clock_sync.wait_for_tick(),
191            )
192            .await
193            {
194                // Button pushes
195                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197                        return Ok(Self::MinutesSeconds);
198                    }
199                    (PressDuration::Short, _) => {
200                        return Ok(Self::HoursMinutes { speed: 1.0 });
201                    }
202                    (PressDuration::Long, _) => {
203                        return Ok(Self::EditOffset);
204                    }
205                },
206                // Clock tick
207                Either::Second(tick) => {
208                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
209                    led4.write_text(
210                        [
211                            Self::tens_hours(hours),
212                            Self::ones_digit(hours),
213                            Self::tens_digit(minutes),
214                            Self::ones_digit(minutes),
215                        ],
216                        BlinkState::Solid,
217                    );
218                }
219            }
220        }
221    }
222
223    async fn execute_minutes_seconds(
224        self,
225        clock_sync: &ClockSync,
226        button_watch13: &ButtonWatch13,
227        led4: &Led4<'_>,
228    ) -> Result<Self> {
229        clock_sync.set_speed(1.0).await;
230        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231        led4.write_text(
232            [
233                Self::tens_digit(minutes),
234                Self::ones_digit(minutes),
235                Self::tens_digit(seconds),
236                Self::ones_digit(seconds),
237            ],
238            BlinkState::Solid,
239        );
240        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241        loop {
242            match select(
243                button_watch13.wait_for_press_duration(),
244                clock_sync.wait_for_tick(),
245            )
246            .await
247            {
248                // Button pushes
249                Either::First(PressDuration::Short) => {
250                    return Ok(Self::HoursMinutes {
251                        speed: FAST_MODE_SPEED,
252                    });
253                }
254                Either::First(PressDuration::Long) => {
255                    return Ok(Self::EditOffset);
256                }
257                // Clock tick
258                Either::Second(tick) => {
259                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260                    led4.write_text(
261                        [
262                            Self::tens_digit(minutes),
263                            Self::ones_digit(minutes),
264                            Self::tens_digit(seconds),
265                            Self::ones_digit(seconds),
266                        ],
267                        BlinkState::Solid,
268                    );
269                }
270            }
271        }
272    }
273
274    async fn execute_edit_offset(
275        self,
276        clock_sync: &ClockSync,
277        button_watch13: &ButtonWatch13,
278        timezone_field: &TimezoneField,
279        led4: &Led4<'_>,
280    ) -> Result<Self> {
281        info!("Entering edit offset mode");
282
283        // Blink current hours and minutes
284        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285        led4.write_text(
286            [
287                Self::tens_hours(hours),
288                Self::ones_digit(hours),
289                Self::tens_digit(minutes),
290                Self::ones_digit(minutes),
291            ],
292            BlinkState::BlinkingAndOn,
293        );
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        clock_sync.set_speed(1.0).await;
301        loop {
302            info!("Waiting for button press in edit mode");
303            match button_watch13.wait_for_press_duration().await {
304                PressDuration::Short => {
305                    info!("Short press detected - incrementing offset");
306                    // Increment the offset by 1 hour
307                    offset_minutes += 60;
308                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309                    if offset_minutes >= ONE_DAY_MINUTES {
310                        offset_minutes -= ONE_DAY_MINUTES;
311                    }
312                    clock_sync.set_offset_minutes(offset_minutes).await;
313                    info!("New offset: {} minutes", offset_minutes);
314
315                    // Update display (atomic already updated, can use now_local)
316                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317                    info!(
318                        "Updated time after offset change: {:02}:{:02}",
319                        hours, minutes
320                    );
321                    led4.write_text(
322                        [
323                            Self::tens_hours(hours),
324                            Self::ones_digit(hours),
325                            Self::tens_digit(minutes),
326                            Self::ones_digit(minutes),
327                        ],
328                        BlinkState::BlinkingAndOn,
329                    );
330                }
331                PressDuration::Long => {
332                    info!("Long press detected - saving and exiting edit mode");
333                    // Save to flash and exit edit mode
334                    timezone_field.set_offset_minutes(offset_minutes)?;
335                    info!("Offset saved to flash: {} minutes", offset_minutes);
336                    return Ok(Self::HoursMinutes { speed: 1.0 });
337                }
338            }
339        }
340    }
Source

pub async fn set_offset_minutes(&self, minutes: i32)

Update the UTC offset used for local time.

Examples found in repository?
examples/clock_led8x12.rs (line 311)
281    async fn execute_edit_offset(
282        self,
283        clock_sync: &ClockSync,
284        button_watch13: &ButtonWatch13,
285        timezone_field: &TimezoneField,
286        led8x12: &Led8x12,
287    ) -> Result<Self> {
288        info!("Entering edit offset mode");
289        clock_sync.set_speed(1.0).await;
290
291        // Blink current hours and minutes with edit color accent.
292        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293        show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        loop {
301            info!("Waiting for button press in edit mode");
302            match button_watch13.wait_for_press_duration().await {
303                PressDuration::Short => {
304                    info!("Short press detected - incrementing offset");
305                    // Increment the offset by 1 hour
306                    offset_minutes += 60;
307                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308                    if offset_minutes >= ONE_DAY_MINUTES {
309                        offset_minutes -= ONE_DAY_MINUTES;
310                    }
311                    clock_sync.set_offset_minutes(offset_minutes).await;
312                    info!("New offset: {} minutes", offset_minutes);
313
314                    // Update display
315                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316                    info!(
317                        "Updated time after offset change: {:02}:{:02}",
318                        hours, minutes
319                    );
320                    show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321                }
322                PressDuration::Long => {
323                    info!("Long press detected - saving and exiting edit mode");
324                    // Save to flash and exit edit mode
325                    timezone_field.set_offset_minutes(offset_minutes)?;
326                    info!("Offset saved to flash: {} minutes", offset_minutes);
327                    return Ok(Self::HoursMinutes { speed: 1.0 });
328                }
329            }
330        }
331    }
More examples
Hide additional examples
examples/clock_led12x4.rs (line 314)
284    async fn execute_edit_offset(
285        self,
286        clock_sync: &ClockSync,
287        button_watch13: &ButtonWatch13,
288        timezone_field: &TimezoneField,
289        led12x4: &Led12x4,
290    ) -> Result<Self> {
291        info!("Entering edit offset mode");
292        clock_sync.set_speed(1.0).await;
293
294        // Blink current hours and minutes with edit color accent.
295        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296        show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298        // Get the current offset minutes from clock (source of truth)
299        let mut offset_minutes = clock_sync.offset_minutes();
300        info!("Current offset: {} minutes", offset_minutes);
301
302        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303        loop {
304            info!("Waiting for button press in edit mode");
305            match button_watch13.wait_for_press_duration().await {
306                PressDuration::Short => {
307                    info!("Short press detected - incrementing offset");
308                    // Increment the offset by 1 hour
309                    offset_minutes += 60;
310                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311                    if offset_minutes >= ONE_DAY_MINUTES {
312                        offset_minutes -= ONE_DAY_MINUTES;
313                    }
314                    clock_sync.set_offset_minutes(offset_minutes).await;
315                    info!("New offset: {} minutes", offset_minutes);
316
317                    // Update display (atomic already updated, can use now_local)
318                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319                    info!(
320                        "Updated time after offset change: {:02}:{:02}",
321                        hours, minutes
322                    );
323                    show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324                }
325                PressDuration::Long => {
326                    info!("Long press detected - saving and exiting edit mode");
327                    // Save to flash and exit edit mode
328                    timezone_field.set_offset_minutes(offset_minutes)?;
329                    info!("Offset saved to flash: {} minutes", offset_minutes);
330                    return Ok(Self::HoursMinutes { speed: 1.0 });
331                }
332            }
333        }
334    }
examples/clock_servos.rs (line 283)
245    async fn execute_edit_offset(
246        self,
247        clock_sync: &ClockSync,
248        button_watch13: &ButtonWatch13,
249        timezone_field: &TimezoneField,
250        servo_display: &ServoClockDisplay,
251    ) -> Result<Self> {
252        info!("Entering edit offset mode");
253        clock_sync.set_speed(1.0).await;
254
255        // Show current hours and minutes
256        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257        servo_display
258            .show_hours_minutes_indicator(hours, minutes)
259            .await;
260        // Add a gentle wiggle on the bottom servo to signal edit mode.
261        const WIGGLE: [(u16, Duration); 2] = [
262            (80, Duration::from_millis(250)),
263            (100, Duration::from_millis(250)),
264        ];
265        servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267        // Get the current offset minutes from clock (source of truth)
268        let mut offset_minutes = clock_sync.offset_minutes();
269        info!("Current offset: {} minutes", offset_minutes);
270
271        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272        loop {
273            info!("Waiting for button press in edit mode");
274            match button_watch13.wait_for_press_duration().await {
275                PressDuration::Short => {
276                    info!("Short press detected - incrementing offset");
277                    // Increment the offset by 1 hour
278                    offset_minutes += 60;
279                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280                    if offset_minutes >= ONE_DAY_MINUTES {
281                        offset_minutes -= ONE_DAY_MINUTES;
282                    }
283                    clock_sync.set_offset_minutes(offset_minutes).await;
284                    info!("New offset: {} minutes", offset_minutes);
285
286                    // Update display (atomic already updated, can use now_local)
287                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288                    info!(
289                        "Updated time after offset change: {:02}:{:02}",
290                        hours, minutes
291                    );
292                    servo_display
293                        .show_hours_minutes_indicator(hours, minutes)
294                        .await;
295                    servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296                }
297                PressDuration::Long => {
298                    info!("Long press detected - saving and exiting edit mode");
299                    // Save to flash and exit edit mode
300                    timezone_field.set_offset_minutes(offset_minutes)?;
301                    info!("Offset saved to flash: {} minutes", offset_minutes);
302                    return Ok(Self::HoursMinutes { speed: 1.0 });
303                }
304            }
305        }
306    }
examples/clock_led4.rs (line 312)
274    async fn execute_edit_offset(
275        self,
276        clock_sync: &ClockSync,
277        button_watch13: &ButtonWatch13,
278        timezone_field: &TimezoneField,
279        led4: &Led4<'_>,
280    ) -> Result<Self> {
281        info!("Entering edit offset mode");
282
283        // Blink current hours and minutes
284        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285        led4.write_text(
286            [
287                Self::tens_hours(hours),
288                Self::ones_digit(hours),
289                Self::tens_digit(minutes),
290                Self::ones_digit(minutes),
291            ],
292            BlinkState::BlinkingAndOn,
293        );
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        clock_sync.set_speed(1.0).await;
301        loop {
302            info!("Waiting for button press in edit mode");
303            match button_watch13.wait_for_press_duration().await {
304                PressDuration::Short => {
305                    info!("Short press detected - incrementing offset");
306                    // Increment the offset by 1 hour
307                    offset_minutes += 60;
308                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309                    if offset_minutes >= ONE_DAY_MINUTES {
310                        offset_minutes -= ONE_DAY_MINUTES;
311                    }
312                    clock_sync.set_offset_minutes(offset_minutes).await;
313                    info!("New offset: {} minutes", offset_minutes);
314
315                    // Update display (atomic already updated, can use now_local)
316                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317                    info!(
318                        "Updated time after offset change: {:02}:{:02}",
319                        hours, minutes
320                    );
321                    led4.write_text(
322                        [
323                            Self::tens_hours(hours),
324                            Self::ones_digit(hours),
325                            Self::tens_digit(minutes),
326                            Self::ones_digit(minutes),
327                        ],
328                        BlinkState::BlinkingAndOn,
329                    );
330                }
331                PressDuration::Long => {
332                    info!("Long press detected - saving and exiting edit mode");
333                    // Save to flash and exit edit mode
334                    timezone_field.set_offset_minutes(offset_minutes)?;
335                    info!("Offset saved to flash: {} minutes", offset_minutes);
336                    return Ok(Self::HoursMinutes { speed: 1.0 });
337                }
338            }
339        }
340    }
Source

pub fn offset_minutes(&self) -> i32

Get the current UTC offset in minutes.

Examples found in repository?
examples/clock_led8x12.rs (line 296)
281    async fn execute_edit_offset(
282        self,
283        clock_sync: &ClockSync,
284        button_watch13: &ButtonWatch13,
285        timezone_field: &TimezoneField,
286        led8x12: &Led8x12,
287    ) -> Result<Self> {
288        info!("Entering edit offset mode");
289        clock_sync.set_speed(1.0).await;
290
291        // Blink current hours and minutes with edit color accent.
292        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293        show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        loop {
301            info!("Waiting for button press in edit mode");
302            match button_watch13.wait_for_press_duration().await {
303                PressDuration::Short => {
304                    info!("Short press detected - incrementing offset");
305                    // Increment the offset by 1 hour
306                    offset_minutes += 60;
307                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308                    if offset_minutes >= ONE_DAY_MINUTES {
309                        offset_minutes -= ONE_DAY_MINUTES;
310                    }
311                    clock_sync.set_offset_minutes(offset_minutes).await;
312                    info!("New offset: {} minutes", offset_minutes);
313
314                    // Update display
315                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316                    info!(
317                        "Updated time after offset change: {:02}:{:02}",
318                        hours, minutes
319                    );
320                    show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321                }
322                PressDuration::Long => {
323                    info!("Long press detected - saving and exiting edit mode");
324                    // Save to flash and exit edit mode
325                    timezone_field.set_offset_minutes(offset_minutes)?;
326                    info!("Offset saved to flash: {} minutes", offset_minutes);
327                    return Ok(Self::HoursMinutes { speed: 1.0 });
328                }
329            }
330        }
331    }
More examples
Hide additional examples
examples/clock_led12x4.rs (line 299)
284    async fn execute_edit_offset(
285        self,
286        clock_sync: &ClockSync,
287        button_watch13: &ButtonWatch13,
288        timezone_field: &TimezoneField,
289        led12x4: &Led12x4,
290    ) -> Result<Self> {
291        info!("Entering edit offset mode");
292        clock_sync.set_speed(1.0).await;
293
294        // Blink current hours and minutes with edit color accent.
295        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296        show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298        // Get the current offset minutes from clock (source of truth)
299        let mut offset_minutes = clock_sync.offset_minutes();
300        info!("Current offset: {} minutes", offset_minutes);
301
302        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303        loop {
304            info!("Waiting for button press in edit mode");
305            match button_watch13.wait_for_press_duration().await {
306                PressDuration::Short => {
307                    info!("Short press detected - incrementing offset");
308                    // Increment the offset by 1 hour
309                    offset_minutes += 60;
310                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311                    if offset_minutes >= ONE_DAY_MINUTES {
312                        offset_minutes -= ONE_DAY_MINUTES;
313                    }
314                    clock_sync.set_offset_minutes(offset_minutes).await;
315                    info!("New offset: {} minutes", offset_minutes);
316
317                    // Update display (atomic already updated, can use now_local)
318                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319                    info!(
320                        "Updated time after offset change: {:02}:{:02}",
321                        hours, minutes
322                    );
323                    show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324                }
325                PressDuration::Long => {
326                    info!("Long press detected - saving and exiting edit mode");
327                    // Save to flash and exit edit mode
328                    timezone_field.set_offset_minutes(offset_minutes)?;
329                    info!("Offset saved to flash: {} minutes", offset_minutes);
330                    return Ok(Self::HoursMinutes { speed: 1.0 });
331                }
332            }
333        }
334    }
examples/clock_servos.rs (line 268)
245    async fn execute_edit_offset(
246        self,
247        clock_sync: &ClockSync,
248        button_watch13: &ButtonWatch13,
249        timezone_field: &TimezoneField,
250        servo_display: &ServoClockDisplay,
251    ) -> Result<Self> {
252        info!("Entering edit offset mode");
253        clock_sync.set_speed(1.0).await;
254
255        // Show current hours and minutes
256        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257        servo_display
258            .show_hours_minutes_indicator(hours, minutes)
259            .await;
260        // Add a gentle wiggle on the bottom servo to signal edit mode.
261        const WIGGLE: [(u16, Duration); 2] = [
262            (80, Duration::from_millis(250)),
263            (100, Duration::from_millis(250)),
264        ];
265        servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267        // Get the current offset minutes from clock (source of truth)
268        let mut offset_minutes = clock_sync.offset_minutes();
269        info!("Current offset: {} minutes", offset_minutes);
270
271        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272        loop {
273            info!("Waiting for button press in edit mode");
274            match button_watch13.wait_for_press_duration().await {
275                PressDuration::Short => {
276                    info!("Short press detected - incrementing offset");
277                    // Increment the offset by 1 hour
278                    offset_minutes += 60;
279                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280                    if offset_minutes >= ONE_DAY_MINUTES {
281                        offset_minutes -= ONE_DAY_MINUTES;
282                    }
283                    clock_sync.set_offset_minutes(offset_minutes).await;
284                    info!("New offset: {} minutes", offset_minutes);
285
286                    // Update display (atomic already updated, can use now_local)
287                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288                    info!(
289                        "Updated time after offset change: {:02}:{:02}",
290                        hours, minutes
291                    );
292                    servo_display
293                        .show_hours_minutes_indicator(hours, minutes)
294                        .await;
295                    servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296                }
297                PressDuration::Long => {
298                    info!("Long press detected - saving and exiting edit mode");
299                    // Save to flash and exit edit mode
300                    timezone_field.set_offset_minutes(offset_minutes)?;
301                    info!("Offset saved to flash: {} minutes", offset_minutes);
302                    return Ok(Self::HoursMinutes { speed: 1.0 });
303                }
304            }
305        }
306    }
examples/clock_led4.rs (line 296)
274    async fn execute_edit_offset(
275        self,
276        clock_sync: &ClockSync,
277        button_watch13: &ButtonWatch13,
278        timezone_field: &TimezoneField,
279        led4: &Led4<'_>,
280    ) -> Result<Self> {
281        info!("Entering edit offset mode");
282
283        // Blink current hours and minutes
284        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285        led4.write_text(
286            [
287                Self::tens_hours(hours),
288                Self::ones_digit(hours),
289                Self::tens_digit(minutes),
290                Self::ones_digit(minutes),
291            ],
292            BlinkState::BlinkingAndOn,
293        );
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        clock_sync.set_speed(1.0).await;
301        loop {
302            info!("Waiting for button press in edit mode");
303            match button_watch13.wait_for_press_duration().await {
304                PressDuration::Short => {
305                    info!("Short press detected - incrementing offset");
306                    // Increment the offset by 1 hour
307                    offset_minutes += 60;
308                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309                    if offset_minutes >= ONE_DAY_MINUTES {
310                        offset_minutes -= ONE_DAY_MINUTES;
311                    }
312                    clock_sync.set_offset_minutes(offset_minutes).await;
313                    info!("New offset: {} minutes", offset_minutes);
314
315                    // Update display (atomic already updated, can use now_local)
316                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317                    info!(
318                        "Updated time after offset change: {:02}:{:02}",
319                        hours, minutes
320                    );
321                    led4.write_text(
322                        [
323                            Self::tens_hours(hours),
324                            Self::ones_digit(hours),
325                            Self::tens_digit(minutes),
326                            Self::ones_digit(minutes),
327                        ],
328                        BlinkState::BlinkingAndOn,
329                    );
330                }
331                PressDuration::Long => {
332                    info!("Long press detected - saving and exiting edit mode");
333                    // Save to flash and exit edit mode
334                    timezone_field.set_offset_minutes(offset_minutes)?;
335                    info!("Offset saved to flash: {} minutes", offset_minutes);
336                    return Ok(Self::HoursMinutes { speed: 1.0 });
337                }
338            }
339        }
340    }
Source

pub async fn set_tick_interval(&self, interval: Option<Duration>)

Set the tick interval. Use None to disable periodic ticks.

Examples found in repository?
examples/clock_servos.rs (line 181)
171    async fn execute_hours_minutes(
172        self,
173        speed: f32,
174        clock_sync: &ClockSync,
175        button_watch13: &ButtonWatch13,
176        servo_display: &ServoClockDisplay,
177    ) -> Result<Self> {
178        clock_sync.set_speed(speed).await;
179        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180        servo_display.show_hours_minutes(hours, minutes).await;
181        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182        loop {
183            match select(
184                button_watch13.wait_for_press_duration(),
185                clock_sync.wait_for_tick(),
186            )
187            .await
188            {
189                // Button pushes
190                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192                        return Ok(Self::MinutesSeconds);
193                    }
194                    (PressDuration::Short, _) => {
195                        return Ok(Self::HoursMinutes { speed: 1.0 });
196                    }
197                    (PressDuration::Long, _) => {
198                        return Ok(Self::EditOffset);
199                    }
200                },
201                // Clock tick
202                Either::Second(tick) => {
203                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
204                    servo_display.show_hours_minutes(hours, minutes).await;
205                }
206            }
207        }
208    }
209
210    async fn execute_minutes_seconds(
211        self,
212        clock_sync: &ClockSync,
213        button_watch13: &ButtonWatch13,
214        servo_display: &ServoClockDisplay,
215    ) -> Result<Self> {
216        clock_sync.set_speed(1.0).await;
217        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218        servo_display.show_minutes_seconds(minutes, seconds).await;
219        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220        loop {
221            match select(
222                button_watch13.wait_for_press_duration(),
223                clock_sync.wait_for_tick(),
224            )
225            .await
226            {
227                // Button pushes
228                Either::First(PressDuration::Short) => {
229                    return Ok(Self::HoursMinutes {
230                        speed: FAST_MODE_SPEED,
231                    });
232                }
233                Either::First(PressDuration::Long) => {
234                    return Ok(Self::EditOffset);
235                }
236                // Clock tick
237                Either::Second(tick) => {
238                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239                    servo_display.show_minutes_seconds(minutes, seconds).await;
240                }
241            }
242        }
243    }
244
245    async fn execute_edit_offset(
246        self,
247        clock_sync: &ClockSync,
248        button_watch13: &ButtonWatch13,
249        timezone_field: &TimezoneField,
250        servo_display: &ServoClockDisplay,
251    ) -> Result<Self> {
252        info!("Entering edit offset mode");
253        clock_sync.set_speed(1.0).await;
254
255        // Show current hours and minutes
256        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257        servo_display
258            .show_hours_minutes_indicator(hours, minutes)
259            .await;
260        // Add a gentle wiggle on the bottom servo to signal edit mode.
261        const WIGGLE: [(u16, Duration); 2] = [
262            (80, Duration::from_millis(250)),
263            (100, Duration::from_millis(250)),
264        ];
265        servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267        // Get the current offset minutes from clock (source of truth)
268        let mut offset_minutes = clock_sync.offset_minutes();
269        info!("Current offset: {} minutes", offset_minutes);
270
271        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272        loop {
273            info!("Waiting for button press in edit mode");
274            match button_watch13.wait_for_press_duration().await {
275                PressDuration::Short => {
276                    info!("Short press detected - incrementing offset");
277                    // Increment the offset by 1 hour
278                    offset_minutes += 60;
279                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280                    if offset_minutes >= ONE_DAY_MINUTES {
281                        offset_minutes -= ONE_DAY_MINUTES;
282                    }
283                    clock_sync.set_offset_minutes(offset_minutes).await;
284                    info!("New offset: {} minutes", offset_minutes);
285
286                    // Update display (atomic already updated, can use now_local)
287                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288                    info!(
289                        "Updated time after offset change: {:02}:{:02}",
290                        hours, minutes
291                    );
292                    servo_display
293                        .show_hours_minutes_indicator(hours, minutes)
294                        .await;
295                    servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296                }
297                PressDuration::Long => {
298                    info!("Long press detected - saving and exiting edit mode");
299                    // Save to flash and exit edit mode
300                    timezone_field.set_offset_minutes(offset_minutes)?;
301                    info!("Offset saved to flash: {} minutes", offset_minutes);
302                    return Ok(Self::HoursMinutes { speed: 1.0 });
303                }
304            }
305        }
306    }
More examples
Hide additional examples
examples/clock_led8x12.rs (line 207)
197    async fn execute_hours_minutes(
198        self,
199        speed: f32,
200        clock_sync: &ClockSync,
201        button_watch13: &ButtonWatch13,
202        led8x12: &Led8x12,
203    ) -> Result<Self> {
204        clock_sync.set_speed(speed).await;
205        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206        show_hours_minutes(led8x12, hours, minutes).await?;
207        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208        loop {
209            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210                // Button pushes
211                Either::First(press_duration) => {
212                    info!(
213                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214                        press_duration,
215                        speed.to_bits()
216                    );
217                    match (press_duration, speed.to_bits()) {
218                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219                            info!("HoursMinutes -> MinutesSeconds");
220                            return Ok(Self::MinutesSeconds);
221                        }
222                        (PressDuration::Short, _) => {
223                            info!("HoursMinutes: Resetting speed to 1.0");
224                            return Ok(Self::HoursMinutes { speed: 1.0 });
225                        }
226                        (PressDuration::Long, _) => {
227                            info!("HoursMinutes -> EditOffset");
228                            return Ok(Self::EditOffset);
229                        }
230                    }
231                }
232                // Clock tick
233                Either::Second(tick_event) => {
234                    let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235                    show_hours_minutes(led8x12, hours, minutes).await?;
236                }
237            }
238        }
239    }
240
241    async fn execute_minutes_seconds(
242        self,
243        clock_sync: &ClockSync,
244        button_watch13: &ButtonWatch13,
245        led8x12: &Led8x12,
246    ) -> Result<Self> {
247        clock_sync.set_speed(1.0).await;
248        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249        show_minutes_seconds(led8x12, minutes, seconds).await?;
250        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251        loop {
252            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253                // Button pushes
254                Either::First(press_duration) => {
255                    info!(
256                        "MinutesSeconds: Button press detected: {:?}",
257                        press_duration
258                    );
259                    match press_duration {
260                        PressDuration::Short => {
261                            info!("MinutesSeconds -> HoursMinutes (fast)");
262                            return Ok(Self::HoursMinutes {
263                                speed: FAST_MODE_SPEED,
264                            });
265                        }
266                        PressDuration::Long => {
267                            info!("MinutesSeconds -> EditOffset");
268                            return Ok(Self::EditOffset);
269                        }
270                    }
271                }
272                // Clock tick
273                Either::Second(tick_event) => {
274                    let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275                    show_minutes_seconds(led8x12, minutes, seconds).await?;
276                }
277            }
278        }
279    }
280
281    async fn execute_edit_offset(
282        self,
283        clock_sync: &ClockSync,
284        button_watch13: &ButtonWatch13,
285        timezone_field: &TimezoneField,
286        led8x12: &Led8x12,
287    ) -> Result<Self> {
288        info!("Entering edit offset mode");
289        clock_sync.set_speed(1.0).await;
290
291        // Blink current hours and minutes with edit color accent.
292        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293        show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        loop {
301            info!("Waiting for button press in edit mode");
302            match button_watch13.wait_for_press_duration().await {
303                PressDuration::Short => {
304                    info!("Short press detected - incrementing offset");
305                    // Increment the offset by 1 hour
306                    offset_minutes += 60;
307                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308                    if offset_minutes >= ONE_DAY_MINUTES {
309                        offset_minutes -= ONE_DAY_MINUTES;
310                    }
311                    clock_sync.set_offset_minutes(offset_minutes).await;
312                    info!("New offset: {} minutes", offset_minutes);
313
314                    // Update display
315                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316                    info!(
317                        "Updated time after offset change: {:02}:{:02}",
318                        hours, minutes
319                    );
320                    show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321                }
322                PressDuration::Long => {
323                    info!("Long press detected - saving and exiting edit mode");
324                    // Save to flash and exit edit mode
325                    timezone_field.set_offset_minutes(offset_minutes)?;
326                    info!("Offset saved to flash: {} minutes", offset_minutes);
327                    return Ok(Self::HoursMinutes { speed: 1.0 });
328                }
329            }
330        }
331    }
examples/clock_led12x4.rs (line 200)
190    async fn execute_hours_minutes(
191        self,
192        speed: f32,
193        clock_sync: &ClockSync,
194        button_watch13: &ButtonWatch13,
195        led12x4: &Led12x4,
196    ) -> Result<Self> {
197        clock_sync.set_speed(speed).await;
198        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199        show_hours_minutes(led12x4, hours, minutes).await?;
200        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201        loop {
202            match select(
203                button_watch13.wait_for_press_duration(),
204                clock_sync.wait_for_tick(),
205            )
206            .await
207            {
208                // Button pushes
209                Either::First(press_duration) => {
210                    info!(
211                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212                        press_duration,
213                        speed.to_bits()
214                    );
215                    match (press_duration, speed.to_bits()) {
216                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217                            info!("HoursMinutes -> MinutesSeconds");
218                            return Ok(Self::MinutesSeconds);
219                        }
220                        (PressDuration::Short, _) => {
221                            info!("HoursMinutes: Resetting speed to 1.0");
222                            return Ok(Self::HoursMinutes { speed: 1.0 });
223                        }
224                        (PressDuration::Long, _) => {
225                            info!("HoursMinutes -> EditOffset");
226                            return Ok(Self::EditOffset);
227                        }
228                    }
229                }
230                // Clock tick
231                Either::Second(tick) => {
232                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
233                    show_hours_minutes(led12x4, hours, minutes).await?;
234                }
235            }
236        }
237    }
238
239    async fn execute_minutes_seconds(
240        self,
241        clock_sync: &ClockSync,
242        button_watch13: &ButtonWatch13,
243        led12x4: &Led12x4,
244    ) -> Result<Self> {
245        clock_sync.set_speed(1.0).await;
246        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247        show_minutes_seconds(led12x4, minutes, seconds).await?;
248        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249        loop {
250            match select(
251                button_watch13.wait_for_press_duration(),
252                clock_sync.wait_for_tick(),
253            )
254            .await
255            {
256                // Button pushes
257                Either::First(press_duration) => {
258                    info!(
259                        "MinutesSeconds: Button press detected: {:?}",
260                        press_duration
261                    );
262                    match press_duration {
263                        PressDuration::Short => {
264                            info!("MinutesSeconds -> HoursMinutes (fast)");
265                            return Ok(Self::HoursMinutes {
266                                speed: FAST_MODE_SPEED,
267                            });
268                        }
269                        PressDuration::Long => {
270                            info!("MinutesSeconds -> EditOffset");
271                            return Ok(Self::EditOffset);
272                        }
273                    }
274                }
275                // Clock tick
276                Either::Second(tick) => {
277                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278                    show_minutes_seconds(led12x4, minutes, seconds).await?;
279                }
280            }
281        }
282    }
283
284    async fn execute_edit_offset(
285        self,
286        clock_sync: &ClockSync,
287        button_watch13: &ButtonWatch13,
288        timezone_field: &TimezoneField,
289        led12x4: &Led12x4,
290    ) -> Result<Self> {
291        info!("Entering edit offset mode");
292        clock_sync.set_speed(1.0).await;
293
294        // Blink current hours and minutes with edit color accent.
295        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296        show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298        // Get the current offset minutes from clock (source of truth)
299        let mut offset_minutes = clock_sync.offset_minutes();
300        info!("Current offset: {} minutes", offset_minutes);
301
302        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303        loop {
304            info!("Waiting for button press in edit mode");
305            match button_watch13.wait_for_press_duration().await {
306                PressDuration::Short => {
307                    info!("Short press detected - incrementing offset");
308                    // Increment the offset by 1 hour
309                    offset_minutes += 60;
310                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311                    if offset_minutes >= ONE_DAY_MINUTES {
312                        offset_minutes -= ONE_DAY_MINUTES;
313                    }
314                    clock_sync.set_offset_minutes(offset_minutes).await;
315                    info!("New offset: {} minutes", offset_minutes);
316
317                    // Update display (atomic already updated, can use now_local)
318                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319                    info!(
320                        "Updated time after offset change: {:02}:{:02}",
321                        hours, minutes
322                    );
323                    show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324                }
325                PressDuration::Long => {
326                    info!("Long press detected - saving and exiting edit mode");
327                    // Save to flash and exit edit mode
328                    timezone_field.set_offset_minutes(offset_minutes)?;
329                    info!("Offset saved to flash: {} minutes", offset_minutes);
330                    return Ok(Self::HoursMinutes { speed: 1.0 });
331                }
332            }
333        }
334    }
examples/clock_led4.rs (line 186)
168    async fn execute_hours_minutes(
169        self,
170        speed: f32,
171        clock_sync: &ClockSync,
172        button_watch13: &ButtonWatch13,
173        led4: &Led4<'_>,
174    ) -> Result<Self> {
175        clock_sync.set_speed(speed).await;
176        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177        led4.write_text(
178            [
179                Self::tens_hours(hours),
180                Self::ones_digit(hours),
181                Self::tens_digit(minutes),
182                Self::ones_digit(minutes),
183            ],
184            BlinkState::Solid,
185        );
186        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187        loop {
188            match select(
189                button_watch13.wait_for_press_duration(),
190                clock_sync.wait_for_tick(),
191            )
192            .await
193            {
194                // Button pushes
195                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197                        return Ok(Self::MinutesSeconds);
198                    }
199                    (PressDuration::Short, _) => {
200                        return Ok(Self::HoursMinutes { speed: 1.0 });
201                    }
202                    (PressDuration::Long, _) => {
203                        return Ok(Self::EditOffset);
204                    }
205                },
206                // Clock tick
207                Either::Second(tick) => {
208                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
209                    led4.write_text(
210                        [
211                            Self::tens_hours(hours),
212                            Self::ones_digit(hours),
213                            Self::tens_digit(minutes),
214                            Self::ones_digit(minutes),
215                        ],
216                        BlinkState::Solid,
217                    );
218                }
219            }
220        }
221    }
222
223    async fn execute_minutes_seconds(
224        self,
225        clock_sync: &ClockSync,
226        button_watch13: &ButtonWatch13,
227        led4: &Led4<'_>,
228    ) -> Result<Self> {
229        clock_sync.set_speed(1.0).await;
230        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231        led4.write_text(
232            [
233                Self::tens_digit(minutes),
234                Self::ones_digit(minutes),
235                Self::tens_digit(seconds),
236                Self::ones_digit(seconds),
237            ],
238            BlinkState::Solid,
239        );
240        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241        loop {
242            match select(
243                button_watch13.wait_for_press_duration(),
244                clock_sync.wait_for_tick(),
245            )
246            .await
247            {
248                // Button pushes
249                Either::First(PressDuration::Short) => {
250                    return Ok(Self::HoursMinutes {
251                        speed: FAST_MODE_SPEED,
252                    });
253                }
254                Either::First(PressDuration::Long) => {
255                    return Ok(Self::EditOffset);
256                }
257                // Clock tick
258                Either::Second(tick) => {
259                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260                    led4.write_text(
261                        [
262                            Self::tens_digit(minutes),
263                            Self::ones_digit(minutes),
264                            Self::tens_digit(seconds),
265                            Self::ones_digit(seconds),
266                        ],
267                        BlinkState::Solid,
268                    );
269                }
270            }
271        }
272    }
273
274    async fn execute_edit_offset(
275        self,
276        clock_sync: &ClockSync,
277        button_watch13: &ButtonWatch13,
278        timezone_field: &TimezoneField,
279        led4: &Led4<'_>,
280    ) -> Result<Self> {
281        info!("Entering edit offset mode");
282
283        // Blink current hours and minutes
284        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285        led4.write_text(
286            [
287                Self::tens_hours(hours),
288                Self::ones_digit(hours),
289                Self::tens_digit(minutes),
290                Self::ones_digit(minutes),
291            ],
292            BlinkState::BlinkingAndOn,
293        );
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        clock_sync.set_speed(1.0).await;
301        loop {
302            info!("Waiting for button press in edit mode");
303            match button_watch13.wait_for_press_duration().await {
304                PressDuration::Short => {
305                    info!("Short press detected - incrementing offset");
306                    // Increment the offset by 1 hour
307                    offset_minutes += 60;
308                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309                    if offset_minutes >= ONE_DAY_MINUTES {
310                        offset_minutes -= ONE_DAY_MINUTES;
311                    }
312                    clock_sync.set_offset_minutes(offset_minutes).await;
313                    info!("New offset: {} minutes", offset_minutes);
314
315                    // Update display (atomic already updated, can use now_local)
316                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317                    info!(
318                        "Updated time after offset change: {:02}:{:02}",
319                        hours, minutes
320                    );
321                    led4.write_text(
322                        [
323                            Self::tens_hours(hours),
324                            Self::ones_digit(hours),
325                            Self::tens_digit(minutes),
326                            Self::ones_digit(minutes),
327                        ],
328                        BlinkState::BlinkingAndOn,
329                    );
330                }
331                PressDuration::Long => {
332                    info!("Long press detected - saving and exiting edit mode");
333                    // Save to flash and exit edit mode
334                    timezone_field.set_offset_minutes(offset_minutes)?;
335                    info!("Offset saved to flash: {} minutes", offset_minutes);
336                    return Ok(Self::HoursMinutes { speed: 1.0 });
337                }
338            }
339        }
340    }
Source

pub async fn set_speed(&self, speed_multiplier: f32)

Update the speed multiplier (1.0 = real time).

Examples found in repository?
examples/clock_servos.rs (line 178)
171    async fn execute_hours_minutes(
172        self,
173        speed: f32,
174        clock_sync: &ClockSync,
175        button_watch13: &ButtonWatch13,
176        servo_display: &ServoClockDisplay,
177    ) -> Result<Self> {
178        clock_sync.set_speed(speed).await;
179        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
180        servo_display.show_hours_minutes(hours, minutes).await;
181        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
182        loop {
183            match select(
184                button_watch13.wait_for_press_duration(),
185                clock_sync.wait_for_tick(),
186            )
187            .await
188            {
189                // Button pushes
190                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
191                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
192                        return Ok(Self::MinutesSeconds);
193                    }
194                    (PressDuration::Short, _) => {
195                        return Ok(Self::HoursMinutes { speed: 1.0 });
196                    }
197                    (PressDuration::Long, _) => {
198                        return Ok(Self::EditOffset);
199                    }
200                },
201                // Clock tick
202                Either::Second(tick) => {
203                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
204                    servo_display.show_hours_minutes(hours, minutes).await;
205                }
206            }
207        }
208    }
209
210    async fn execute_minutes_seconds(
211        self,
212        clock_sync: &ClockSync,
213        button_watch13: &ButtonWatch13,
214        servo_display: &ServoClockDisplay,
215    ) -> Result<Self> {
216        clock_sync.set_speed(1.0).await;
217        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
218        servo_display.show_minutes_seconds(minutes, seconds).await;
219        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
220        loop {
221            match select(
222                button_watch13.wait_for_press_duration(),
223                clock_sync.wait_for_tick(),
224            )
225            .await
226            {
227                // Button pushes
228                Either::First(PressDuration::Short) => {
229                    return Ok(Self::HoursMinutes {
230                        speed: FAST_MODE_SPEED,
231                    });
232                }
233                Either::First(PressDuration::Long) => {
234                    return Ok(Self::EditOffset);
235                }
236                // Clock tick
237                Either::Second(tick) => {
238                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
239                    servo_display.show_minutes_seconds(minutes, seconds).await;
240                }
241            }
242        }
243    }
244
245    async fn execute_edit_offset(
246        self,
247        clock_sync: &ClockSync,
248        button_watch13: &ButtonWatch13,
249        timezone_field: &TimezoneField,
250        servo_display: &ServoClockDisplay,
251    ) -> Result<Self> {
252        info!("Entering edit offset mode");
253        clock_sync.set_speed(1.0).await;
254
255        // Show current hours and minutes
256        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
257        servo_display
258            .show_hours_minutes_indicator(hours, minutes)
259            .await;
260        // Add a gentle wiggle on the bottom servo to signal edit mode.
261        const WIGGLE: [(u16, Duration); 2] = [
262            (80, Duration::from_millis(250)),
263            (100, Duration::from_millis(250)),
264        ];
265        servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
266
267        // Get the current offset minutes from clock (source of truth)
268        let mut offset_minutes = clock_sync.offset_minutes();
269        info!("Current offset: {} minutes", offset_minutes);
270
271        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
272        loop {
273            info!("Waiting for button press in edit mode");
274            match button_watch13.wait_for_press_duration().await {
275                PressDuration::Short => {
276                    info!("Short press detected - incrementing offset");
277                    // Increment the offset by 1 hour
278                    offset_minutes += 60;
279                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
280                    if offset_minutes >= ONE_DAY_MINUTES {
281                        offset_minutes -= ONE_DAY_MINUTES;
282                    }
283                    clock_sync.set_offset_minutes(offset_minutes).await;
284                    info!("New offset: {} minutes", offset_minutes);
285
286                    // Update display (atomic already updated, can use now_local)
287                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
288                    info!(
289                        "Updated time after offset change: {:02}:{:02}",
290                        hours, minutes
291                    );
292                    servo_display
293                        .show_hours_minutes_indicator(hours, minutes)
294                        .await;
295                    servo_display.bottom.animate(WIGGLE, AtEnd::Loop);
296                }
297                PressDuration::Long => {
298                    info!("Long press detected - saving and exiting edit mode");
299                    // Save to flash and exit edit mode
300                    timezone_field.set_offset_minutes(offset_minutes)?;
301                    info!("Offset saved to flash: {} minutes", offset_minutes);
302                    return Ok(Self::HoursMinutes { speed: 1.0 });
303                }
304            }
305        }
306    }
More examples
Hide additional examples
examples/clock_led8x12.rs (line 204)
197    async fn execute_hours_minutes(
198        self,
199        speed: f32,
200        clock_sync: &ClockSync,
201        button_watch13: &ButtonWatch13,
202        led8x12: &Led8x12,
203    ) -> Result<Self> {
204        clock_sync.set_speed(speed).await;
205        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
206        show_hours_minutes(led8x12, hours, minutes).await?;
207        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
208        loop {
209            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
210                // Button pushes
211                Either::First(press_duration) => {
212                    info!(
213                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
214                        press_duration,
215                        speed.to_bits()
216                    );
217                    match (press_duration, speed.to_bits()) {
218                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
219                            info!("HoursMinutes -> MinutesSeconds");
220                            return Ok(Self::MinutesSeconds);
221                        }
222                        (PressDuration::Short, _) => {
223                            info!("HoursMinutes: Resetting speed to 1.0");
224                            return Ok(Self::HoursMinutes { speed: 1.0 });
225                        }
226                        (PressDuration::Long, _) => {
227                            info!("HoursMinutes -> EditOffset");
228                            return Ok(Self::EditOffset);
229                        }
230                    }
231                }
232                // Clock tick
233                Either::Second(tick_event) => {
234                    let (hours, minutes, _) = h12_m_s(&tick_event.local_time);
235                    show_hours_minutes(led8x12, hours, minutes).await?;
236                }
237            }
238        }
239    }
240
241    async fn execute_minutes_seconds(
242        self,
243        clock_sync: &ClockSync,
244        button_watch13: &ButtonWatch13,
245        led8x12: &Led8x12,
246    ) -> Result<Self> {
247        clock_sync.set_speed(1.0).await;
248        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
249        show_minutes_seconds(led8x12, minutes, seconds).await?;
250        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
251        loop {
252            match select(button_watch13.wait_for_press_duration(), clock_sync.wait_for_tick()).await {
253                // Button pushes
254                Either::First(press_duration) => {
255                    info!(
256                        "MinutesSeconds: Button press detected: {:?}",
257                        press_duration
258                    );
259                    match press_duration {
260                        PressDuration::Short => {
261                            info!("MinutesSeconds -> HoursMinutes (fast)");
262                            return Ok(Self::HoursMinutes {
263                                speed: FAST_MODE_SPEED,
264                            });
265                        }
266                        PressDuration::Long => {
267                            info!("MinutesSeconds -> EditOffset");
268                            return Ok(Self::EditOffset);
269                        }
270                    }
271                }
272                // Clock tick
273                Either::Second(tick_event) => {
274                    let (_, minutes, seconds) = h12_m_s(&tick_event.local_time);
275                    show_minutes_seconds(led8x12, minutes, seconds).await?;
276                }
277            }
278        }
279    }
280
281    async fn execute_edit_offset(
282        self,
283        clock_sync: &ClockSync,
284        button_watch13: &ButtonWatch13,
285        timezone_field: &TimezoneField,
286        led8x12: &Led8x12,
287    ) -> Result<Self> {
288        info!("Entering edit offset mode");
289        clock_sync.set_speed(1.0).await;
290
291        // Blink current hours and minutes with edit color accent.
292        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
293        show_hours_minutes_indicator(led8x12, hours, minutes).await?;
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        loop {
301            info!("Waiting for button press in edit mode");
302            match button_watch13.wait_for_press_duration().await {
303                PressDuration::Short => {
304                    info!("Short press detected - incrementing offset");
305                    // Increment the offset by 1 hour
306                    offset_minutes += 60;
307                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
308                    if offset_minutes >= ONE_DAY_MINUTES {
309                        offset_minutes -= ONE_DAY_MINUTES;
310                    }
311                    clock_sync.set_offset_minutes(offset_minutes).await;
312                    info!("New offset: {} minutes", offset_minutes);
313
314                    // Update display
315                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
316                    info!(
317                        "Updated time after offset change: {:02}:{:02}",
318                        hours, minutes
319                    );
320                    show_hours_minutes_indicator(led8x12, hours, minutes).await?;
321                }
322                PressDuration::Long => {
323                    info!("Long press detected - saving and exiting edit mode");
324                    // Save to flash and exit edit mode
325                    timezone_field.set_offset_minutes(offset_minutes)?;
326                    info!("Offset saved to flash: {} minutes", offset_minutes);
327                    return Ok(Self::HoursMinutes { speed: 1.0 });
328                }
329            }
330        }
331    }
examples/clock_led12x4.rs (line 197)
190    async fn execute_hours_minutes(
191        self,
192        speed: f32,
193        clock_sync: &ClockSync,
194        button_watch13: &ButtonWatch13,
195        led12x4: &Led12x4,
196    ) -> Result<Self> {
197        clock_sync.set_speed(speed).await;
198        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
199        show_hours_minutes(led12x4, hours, minutes).await?;
200        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
201        loop {
202            match select(
203                button_watch13.wait_for_press_duration(),
204                clock_sync.wait_for_tick(),
205            )
206            .await
207            {
208                // Button pushes
209                Either::First(press_duration) => {
210                    info!(
211                        "HoursMinutes: Button press detected: {:?}, speed_bits={}",
212                        press_duration,
213                        speed.to_bits()
214                    );
215                    match (press_duration, speed.to_bits()) {
216                        (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
217                            info!("HoursMinutes -> MinutesSeconds");
218                            return Ok(Self::MinutesSeconds);
219                        }
220                        (PressDuration::Short, _) => {
221                            info!("HoursMinutes: Resetting speed to 1.0");
222                            return Ok(Self::HoursMinutes { speed: 1.0 });
223                        }
224                        (PressDuration::Long, _) => {
225                            info!("HoursMinutes -> EditOffset");
226                            return Ok(Self::EditOffset);
227                        }
228                    }
229                }
230                // Clock tick
231                Either::Second(tick) => {
232                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
233                    show_hours_minutes(led12x4, hours, minutes).await?;
234                }
235            }
236        }
237    }
238
239    async fn execute_minutes_seconds(
240        self,
241        clock_sync: &ClockSync,
242        button_watch13: &ButtonWatch13,
243        led12x4: &Led12x4,
244    ) -> Result<Self> {
245        clock_sync.set_speed(1.0).await;
246        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
247        show_minutes_seconds(led12x4, minutes, seconds).await?;
248        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
249        loop {
250            match select(
251                button_watch13.wait_for_press_duration(),
252                clock_sync.wait_for_tick(),
253            )
254            .await
255            {
256                // Button pushes
257                Either::First(press_duration) => {
258                    info!(
259                        "MinutesSeconds: Button press detected: {:?}",
260                        press_duration
261                    );
262                    match press_duration {
263                        PressDuration::Short => {
264                            info!("MinutesSeconds -> HoursMinutes (fast)");
265                            return Ok(Self::HoursMinutes {
266                                speed: FAST_MODE_SPEED,
267                            });
268                        }
269                        PressDuration::Long => {
270                            info!("MinutesSeconds -> EditOffset");
271                            return Ok(Self::EditOffset);
272                        }
273                    }
274                }
275                // Clock tick
276                Either::Second(tick) => {
277                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
278                    show_minutes_seconds(led12x4, minutes, seconds).await?;
279                }
280            }
281        }
282    }
283
284    async fn execute_edit_offset(
285        self,
286        clock_sync: &ClockSync,
287        button_watch13: &ButtonWatch13,
288        timezone_field: &TimezoneField,
289        led12x4: &Led12x4,
290    ) -> Result<Self> {
291        info!("Entering edit offset mode");
292        clock_sync.set_speed(1.0).await;
293
294        // Blink current hours and minutes with edit color accent.
295        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
296        show_hours_minutes_indicator(led12x4, hours, minutes).await?;
297
298        // Get the current offset minutes from clock (source of truth)
299        let mut offset_minutes = clock_sync.offset_minutes();
300        info!("Current offset: {} minutes", offset_minutes);
301
302        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
303        loop {
304            info!("Waiting for button press in edit mode");
305            match button_watch13.wait_for_press_duration().await {
306                PressDuration::Short => {
307                    info!("Short press detected - incrementing offset");
308                    // Increment the offset by 1 hour
309                    offset_minutes += 60;
310                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
311                    if offset_minutes >= ONE_DAY_MINUTES {
312                        offset_minutes -= ONE_DAY_MINUTES;
313                    }
314                    clock_sync.set_offset_minutes(offset_minutes).await;
315                    info!("New offset: {} minutes", offset_minutes);
316
317                    // Update display (atomic already updated, can use now_local)
318                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
319                    info!(
320                        "Updated time after offset change: {:02}:{:02}",
321                        hours, minutes
322                    );
323                    show_hours_minutes_indicator(led12x4, hours, minutes).await?;
324                }
325                PressDuration::Long => {
326                    info!("Long press detected - saving and exiting edit mode");
327                    // Save to flash and exit edit mode
328                    timezone_field.set_offset_minutes(offset_minutes)?;
329                    info!("Offset saved to flash: {} minutes", offset_minutes);
330                    return Ok(Self::HoursMinutes { speed: 1.0 });
331                }
332            }
333        }
334    }
examples/clock_led4.rs (line 175)
168    async fn execute_hours_minutes(
169        self,
170        speed: f32,
171        clock_sync: &ClockSync,
172        button_watch13: &ButtonWatch13,
173        led4: &Led4<'_>,
174    ) -> Result<Self> {
175        clock_sync.set_speed(speed).await;
176        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
177        led4.write_text(
178            [
179                Self::tens_hours(hours),
180                Self::ones_digit(hours),
181                Self::tens_digit(minutes),
182                Self::ones_digit(minutes),
183            ],
184            BlinkState::Solid,
185        );
186        clock_sync.set_tick_interval(Some(ONE_MINUTE)).await;
187        loop {
188            match select(
189                button_watch13.wait_for_press_duration(),
190                clock_sync.wait_for_tick(),
191            )
192            .await
193            {
194                // Button pushes
195                Either::First(press_duration) => match (press_duration, speed.to_bits()) {
196                    (PressDuration::Short, bits) if bits == 1.0f32.to_bits() => {
197                        return Ok(Self::MinutesSeconds);
198                    }
199                    (PressDuration::Short, _) => {
200                        return Ok(Self::HoursMinutes { speed: 1.0 });
201                    }
202                    (PressDuration::Long, _) => {
203                        return Ok(Self::EditOffset);
204                    }
205                },
206                // Clock tick
207                Either::Second(tick) => {
208                    let (hours, minutes, _) = h12_m_s(&tick.local_time);
209                    led4.write_text(
210                        [
211                            Self::tens_hours(hours),
212                            Self::ones_digit(hours),
213                            Self::tens_digit(minutes),
214                            Self::ones_digit(minutes),
215                        ],
216                        BlinkState::Solid,
217                    );
218                }
219            }
220        }
221    }
222
223    async fn execute_minutes_seconds(
224        self,
225        clock_sync: &ClockSync,
226        button_watch13: &ButtonWatch13,
227        led4: &Led4<'_>,
228    ) -> Result<Self> {
229        clock_sync.set_speed(1.0).await;
230        let (_, minutes, seconds) = h12_m_s(&clock_sync.now_local());
231        led4.write_text(
232            [
233                Self::tens_digit(minutes),
234                Self::ones_digit(minutes),
235                Self::tens_digit(seconds),
236                Self::ones_digit(seconds),
237            ],
238            BlinkState::Solid,
239        );
240        clock_sync.set_tick_interval(Some(ONE_SECOND)).await;
241        loop {
242            match select(
243                button_watch13.wait_for_press_duration(),
244                clock_sync.wait_for_tick(),
245            )
246            .await
247            {
248                // Button pushes
249                Either::First(PressDuration::Short) => {
250                    return Ok(Self::HoursMinutes {
251                        speed: FAST_MODE_SPEED,
252                    });
253                }
254                Either::First(PressDuration::Long) => {
255                    return Ok(Self::EditOffset);
256                }
257                // Clock tick
258                Either::Second(tick) => {
259                    let (_, minutes, seconds) = h12_m_s(&tick.local_time);
260                    led4.write_text(
261                        [
262                            Self::tens_digit(minutes),
263                            Self::ones_digit(minutes),
264                            Self::tens_digit(seconds),
265                            Self::ones_digit(seconds),
266                        ],
267                        BlinkState::Solid,
268                    );
269                }
270            }
271        }
272    }
273
274    async fn execute_edit_offset(
275        self,
276        clock_sync: &ClockSync,
277        button_watch13: &ButtonWatch13,
278        timezone_field: &TimezoneField,
279        led4: &Led4<'_>,
280    ) -> Result<Self> {
281        info!("Entering edit offset mode");
282
283        // Blink current hours and minutes
284        let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
285        led4.write_text(
286            [
287                Self::tens_hours(hours),
288                Self::ones_digit(hours),
289                Self::tens_digit(minutes),
290                Self::ones_digit(minutes),
291            ],
292            BlinkState::BlinkingAndOn,
293        );
294
295        // Get the current offset minutes from clock (source of truth)
296        let mut offset_minutes = clock_sync.offset_minutes();
297        info!("Current offset: {} minutes", offset_minutes);
298
299        clock_sync.set_tick_interval(None).await; // Disable ticks in edit mode
300        clock_sync.set_speed(1.0).await;
301        loop {
302            info!("Waiting for button press in edit mode");
303            match button_watch13.wait_for_press_duration().await {
304                PressDuration::Short => {
305                    info!("Short press detected - incrementing offset");
306                    // Increment the offset by 1 hour
307                    offset_minutes += 60;
308                    const ONE_DAY_MINUTES: i32 = ONE_DAY.as_secs() as i32 / 60;
309                    if offset_minutes >= ONE_DAY_MINUTES {
310                        offset_minutes -= ONE_DAY_MINUTES;
311                    }
312                    clock_sync.set_offset_minutes(offset_minutes).await;
313                    info!("New offset: {} minutes", offset_minutes);
314
315                    // Update display (atomic already updated, can use now_local)
316                    let (hours, minutes, _) = h12_m_s(&clock_sync.now_local());
317                    info!(
318                        "Updated time after offset change: {:02}:{:02}",
319                        hours, minutes
320                    );
321                    led4.write_text(
322                        [
323                            Self::tens_hours(hours),
324                            Self::ones_digit(hours),
325                            Self::tens_digit(minutes),
326                            Self::ones_digit(minutes),
327                        ],
328                        BlinkState::BlinkingAndOn,
329                    );
330                }
331                PressDuration::Long => {
332                    info!("Long press detected - saving and exiting edit mode");
333                    // Save to flash and exit edit mode
334                    timezone_field.set_offset_minutes(offset_minutes)?;
335                    info!("Offset saved to flash: {} minutes", offset_minutes);
336                    return Ok(Self::HoursMinutes { speed: 1.0 });
337                }
338            }
339        }
340    }
Source

pub async fn set_utc_time(&self, unix_seconds: UnixSeconds)

Manually set the current UTC time and mark the clock as synced.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<Src, Dst> LosslessTryInto<Dst> for Src
where Dst: LosslessTryFrom<Src>,

Source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
Source§

impl<Src, Dst> LossyInto<Dst> for Src
where Dst: LossyFrom<Src>,

Source§

fn lossy_into(self) -> Dst

Performs the conversion.
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.