Esphome Set your time

Do you mind sharing it or the approach you’ve taken?
Thanks in advance!

Patience. I’m from Ukraine. We have power outages and missile attacks, so I can’t test the code often. I’ll definitely share when I finish.

1 Like

Hi, I’d like this approach to set the clock and I’m on LVGL environment so I would put clock directly on display if needed
Waiting for your precious piece of code

substitutions:
  timezone: "Europe/Kiev"

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: arduino

esphome:
  name: "time"
  friendly_name: "time"
  platformio_options:
    board_build.flash_mode: dio
  on_boot:
    - priority: 200
      then:
        - ds1307.read_time:
            id: rtc_time

psram:
  mode: octal
  speed: 80MHz

i2c:
  - id: bus_slow
    sda: GPIO01
    scl: GPIO02
    scan: True
    frequency: 100kHz  

number:
  - platform: template
    name: "Year Select"
    icon: "mdi:hours-24"
    id: year_select
    mode: BOX
    min_value: 2025
    max_value: 2040
    step: 1
    initial_value: 2025
    unit_of_measurement: "Year"
    update_interval: 0s
    optimistic: true   

  - platform: template
    name: "Month Select"
    icon: "mdi:hours-24"
    id: month_select
    mode: BOX
    min_value: 1
    max_value: 12
    step: 1
    initial_value: 1
    unit_of_measurement: "Month"
    update_interval: 0s
    optimistic: true   

  - platform: template
    name: "Day Select"
    icon: "mdi:hours-24"
    id: day_select
    mode: BOX
    min_value: 1
    max_value: 31
    step: 1
    initial_value: 1
    unit_of_measurement: "Day"
    update_interval: 0s
    optimistic: true   

  - platform: template
    name: "Hours Select"
    icon: "mdi:hours-24"
    id: hours_select
    mode: BOX
    min_value: 0
    max_value: 23
    step: 1
    initial_value: 0
    unit_of_measurement: "Hours"
    update_interval: 0s
    optimistic: true   


  - platform: template
    name: "Minutes Select"
    icon: "mdi:hours-24"
    id: minutes_select
    mode: BOX
    min_value: 0
    max_value: 59
    step: 1
    initial_value: 0
    unit_of_measurement: "Minutes"
    update_interval: 0s
    optimistic: true   

text_sensor:
  - platform: template
    name: "Current Time"
    id: current_time
    icon: mdi:clock-time-eight-outline
    lambda: |-
      auto time = id(rtc_time).now();
      return time.strftime("%Y-%m-%d / %H:%M");
    update_interval: 5s

button:
  - platform: template
    name: "Set Manual Time"
    id: set_time_button
    icon: mdi:clock-time-six-outline
    on_press:
      - script.execute: set_time

script:
  - id: set_time
    then:
      - lambda: |-
          setenv("TZ", "${timezone}", 1);  
          tzset();  

          struct tm time_info;
          time_info.tm_year = id(year_select).state - 1900;
          time_info.tm_mon = id(month_select).state - 1;
          time_info.tm_mday = id(day_select).state;
          time_info.tm_hour = id(hours_select).state;
          time_info.tm_min = id(minutes_select).state;
          time_info.tm_sec = 0;
          time_info.tm_isdst = -1;

          std::time_t t = mktime(&time_info);
          struct timeval tv = {t, 0};
          settimeofday(&tv, NULL);

          ESP_LOGD("main", "Time set to: %s", ctime(&t));
      - delay: 1s    
      - component.update: current_time    
      - ds1307.write_time: 
          id: rtc_time
      - logger.log: Time synchronized ds1307
      - delay: 1s
      - ds1307.read_time: 
          id: rtc_time
      - logger.log: Time read by ds1307

time:
  - platform: homeassistant        
    id: ha_time
    update_interval: 60s
    on_time_sync:
      then:
        - ds1307.write_time: 
            id: rtc_time
        - logger.log: Time synchronized ds1307
        - delay: 1s
        - ds1307.read_time: 
            id: rtc_time
        - logger.log: Time read by ds1307

  - platform: ds1307
    id: rtc_time
    timezone: "unknown"
    i2c_id: bus_slow
    address: 0x68
    update_interval: never

1 Like

if there is no connection with the home assistant, then the time can be set manually… when the connection appears, the time will be adjusted automatically

1 Like

Just for my understanding do you just spoof the device in thinking it has a ds rtc attached but doesn’t and then set the time locally? My use case is devices connected via rs485 so time will be provided over serial from a master controller which has a rtc. Thanks

Of course I’m lying… there is no real time clock.They are not even present in my code. :grinning:

- platform: ds1307
    id: rtc_time
    timezone: "unknown"
    i2c_id: bus_slow
    address: 0x68
    update_interval: never

You are very observant.

Ok thank you, very clever solution

That’s a clever way to make sure the esp always runs on the correct time. In my case: my aquarium lights! Thank you!

It’s not that clever really… The ds1307 will drift between 2 - 10s every day so, the longer it goes without network access the greater the time drift will become. These arent really made for anything more than keeping time over a several hour internet outage or power outage beyond maybe 72 hours at least for people who need a high degree of accuracy in the timing.

You are absolutely right. I wouldn’t have even thought about such a function if… There’s a war in my country. I’m from Ukraine. There are frequent power and internet outages. I was just trying to make the time setting independent.

1 Like

You can also run a local NTP server in your lan, even on an esp32 (a bit dodgy, due to wireless connectivity). The bigger question is how to get a reliable time source into this ntpd, ‘normally’ the answer would involve GPS (to resync the RTC) or reading an AM time signal transmitter (e.g. DCF77), but I assume those will be affected around you as well.

This is using the esp32 rtc not ds1370. He is just spoofing esphome codebase to believe the ds rtc is attached . But actually time is set after each power cycle manually.
My use case is a heating system where master node is generally connected to HA but has a DS3231 and distributes time via rs485 to the slaves. These are all powered off a ups. Regardless of state of HA and network the heating system will opperate. (Biomass with large thermal store)

No politics please.

1 Like

I am having a similar problem. A custom PCB with an ESP32C6 on it with a DS3231M as RTC to keep the time while without power. The problem is that I have to set the time manually once when the user connects the first time via webbrowser.

time:
  - platform: ds1307
    id: ds1307_time
    update_interval: 12h

datetime:
  - platform: template
    name: "Datum & Zeit überschreiben"
    type: datetime
    id: my_date_picker
    optimistic: true
    # This keeps it synced or allows logic to run when changed
    on_value:
      then:
        - lambda: |-
            struct tm t = {0};
            t.tm_year = x.year - 1900;
            t.tm_mon  = x.month - 1;
            t.tm_mday = x.day_of_month;
            t.tm_hour = x.hour;
            t.tm_min  = x.minute;
            t.tm_sec  = x.second;
            t.tm_isdst = -1;
            
            time_t epoch = mktime(&t);
            
            struct timeval tv = { .tv_sec = epoch, .tv_usec = 0 };
            settimeofday(&tv, NULL);
            
            ESP_LOGI("custom", "Internal system clock forced to UI time.");
        - ds1307.write_time

This works well, a datepicker can be used in the browser to set the time.

However, it would be simpler to have only a “Sync” button in the webinterface which takes the time from the user´s browser and writes it to the internal clock and RTC.

I thought about altering the webserver-v1.min.js to achieve that, but maybe someone else has another smart idea?

2 Likes

Seems like a good idea. The v1 webserver is not maintained however, v2 is the default and v3 is the latest, it should target those.

I suspect something might have to be added to the time and webserver components as well as the client code to make it happen - there needs to be an action via a POST request to send the time.

2 Likes