#:########################################################################################:# # TITLE: COMMON SNTP TIME SOURCE # zorruno.com common ESPHome include #:########################################################################################:# # FILE: # common/sntp_common.yaml #:########################################################################################:# # VERSIONS: # V1.1 2026-05-23 Fixed offline fallback clock so it increments from assumed noon boot time # V1.0 Initial common SNTP time source and diagnostic sensors #:########################################################################################:# # PURPOSE: # - Provides an SNTP time source for ESPHome devices. # - Stores the current time as minutes since midnight in current_mins. # - Provides a simple fallback clock if SNTP is not available. # - Publishes diagnostic text sensors for last restart, current/internal time, and sync status. #:########################################################################################:# # OPERATION NOTES: # - SNTP time is stored in id(sntp_time). # - Current minutes since midnight are stored in id(current_mins). # - If SNTP is valid, current_mins follows the real SNTP time. # - If SNTP is invalid, current_mins increments once per minute from the assumed boot time. # - The fallback assumes the device was powered on at 12:00 noon. # - If accurate offline time is needed, power-cycle the device at 12:00 noon. #:########################################################################################:# #:########################################################################################:# # SUBSTITUTIONS: Specific SNTP variable substitutions # If NOT using a secrets file, replace these values directly in quotes. #:########################################################################################:# substitutions: timezone: "Pacific/Auckland" sntp_update_interval: 6h # Network time servers # https://www.ntppool.org/zone/@ sntp_server_1: pool.ntp.org sntp_server_2: pool.ntp.org sntp_server_3: pool.ntp.org #:########################################################################################:# # GLOBALS: Internal clock fallback support #:########################################################################################:# globals: - id: current_mins type: int restore_value: false initial_value: "720" # 720 minutes from midnight is 12:00 noon. #:########################################################################################:# # INTERVAL: Keep current_mins updated #:########################################################################################:# interval: - interval: 60s then: - lambda: |- // If SNTP is valid, store real minutes since midnight. auto now = id(sntp_time).now(); if (now.is_valid()) { id(current_mins) = (now.hour * 60) + now.minute; } else { // Fallback: increment from the assumed startup time. // Initial value is 720, so offline boot assumes 12:00 noon. id(current_mins) = (id(current_mins) + 1) % 1440; } #:########################################################################################:# # TIME: Real time clock source for ESPHome # https://esphome.io/components/time/index.html # https://esphome.io/components/time/sntp #:########################################################################################:# time: - platform: sntp id: sntp_time timezone: "${timezone}" update_interval: ${sntp_update_interval} servers: - "${sntp_server_1}" - "${sntp_server_2}" - "${sntp_server_3}" on_time_sync: then: - logger.log: "Synchronised SNTP clock" - text_sensor.template.publish: id: time_sync state: "SNTP clock synced" # Update last restart time once only, after the first successful SNTP sync. - if: condition: lambda: |- return id(device_last_restart).state.empty(); then: - text_sensor.template.publish: id: device_last_restart state: !lambda |- auto now = id(sntp_time).now(); return now.strftime("%a %d %b %Y - %I:%M:%S %p"); #:########################################################################################:# # TEXT SENSOR COMPONENT: # https://esphome.io/components/text_sensor/ #:########################################################################################:# text_sensor: # Shows when the device was last restarted, based on the first successful SNTP sync. - platform: template name: "Time: Last Restart" id: device_last_restart icon: mdi:clock entity_category: diagnostic update_interval: never # Shows the current SNTP time if valid, otherwise the internal fallback time. - platform: template name: "Time: Internal Time" id: time_text icon: mdi:clock-outline update_interval: 1min entity_category: diagnostic lambda: |- if (id(sntp_time).now().is_valid()) { auto t = id(sntp_time).now().strftime("%H:%M:%S - %d-%m-%Y"); return { t }; } int mins = id(current_mins); if (mins < 0) mins = 0; if (mins >= 1440) mins = mins % 1440; int hour = mins / 60; int minute = mins % 60; char buff[32]; snprintf(buff, sizeof(buff), "%02d:%02d (fallback)", hour, minute); return { std::string(buff) }; # Shows whether the device is using SNTP or the fallback clock. - platform: template name: "Time: Sync Status" id: time_sync icon: mdi:clock-check-outline update_interval: 1min entity_category: diagnostic lambda: |- if (id(sntp_time).now().is_valid()) { return { std::string("SNTP clock synced") }; } return { std::string("Using fallback internal clock") };