123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- * SPDX-FileCopyrightText: 2022 Helmut Pozimski <helmut@pozimski.eu>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
- #include <time.h>
- #include <stdlib.h>
- #include <nvs_flash.h>
- #include <esp_sleep.h>
- #include <esp_system.h>
- #include "ds3231.h"
- #include "tm1637.h"
- #include "wifi.h"
- #include "configuration.h"
- #include <lwip/apps/sntp.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/event_groups.h>
- #define TIME_SYNCED_BIT BIT0
- #define SECONDS_TO_MICROSECONDS 1000000
- #define THREE_HOURS_IN_SECONDS 3 * 60 * 60
- #define HALF_HOUR_IN_SECONDS 30 * 60
- static EventGroupHandle_t time_sync_event_group;
- static uint8_t should_enable_display(uint8_t hour) {
- return hour < 23 && hour >= 6;
- }
- static void update_display(uint8_t hour, uint8_t minute) {
- tm1637_config display_config;
- uint8_t enable_display = should_enable_display(hour);
- tm1637_init(&display_config, TM1637_CLK_PIN, TM1637_DIO_PIN, true, 1);
- if (hour < 10) {
- tm1637_set_segment(&display_config, 10, 0, enable_display);
- tm1637_set_segment(&display_config, hour, 1, enable_display);
- } else {
- tm1637_set_segment(&display_config, hour / 10, 0, enable_display);
- tm1637_set_segment(&display_config, hour % 10, 1, enable_display);
- }
- if (minute < 10) {
- tm1637_set_segment(&display_config, 0, 2, enable_display);
- tm1637_set_segment(&display_config, minute, 3, enable_display);
- } else {
- tm1637_set_segment(&display_config, minute / 10, 2, enable_display);
- tm1637_set_segment(&display_config, minute % 10, 3, enable_display);
- }
- }
- static struct tm *convert_to_local(struct tm *timeinfo) {
- setenv("TZ", "GMT+0GMT+0", 1);
- tzset();
- time_t epoch_time = mktime(timeinfo);
- setenv("TZ", LOCAL_TIMEZONE, 1);
- tzset();
- return localtime(&epoch_time);
- }
- static void time_sync_callback(struct timeval *tv) {
- sntp_stop();
- wifi_stop();
- struct tm date_time;
- localtime_r(&tv->tv_sec, &date_time);
- ds3231_init(DS3231_SDA_PIN, DS3231_SCL_PIN);
- ds3231_write_date_time(date_time);
- struct tm *local_time = convert_to_local(&date_time);
- update_display(local_time->tm_hour, local_time->tm_min);
- xEventGroupSetBits(time_sync_event_group, TIME_SYNCED_BIT);
- }
- static void sync_time() {
- wifi_init();
- if (wifi_start()) {
- sntp_setoperatingmode(SNTP_OPMODE_POLL);
- sntp_setservername(0, "pool.ntp.org");
- sntp_init();
- time_sync_event_group = xEventGroupCreate();
- sntp_set_time_sync_notification_cb(&time_sync_callback);
- xEventGroupWaitBits(time_sync_event_group, TIME_SYNCED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
- vEventGroupDelete(time_sync_event_group);
- }
- }
- static void check_sync(struct tm *date_time) {
- if (date_time->tm_year == 0 || (date_time->tm_hour == 12 && date_time->tm_min == 0)) {
- esp_restart();
- } else {
- struct tm *local_time = convert_to_local(date_time);
- update_display(local_time->tm_hour, local_time->tm_min);
- }
- }
- static void display_time() {
- struct tm date_time;
- esp_err_t ret = ds3231_read_date_time(&date_time);
- if (ret == ESP_OK) {
- check_sync(&date_time);
- }
- }
- static uint16_t min(uint16_t a, uint16_t b) {
- return (a < b) ? a : b;
- }
- static uint16_t max(uint16_t a, uint16_t b) {
- return (a > b) ? a : b;
- }
- static uint64_t determine_sleep_time(struct tm *local_time) {
- uint16_t wakeup_time_sec;
- if (!should_enable_display(local_time->tm_hour)) {
- if (local_time->tm_hour == 5) {
- wakeup_time_sec = min((60 - local_time->tm_min) * 60
- + (60 - local_time->tm_sec), HALF_HOUR_IN_SECONDS);
- } else {
- wakeup_time_sec = HALF_HOUR_IN_SECONDS;
- }
- } else {
- wakeup_time_sec = 60 - local_time->tm_sec;
- }
- wakeup_time_sec = max(wakeup_time_sec, 1);
- return wakeup_time_sec * SECONDS_TO_MICROSECONDS;
- }
- static void sleep_until_next_update() {
- struct tm date_time;
- ds3231_read_date_time(&date_time);
- struct tm *local_time = convert_to_local(&date_time);
- esp_deep_sleep(determine_sleep_time(local_time));
- }
- void app_main() {
- ESP_ERROR_CHECK(nvs_flash_init());
- esp_reset_reason_t reset_reason = esp_reset_reason();
- if (reset_reason == ESP_RST_SW || reset_reason == ESP_RST_EXT) {
- sync_time();
- } else {
- ds3231_init(DS3231_SDA_PIN, DS3231_SCL_PIN);
- ds3231_disable_32khz_output();
- display_time();
- }
- sleep_until_next_update();
- }
|