How Do I Format Lambda for text_sensor - ESPHome Sprinkler

for now I’m using this quick&dirty solution

I’m using an helper

then when the sprinkler start, there is an automation that does the math and set the value

{% set total = 0 %}
{% if states('switch.zone_1_enable') == 'on' %}
   {% set total = total + (states('number.zone_1_duration')|int*60)%}
{% endif %}
{% if states('switch.zone_2_enable') == 'on' %}
   {% set total = total + (states('number.zone_2_duration')|int*60)%}
{% endif %}
{% if states('switch.zone_3_enable') == 'on' %}
   {% set total = total + (states('number.zone_3_duration')|int*60)%}
{% endif %}
{% if states('switch.zone_4_enable') == 'on' %}
   {% set total = total + (states('number.zone_4_duration')|int*60)%}
{% endif %}
{% if states('switch.zone_5_enable') == 'on' %}
   {% set total = total + (states('number.zone_5_duration')|int*60)%}
{% endif %}
{% if states('switch.zone_6_enable') == 'on' %}
   {% set total = total + (states('number.zone_6_duration')|int*60)%}
{% endif %}
{% set total = total * (states('number.run_duration_multiplier')|int) %}
{{ total | timestamp_custom("%H:%M:%S",0)}}

next step, dynamically populate the list of the active zone and sum the corresponding values.
any idea is welcome :smiley:

2 Likes

@rcblackwell I hope that your are going well, I’m trying to compile the code with ESPHome 2023.3.0 and I’m now stuck with this error, any ideas?

sprinkler-control.yaml:483:175:
error: ‘class esphome::sprinkler::Sprinkler’ has no member named ‘time_remaining’

This was a breaking change in sprinkler component v2. The item is now called time_remaining_active_valve.

1 Like

THANK YOU, I missed it. I will have a look to see if there are additional changes.

Thank you again

Hi @SebaVT
May I ask you to share a screenshot of your full Lovelace sprinkler/ irrigation dashboard and it’s code to get some inspiration? :slight_smile:

Hey @olympia, I haven’t touched the code in a while and is still a work in progress with some bugs, but here IT is:

DISCLAIMER: I’m not a programmer so don’t expect a clean code. I learned how to code this while writing it.

