Set DS1307 time to specific value

Hi,

I’m trying to set up an ESP32 with a DS1307 RTC module.

The ESP32 will not have any other time source as no network is available. I’ve configured the ESP32 to act as an access point and I’ve enabled the web server so I can set some configuration items.

I’ve configured a datetime template where I can specify the current date and time. I would like to sync this user-provided value to the system clock (and RTC) so I can update the time this way. Once it’s set, the system should read the time from the RTC on boot. I can’t seem to find how to set the current system time to an explicit value, so I can then write it to the ds1307.

The DS1307 seems to be halted now. I assume that’s because no initial time has been configured on it?

Currently when the esp32 boots, it shows the following relevant lines:

[11:48:59][C][ds1307:013]: Setting up DS1307...
[11:49:00][D][ds1307:092]: Read  00:00:00 2000-01-01  CH:ON RS:3 SQWE:OFF OUT:OFF
[11:49:00][W][ds1307:037]: RTC halted, not syncing to system clock.

I have the following lines in my config regarding time:

esphome:
  name: moemoe
  platform: ESP32
  board: esp32doit-devkit-v1

logger:
  level: DEBUG

wifi:
  ap:
    ssid: 'My ESP32'
    password: 'secret'
    ap_timeout: 10s

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  id: i2c_bus

time:
  - platform: ds1307
    id: ds1307_time
    timezone: Europe/Brussels
    on_time_sync:
      then:
        - logger.log: "DS1307 time synchronised"

Same issue for me. ESP32 with limited internet availability needs to be set manually.
I let the user enter date and time (global variables as int) via pushbuttons.

And then the magic should happen and the DS1307 should get the new date time.

How can this be done? Any ideas

@RikT @Thomas717
You can do it using this component
Until it get merged into main branch you need to specify this pr using external_component:

...
external_components:
  - source: github://pr#7621
    refresh: 30s
    components: [ time ]

time:
  - platform: ds1307
    id: ds1307_time

datetime:
  - platform: template
    type: datetime
    name: Pick a Datetime
    optimistic: yes
    on_value:
      then:
        lambda: |-
          id(ds1307_time).set_time(x);

button:
  - platform: template
    name: "Press to print current date/time"
    on_press: 
      then:
        - logger.log:
            format: "local: %s"
            args: [ 'id(ds1307_time).now().strftime("%Y-%m-%d %H:%M:%S").c_str()' ]
...

Thanks to rfdarter :+1:

There seems to be a bug in pr#7621 related to setting of the hour.
Here is my lambda code:

        int hour = id(dt_hour).state;
        ESP_LOGD("main", "hour is: %d", hour);
        id(rtc_time).set_time(year, month, day, hour, minute, 0);
        auto time = id(rtc_time).now();
        id(current_time).publish_state(time.strftime("%Y-%m-%d / %H:%M"));

The log show hour is “N” but the time is set to “N-1”. Entering hour = 0 is ignored.
I am using a DS3231 but should be the same as DS1307 from a programming point of view.
I too have a webserver application that requires date and time independent of the internet.
I could create a custom component to write to the DS3231 registers but that should not be necessary.
I could just add one to hour but that seems like a hack.

Here is a complete example of how to set time on a DS3231/DS1307 RTC without an internet connection and not requiring pr#7621

esphome:
  name: settime
  friendly_name: Set Time Demo
  platformio_options:
    board_build.arduino.memory_type: qio_opi
    board_upload.maximum_ram_size: 524288
  on_boot:
    - priority: 200
      then:
        - ds1307.read_time:

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  #partitions: "/config/esphome/default_16MB.csv"
  framework:
    type: arduino
psram:
  mode: octal
  speed: 80MHz

# Enable logging
logger:
  level: debug

wifi:
  ap:
    ssid: "Demo"
    password: "password"
    
web_server:
  port: 80
  version: 3
  ota: true
  log: true
  local: true
  sorting_groups:
    - id: sorting_group_time
      name: "Current Date/Time"
      sorting_weight: 10


i2c:
  sda: GPIO01
  scl: GPIO02
  scan: true
  id: bus_a

time:
  - platform: ds1307 
    id: rtc_time
    timezone: "unknown"
    
number: 
  # Set Date Times
  - platform: template 
    name: "Year"
    id: dt_year
    web_server:
      sorting_group_id: sorting_group_time
    optimistic: true
    mode: box
    min_value: 2025
    max_value: 2100
    step: 1
    initial_value: 2025
    restore_value: true
  - platform: template 
    name: "_Month"
    id: dt_month
    web_server:
      sorting_group_id: sorting_group_time
    optimistic: true
    mode: box
    min_value: 1
    max_value: 12
    step: 1
    initial_value: 1
  - platform: template 
    name: "Day"
    id: dt_day
    web_server:
      sorting_group_id: sorting_group_time
    optimistic: true
    mode: box
    min_value: 1
    max_value: 31
    step: 1
    initial_value: 1
  - platform: template 
    name: "Hour"
    id: dt_hour
    web_server:
      sorting_group_id: sorting_group_time
    optimistic: true
    mode: box
    min_value: 0
    max_value: 23
    step: 1
    initial_value: 12
  - platform: template 
    name: "Minute"
    id: dt_minute
    web_server:
      sorting_group_id: sorting_group_time
    optimistic: true
    mode: box
    min_value: 1
    max_value: 59
    step: 1
    initial_value: 0

text_sensor:
  - platform: template
    name: "Date/Time"
    id: current_time
    web_server:
      sorting_group_id: sorting_group_time
    lambda: |-
      auto time = id(rtc_time).now();
      return time.strftime("%Y-%m-%d / %H:%M");

button:
  - platform: template
    name: "~Set Time"
    id: set_time_button
    web_server:
      sorting_group_id: sorting_group_time
    on_press:
      then:
        - lambda: |-
            ESP_LOGD("main", "Button Pressed");
            int year = id(dt_year).state;
            int month = id(dt_month).state;
            int day = id(dt_day).state;
            int hour = id(dt_hour).state;
            int tmp;
            int minute = id(dt_minute).state;
            year = (year - 2000) / 10 * 16 + ((year - 2000) % 10);
            month = month / 10 * 16 + (month % 10);
            day = day / 10 * 16 + (day % 10);
            hour = hour / 10 * 16 + (hour % 10);
            minute = minute / 10 * 16 + (minute % 10);
            Wire.beginTransmission(0x68);
            Wire.write(0);  // Start at register 0
            Wire.write(0);       // Seconds
            Wire.write(minute);  // Minutes
            Wire.write(hour);    // Hours
            Wire.write(1);   // Day of the week
            Wire.write(day);     // Day of the month
            Wire.write(month);  // Month
            Wire.write(year);   // Year
            Wire.endTransmission();
        - ds1307.read_time:
            id: rtc_time
        - lambda: |-
            auto time = id(rtc_time).now();
            id(current_time).publish_state(time.strftime("%Y-%m-%d / %H:%M"));