ESPHome DutyTime

I have a dutytime sensor set up to display the runtime of a filter in hours, minutes and seconds. It displays properly but when it reaches 24 hours it resets to zero by itself with out anything calling the reset function.

Has anyone else encountered this behavior or know of a way to resolve it. I would eventually like to get the display working for days and hours.

Maybe your board is rebooting?
try with:
restore: true

I have restore: true. It’s not rebooting. I watched it roll over this morning.

Unexpected.
Feel free to post your yaml.

esphome:
  name: aquarium
  friendly_name: Aquarium


esp8266:
  board: esp01_1m

logger:

api:
  encryption:
    key: "redacted"

ota:
  - platform: esphome
    password: "redacted"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

time:
  - platform: sntp
    id: sntp_time

output:
  - platform: gpio
    id: filter_pin
    pin: GPIO03

switch:
  - platform: output
    id: filter_switch
    name: Filter
    icon: "mdi:air-filter"
    output: filter_pin
    restore_mode: RESTORE_DEFAULT_ON
    internal: false
    on_turn_on: 
      then:
        - sensor.duty_time.start: filter_on_time
    on_turn_off: 
      then:
        - sensor.duty_time.stop: filter_on_time
        - script.execute: publish_filter_runtime

sensor:
  - platform: duty_time
    id: filter_on_time
    name: Filter On Time
    unit_of_measurement: s
    accuracy_decimals: 0
    restore: true
    internal: true

text_sensor:
  - platform: template
    name: "Filter Runtime"
    id: filter_runtime
    icon: "mdi:chart-bar"
    update_interval: 5s
    lambda: |-
      int seconds = round(id(filter_on_time).state);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
      return {(
       (hours ? String(hours) + "h " : "") +
       (minutes ? String(minutes) + "m " : "") +
       (String(seconds) + "s")
      ).c_str()}; 

button:
  - platform: template
    name: Change Filter
    id: change_filter
    icon: mdi:air-filter
    on_press:
      then:
        - script.execute: reset_filter_runtime    

script:
  - id: reset_filter_runtime
    then:
      - text_sensor.template.publish:
         id: filter_runtime
         state: !lambda |-
          int seconds = round(id(filter_on_time).state);
          seconds = seconds % (24 * 3600);
          int hours = seconds / 3600;
          seconds = seconds % 3600;
          int minutes = seconds /  60;
          seconds = seconds % 60;
          return {(
           (hours ? String(hours) + "h " : "") +
           (minutes ? String(minutes) + "m " : "") +
           (String(seconds) + "s")
          ).c_str()};
      - sensor.duty_time.reset : filter_on_time
      - script.execute: publish_filter_runtime

  - id: publish_filter_runtime
    then:
      - text_sensor.template.publish:
         id: filter_runtime
         state: !lambda |-
          int seconds = round(id(filter_on_time).state);
          seconds = seconds % (24 * 3600);
          int hours = seconds / 3600;
          seconds = seconds % 3600;
          int minutes = seconds /  60;
          seconds = seconds % 60;
          return {(
           (hours ? String(hours) + "h " : "") +
           (minutes ? String(minutes) + "m " : "") +
           (String(seconds) + "s")
          ).c_str()};

%

When seconds rolls over to zero, int hours = seconds/3600, or 0/3600, =0

Try making a global to hold raw seconds and use that in the hours calculation…

I will look at that.

It shows properly up to 24:59:5x (since the updates are 5s it varies)
Then it returns to 0s and starts counting up again. I don’t have it listed in the yaml but I have a sensor that displays the raw value of the dutytime sensor and it also returned to 0.0 and started incrementing again.

For example duty time is one day and one second:

int seconds = round(id(filter_on_time).state); returns 86401s
seconds = seconds % (24 * 3600); 86401 % 86400 returns 1
int hours = seconds / 3600; returns 0
seconds = seconds % 3600; returns 1
int minutes = seconds / 60; returns 0
seconds = seconds % 60; returns 1

Set your duty time sensor
internal: false
and see the real duty time

And if you like to convert the time delete this line:

int seconds = round(id(filter_on_time).state);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;

Thank you @Karosm !

Was able to get it to work with the following:

state: !lambda |-
          int seconds = round(id(filter_on_time).state);
          int days = seconds / 86400;
          seconds = seconds % 86400;
          int hours = seconds / 3600;
          seconds = seconds % 3600;
          int minutes = seconds /  60;
          seconds = seconds % 60;
          return {(
           (days ? String(days) + "d " : "") +
           (hours ? String(hours) + "h " : "") +
           (minutes ? String(minutes) + "m " : "") +
           (String(seconds) + "s")
          ).c_str()};