Lovelace:

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - type: vertical-stack
        cards:
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.sprinkler_controller_run
                show_name: false
                icon: mdi:play
                styles:
                  card:
                    - width: 100px
                    - height: 80px
                tap_action:
                  action: call-service
                  service: switch.turn_on
                  service_data:
                    entity_id: switch.sprinkler_controller_run
              - type: custom:button-card
                entity: switch.sprinkler_controller_pause
                show_name: false
                icon: mdi:pause
                styles:
                  card:
                    - width: 100px
                    - height: 80px
                tap_action:
                  action: call-service
                  service: switch.toggle
                  service_data:
                    entity_id: switch.sprinkler_controller_pause
              - type: custom:button-card
                entity: switch.sprinkler_controller_stop
                show_name: false
                icon: mdi:stop
                styles:
                  card:
                    - width: 100px
                    - height: 80px
                tap_action:
                  action: call-service
                  service: switch.turn_on
                  service_data:
                    entity_id: switch.sprinkler_controller_stop
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.run_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.sprinkler_controller_total_run_time_2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 120px
                    - height: 40px
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.sprinkler_controller_previous_valve
                show_name: false
                icon: mdi:skip-previous
                styles:
                  card:
                    - width: 154px
                    - height: 80px
                tap_action:
                  action: call-service
                  service: switch.turn_on
                  service_data:
                    entity_id: switch.sprinkler_controller_previous_valve
              - type: custom:button-card
                entity: switch.sprinkler_controller_next_valve
                show_name: false
                icon: mdi:skip-next
                styles:
                  card:
                    - width: 154px
                    - height: 80px
                tap_action:
                  action: call-service
                  service: switch.turn_on
                  service_data:
                    entity_id: switch.sprinkler_controller_next_valve
      - type: vertical-stack
        cards:
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_1
                show_name: false
                icon: mdi:numeric-1-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_1
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_1_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_1_time_remaining_2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - entity: number.zone_1_duration
                type: custom:numberbox-card
                border: false
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_2
                show_name: false
                icon: mdi:numeric-2-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_2
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_2_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_2_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - type: custom:numberbox-card
                border: false
                entity: number.zone_2_duration
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_3
                show_name: false
                icon: mdi:numeric-3-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_3
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_3_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_3_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - entity: number.zone_3_duration
                type: custom:numberbox-card
                border: false
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_4
                show_name: false
                icon: mdi:numeric-4-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_4
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_4_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_4_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - type: custom:numberbox-card
                border: false
                entity: number.zone_4_duration
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_5
                show_name: false
                icon: mdi:numeric-5-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_5
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_5_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_5_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - entity: number.zone_5_duration
                type: custom:numberbox-card
                border: false
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_6
                show_name: false
                icon: mdi:numeric-6-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_6
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_6_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_6_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - type: custom:numberbox-card
                border: false
                entity: number.zone_6_duration
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_7
                show_name: false
                icon: mdi:numeric-7-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_7
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_7_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_7_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - entity: number.zone_7_duration
                type: custom:numberbox-card
                border: false
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                entity: switch.enable_zone_8
                show_name: false
                icon: mdi:numeric-8-box-outline
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:button-card
                entity: switch.zone_8
                show_name: false
                icon: mdi:sprinkler
                size: 25px
                styles:
                  card:
                    - width: 40px
                    - height: 40px
              - type: custom:bar-card
                height: 8px
                entities:
                  - entity: sensor.zone_8_progress_percentage
                positions:
                  icon: 'off'
                  indicator: 'off'
                  name: 'off'
                  value: 'off'
              - type: custom:button-card
                entity: sensor.zone_8_time_remaining
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - width: 80px
                    - height: 40px
              - type: custom:numberbox-card
                border: false
                entity: number.zone_8_duration
                unit: time
                name: false
                speed: '200'
                icon_plus: mdi:chevron-up
                icon_minus: mdi:chevron-down
  - type: entities
    entities:
      - entity: sensor.debug
      - entity: sensor.lawn_sprinklers_status
      - entity: switch.lawn_sprinklers
      - entity: switch.lawn_sprinklers_auto_advance
      - entity: switch.lawn_sprinklers_reverse
      - entity: number.sprinkler_controller_multiplier
    title: Controls
    show_header_toggle: false

I have to separate the code in two because the forum won’t allow me to post it completely due its size.

ESPHome part 1:

esphome:
  name: sprinkler-controller
  platform: ESP32
  board: esp32dev
  
  on_boot:
    priority: -100
    then:
      - sprinkler.set_multiplier:
          id: lawn_sprinkler_ctrlr
          multiplier: !lambda "return id(multiplier);"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 0
          run_duration: !lambda "return id(z1_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 1
          run_duration: !lambda "return id(z2_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 2
          run_duration: !lambda "return id(z3_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 3
          run_duration: !lambda "return id(z4_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 4
          run_duration: !lambda "return id(z5_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 5
          run_duration: !lambda "return id(z6_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 6
          run_duration: !lambda "return id(z7_duration)* 60;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 7
          run_duration: !lambda "return id(z8_duration)* 60;"
      - text_sensor.template.publish:
          id: lawn_sprinkler_ctrlr_status
          state: "Idle"

preferences:
  flash_write_interval: 0s

# Enable logging
logger:

# Enable Home Assistant API
api:

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Sprinkler-Controller"
    password: "jGIHokqBCBw1"

captive_portal:

globals:
  - id: multiplier
    type: float
    restore_value: true
    initial_value: '1'

  - id: z1_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z2_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z3_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z4_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z5_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z6_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z7_duration
    type: int
    restore_value: true
    initial_value: '15'
    
  - id: z8_duration
    type: int
    restore_value: true
    initial_value: '15'

  - id: total_run_time
    type: int
    restore_value: false
    initial_value: '0'
     

