############################################################################################ # SPECIFIC DEVICE VARIABLE SUBSTITUTIONS # If NOT using a secrets file, just replace # these with the values (in quotes) ########################################################################################### substitutions: timezone: "Pacific/Auckland" sntp_update_interval: 6h # Set the duration between the sntp service polling # Network time servers https://www.ntppool.org/zone/@ sntp_server_1: !secret ntp_server_1 sntp_server_2: !secret ntp_server_2 sntp_server_3: !secret ntp_server_3 ########################################################################################### # Internal clock fallback support # If SNTP is invalid, we fall back to a simple internal minute counter # We assume user powers on the device at 12:00 noon # => 12 * 60 = 720 minutes from midnight. # Not restored, so it resets each boot. # Therefore, if no network and you still need timing functions, switch on ay noon. ########################################################################################### globals: - id: current_mins type: int restore_value: no initial_value: "720" # 720 is 12:00 Noon interval: - interval: 60s then: - lambda: |- // If SNTP valid, store minutes since midnight. auto now = id(sntp_time).now(); if (now.is_valid()) { id(current_mins) = (now.hour * 60) + now.minute; } else { // Fallback: minutes since boot. id(current_mins) = (int)(millis() / 60000UL); } ########################################################################################### # Real time clock time source for ESPHome # If it's invalid, we fall back to an internal clock # https://esphome.io/components/time/index.html # https://esphome.io/components/time/sntp ########################################################################################### time: - platform: sntp id: sntp_time # Define the timezone of the device timezone: "${timezone}" # Change sync interval from default 5min to 6 hours (or as set in substitutions) update_interval: ${sntp_update_interval} # Set specific sntp servers to use servers: - "${sntp_server_1}" - "${sntp_server_2}" - "${sntp_server_3}" # Publish the time the device was last restarted on_time_sync: then: - logger.log: "Synchronised SNTP clock" - text_sensor.template.publish: id: time_sync state: "SNTP clock Syncd" # Update last restart time, but only once. - if: condition: lambda: 'return id(device_last_restart).state == "";' then: - text_sensor.template.publish: id: device_last_restart #state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");' state: !lambda |- // grab the current SNTP time auto now = id(sntp_time).now(); // format it as e.g. "Fri 23 May 2025 - 03:45:12 PM" return now.strftime("%a %d %b %Y - %I:%M:%S %p"); text_sensor: # Creates a sensor showing when the device was last restarted - platform: template name: "Time: Last Restart" id: device_last_restart icon: mdi:clock entity_category: diagnostic #device_class: timestamp - platform: template name: "Time: Internal Time" id: time_text update_interval: "1min" entity_category: diagnostic lambda: |- // If SNTP time is valid, show real time/date. if (id(sntp_time).now().is_valid()) { auto t = id(sntp_time).now().strftime("%H:%M:%S - %d-%m-%Y"); return { t }; } // Fallback: show internal clock based on current_mins (minutes from midnight). 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) }; - platform: template name: "Time: Sync Status" id: time_sync update_interval: "1min" entity_category: diagnostic