sprinkler:
  - id: lawn_sprinkler_ctrlr
    main_switch:
      name: "Lawn Sprinklers"
    auto_advance_switch: "Lawn Sprinklers Auto Advance"
    reverse_switch: "Lawn Sprinklers Reverse"
    valve_overlap: 1s
    next_prev_ignore_disabled: True
    valves:
      - valve_switch: "Zone 1"
        enable_switch: "Enable Zone 1"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw1
      - valve_switch: "Zone 2"
        enable_switch: "Enable Zone 2"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw2
      - valve_switch: "Zone 3"
        enable_switch: "Enable Zone 3"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw3
      - valve_switch: "Zone 4"
        enable_switch: "Enable Zone 4"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw4
      - valve_switch: "Zone 5"
        enable_switch: "Enable Zone 5"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw5
      - valve_switch: "Zone 6"
        enable_switch: "Enable Zone 6"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw6
      - valve_switch: "Zone 7"
        enable_switch: "Enable Zone 7"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw7
      - valve_switch: "Zone 8"
        enable_switch: "Enable Zone 8"
        run_duration: 900s
        valve_switch_id: lawn_sprinkler_valve_sw8


switch:

  - platform: restart
    name: "Reboot Sprinkler Controller"

  - platform: gpio
    id: lawn_sprinkler_valve_sw1
    pin: 27
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw2
    pin: 32
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw3
    pin: 17
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw4
    pin: 16
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw5
    pin: 15
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw6
    pin: 26
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw7
    pin: 33
    inverted: true
  - platform: gpio
    id: lawn_sprinkler_valve_sw8
    pin: 14
    inverted: true
    
  - platform: template
    id: lawn_sprinkler_ctrlr_run
    name: "Sprinkler Controller Run"
    optimistic: true
    on_turn_on:
      - text_sensor.template.publish:
          id: lawn_sprinkler_ctrlr_status
          state: "Running"
      - sprinkler.resume_or_start_full_cycle: lawn_sprinkler_ctrlr
      - switch.turn_off: lawn_sprinkler_ctrlr_pause
    
  - platform: template
    id: lawn_sprinkler_ctrlr_pause
    name: "Sprinkler Controller Pause"
    optimistic: true
    turn_on_action:
      
      - delay: 500ms
      - lambda: |-
          if(id(lawn_sprinkler_ctrlr_status).state != "Running")
          {
            id(lawn_sprinkler_ctrlr_pause).turn_off();
          }
      - lambda: |-
          if(id(lawn_sprinkler_ctrlr_status).state == "Running")
          {
            id(lawn_sprinkler_ctrlr_status).publish_state("Paused");
            id(lawn_sprinkler_ctrlr).pause();
          }

    on_turn_off:
      lambda: |-
        if(id(lawn_sprinkler_ctrlr_status).state == "Paused")
        {
          id(lawn_sprinkler_ctrlr_status).publish_state("Running");
          id(lawn_sprinkler_ctrlr).resume();
        }


  - platform: template
    id: lawn_sprinkler_ctrlr_stop
    name: "Sprinkler Controller Stop"
    turn_on_action:
      - text_sensor.template.publish:
          id: lawn_sprinkler_ctrlr_status
          state: "Idle"
      - sprinkler.resume: lawn_sprinkler_ctrlr
      - delay: 25ms
      - sprinkler.shutdown: lawn_sprinkler_ctrlr
      - switch.turn_off: lawn_sprinkler_ctrlr_pause
      - switch.turn_off: lawn_sprinkler_ctrlr_run

  - platform: template
    id: lawn_sprinkler_ctrlr_next_valve
    name: "Sprinkler Controller Next Valve"
    turn_on_action:
      - sprinkler.next_valve: lawn_sprinkler_ctrlr
      - delay: 25ms
      - switch.turn_off: lawn_sprinkler_ctrlr_next_valve

  - platform: template
    id: lawn_sprinkler_ctrlr_previous_valve
    name: "Sprinkler Controller Previous Valve"
    turn_on_action:
      - sprinkler.previous_valve: lawn_sprinkler_ctrlr
      - delay: 25ms
      - switch.turn_off: lawn_sprinkler_ctrlr_previous_valve
        

text_sensor:
  - platform: template
    id: lawn_sprinkler_ctrlr_status
    name: "Lawn Sprinklers Status"
    update_interval: 1s
    
  - platform: template
    id: zone_1_time_remaining
    name: "Zone 1 Time Remaining"
  
  - platform: template
    id: zone_2_time_remaining
    name: "Zone 2 Time Remaining"

  - platform: template
    id: zone_3_time_remaining
    name: "Zone 3 Time Remaining"
  
  - platform: template
    id: zone_4_time_remaining
    name: "Zone 4 Time Remaining"

  - platform: template
    id: zone_5_time_remaining
    name: "Zone 5 Time Remaining"
  
  - platform: template
    id: zone_6_time_remaining
    name: "Zone 6 Time Remaining"

  - platform: template
    id: zone_7_time_remaining
    name: "Zone 7 Time Remaining"
  
  - platform: template
    id: zone_8_time_remaining
    name: "Zone 8 Time Remaining"
    
  - platform: template
    id: debug
    name: "Debug"
    
  - platform: template
    id: sprinkler_ctrlr_total_run_time
    name: "Sprinkler Controller Total Run Time"    
    

ESPHome Part 2:

sensor:

  - platform: template
    id: run_progress_percentage
    name: "Run Progress Percentage"
    update_interval: 1s
    lambda: |-
      int seconds = round(id(lawn_sprinkler_ctrlr).total_cycle_time_enabled_valves());
      int days = seconds / (24 * 3600);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
      id(sprinkler_ctrlr_total_run_time).publish_state((
        (days ? String(days) + "d " : "") +
        (hours ? String(hours) + "h " : "") +
        (minutes ? String(minutes) + "m " : "") +
        (String(seconds) + "s")
      ).c_str());


      if (id(lawn_sprinkler_ctrlr).active_valve().has_value())
      {
        id(lawn_sprinkler_ctrlr_status).publish_state("Running");
      }
      else if(id(lawn_sprinkler_ctrlr).paused_valve().has_value())
      {
        id(lawn_sprinkler_ctrlr_status).publish_state("Paused");
      }
      else
      {
        id(lawn_sprinkler_ctrlr_status).publish_state("Idle");
        id(lawn_sprinkler_ctrlr_pause).turn_off();
      }

    

      if(id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        return 0;
      }
      else
      {
        int persentage = (id(lawn_sprinkler_ctrlr).total_cycle_time_enabled_valves() - id(lawn_sprinkler_ctrlr).time_remaining_current_operation().value()) * 100 / id(lawn_sprinkler_ctrlr).total_cycle_time_enabled_valves();
        if (persentage > 100)
        {
          return 0;
        }
        else
        {
          return (persentage);
        }
      }
      
      
      
   
              
  - platform: template
    id: zone1_progress_percentage
    name: "Zone 1 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 0)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_1_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(0) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(0));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_1_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone1_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_1_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};

  - platform: template
    id: zone2_progress_percentage
    name: "Zone 2 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 1)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_2_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(1) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(1));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(1));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_2_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone2_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_2_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};

  - platform: template
    id: zone3_progress_percentage
    name: "Zone 3 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 2)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_3_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(2) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(2));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(2));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_3_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone3_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_3_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};
      
  - platform: template
    id: zone4_progress_percentage
    name: "Zone 4 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 3)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_4_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(3) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(3));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(3));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_4_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone4_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_4_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};
      
  - platform: template
    id: zone5_progress_percentage
    name: "Zone 5 Progress Percentage"
    update_interval: 1s
    lambda: |-
      
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 4)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_5_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(4) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(4));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(4));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_5_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone5_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_5_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};
      

  - platform: template
    id: zone6_progress_percentage
    name: "Zone 6 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 5)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_6_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(5) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(5));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(5));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_6_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone6_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_6_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};
      
  - platform: template
    id: zone7_progress_percentage
    name: "Zone 7 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 6)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_7_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(6) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(6));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(7));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_7_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone7_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_7_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;
      }
      return {};
      
  - platform: template
    id: zone8_progress_percentage
    name: "Zone 8 Progress Percentage"
    update_interval: 1s
    lambda: |-
      if(id(lawn_sprinkler_ctrlr).active_valve().value_or(-1) == 7)
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_8_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return ((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(7) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value()) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(7));
      }
      if (id(lawn_sprinkler_ctrlr).active_valve().has_value() == false && id(lawn_sprinkler_ctrlr_status).state == "Idle")
      {
        int seconds = round(id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(7));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_8_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 0;
      }
      else if(id(zone8_progress_percentage).state > 1 && id(lawn_sprinkler_ctrlr_status).state != "Paused")
      {
        int seconds = 0;
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
        id(zone_8_time_remaining).publish_state((
          (days ? String(days) + "d " : "") +
          (hours ? String(hours) + "h " : "") +
         (minutes ? String(minutes) + "m " : "") +
         (String(seconds) + "s")
          ).c_str());
        return 100;;
      }
      return {};

number:
  - platform: template
    id: sprinkler_ctrlr_multiplier
    name: "Sprinkler Controller Multiplier"
    min_value: 0.01
    max_value: 3
    step: 0.01
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).multiplier();"
    set_action:
      - globals.set:
            id: multiplier
            value: !lambda "return x;"
      - sprinkler.set_multiplier:
          id: lawn_sprinkler_ctrlr
          multiplier: !lambda 'return x;'
            
  - platform: template
    id: sprinkler_valve_0_duration
    name: "Zone 1 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(0) / 60;"
    set_action:
      - globals.set:
            id: z1_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 0
          run_duration: !lambda "return x * 60;"
      
  - platform: template
    id: sprinkler_valve_1_duration
    name: "Zone 2 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(1) / 60;"
    set_action:
      - globals.set:
            id: z2_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 1
          run_duration: !lambda "return x * 60;"
          
  - platform: template
    id: sprinkler_valve_2_duration
    name: "Zone 3 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(2) / 60;"
    set_action:
      - globals.set:
            id: z3_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 2
          run_duration: !lambda "return x * 60;"
      
  - platform: template
    id: sprinkler_valve_3_duration
    name: "Zone 4 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(3) / 60;"
    set_action:
      - globals.set:
            id: z4_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 3
          run_duration: !lambda "return x * 60;"
          
  - platform: template
    id: sprinkler_valve_4_duration
    name: "Zone 5 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(4) / 60;"
    set_action:
      - globals.set:
            id: z5_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 4
          run_duration: !lambda "return x * 60;"
      
  - platform: template
    id: sprinkler_valve_5_duration
    name: "Zone 6 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(5) / 60;"
    set_action:
      - globals.set:
            id: z6_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 5
          run_duration: !lambda "return x * 60;"
          
  - platform: template
    id: sprinkler_valve_6_duration
    name: "Zone 7 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(6) / 60;"
    set_action:
      - globals.set:
            id: z7_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 6
          run_duration: !lambda "return x * 60;"
      
  - platform: template
    id: sprinkler_valve_7_duration
    name: "Zone 8 Duration"
    min_value: 1
    max_value: 240
    step: 1.0
    update_interval: 1s
    lambda: "return id(lawn_sprinkler_ctrlr).valve_run_duration(7) / 60;"
    set_action:
      - globals.set:
            id: z8_duration
            value: !lambda "return x;"
      - sprinkler.set_valve_run_duration:
          id: lawn_sprinkler_ctrlr
          valve_number: 7
          run_duration: !lambda "return x * 60;"

Many thanks, I just wanted to got some inspirations what cards you were using.

Hello @olympia, I would like to thank you for working with the Sprinkler component developer. I see that you brought up some issues that I was battling for. My language barrier was impeding me to express the issues I’m having.

I’m also glad that you are using part of my code. Would you mind sharing your work here? I’m curious about what you are achieving and your dashboard.

Once again, many thanks!

1 Like

Thank you for noting this!

I am actually in the same shoes as you: I am also not a developer and just learning as I want to achieve something new.

Regarding the dashboard, it’s still in heavy development (but I see the light at the end of the tunnel) and I will have no time in the next 1-1.5 weeks to continue. Still a lot to do both on the backend side (esphome code) and on the HA dashboard (still some design headache besides how I actually code it). Will definitely share the end result.

Some (not complete) teaser:
image

1 Like

I have a single garden sprinkler, so nice and simple. I control runtime duration from HA (Helper “input_number.sprinkler_runtime”) it all works fine, however the text sensor that’s exposed to HA updates every 5 seconds (as it should) but does regardless of whether the sprinkler is running or not, so if not running it sends 0 seconds remaining, every 5 seconds, eg:

[14:03:36][D][text_sensor:064]: ‘Time Remaining’: Sending state ‘0s’
[14:03:41][D][text_sensor:064]: ‘Time Remaining’: Sending state ‘0s’
[14:03:46][D][text_sensor:064]: ‘Time Remaining’: Sending state ‘0s’

The code is fairly basic…

switch:
  - platform: gpio
    name: "Sprinkler Switch"
    id: sprinkler_switch
    pin: D1
    internal: True
    on_turn_off:
      then:
      - lambda: |-
          id(time_remaining) = 0;

sensor:
  - platform: homeassistant
    id: runtime_mins
    unit_of_measurement: "min"
    accuracy_decimals: 0
    entity_id: input_number.sprinkler_runtime
    on_value:
      - sprinkler.set_valve_run_duration:
          id: garden_sprinkler_ctrlr
          valve_number: 0
          run_duration: !lambda "return x * 60;"

sprinkler:
  - id: garden_sprinkler_ctrlr
    valves:
      - valve_switch: "Garden Sprinkler"
        run_duration: 300s  # default max
        valve_switch_id: sprinkler_switch

text_sensor:
  - platform: template
    id: time_remaining
    name: "Time Remaining"
    update_interval: 5s
    icon: "mdi:timer-sand"
    lambda: |-
      int seconds = round(id(garden_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
      int days = seconds / (24 * 3600);
      seconds = seconds % (24 * 3600);
      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()};

To avoid always sending data back, I tried doing a simple if statement in the text_sensor:

lambda: |-
      int seconds = round(id(garden_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
      if (seconds > 0) {
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        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()};
      }

but it fails when compiling.

Compiling /data/sprinkler/.pioenvs/sprinkler/src/main.cpp.o
/config/esphome/sprinkler.yaml: In lambda function:
/config/esphome/sprinkler.yaml:90:3: error: control reaches end of non-void function [-Werror=return-type]
cc1plus: some warnings being treated as errors
*** [/data/sprinkler/.pioenvs/sprinkler/src/main.cpp.o] Error 1
========================== [FAILED] Took 7.82 seconds ==========================

What am I doing wrong?

Edit… actually no void function assume it always requires something to be returned then. What’s the alternative to avoid constant traffic from esp back to ha?

A template sensor must always return some value (text, float, etc) But if you give a sensor no name, it is an internal sensor and it won’t publish its state to HA. So remove the name: line from your yaml for this text sensor.

Didn’t make a difference removing name. Also according to help pages name: is required .

Also I do want the time remaining sent to HA, but only when it’s running, not when it’s idle as there is no point sending “0 seconds remaining” every 5 seconds and is just more overhead for HA to deal with,

Sounds like you need a “text delta filter”.

1 Like

Yep that worked thanks seems my C++ code in the lambda doing the return was initially wrong. But the filter is a much cleaner solution !!

1 Like