How can i re-use Set value's from a template

Hi there,

Sorry, im new at HA.
i try to create a smart washing machine by How To Monitor Your Washing Machine in Home Assistant - YouTube
But i don’t understand how i can re-use the Set’s (washingStarted, expectedEndTime, expectedTimeLeft in the sensors.yaml.

In my templates.yaml i have the code:

- sensor:
    #### Washing machine states ####
    - name: "Washing machine states"
      state: >
        {% set washingStarted = as_timestamp(states('input_datetime.washing_started')) -%}
        {% set washingStopped = as_timestamp(states('input_datetime.washing_stopped')) -%}
        {% set washingExpectedRunTime = states('input_number.washing_expected_runtime') | float(0) -%}
        {% set expectedEndTime = washingStarted + washingExpectedRunTime -%}
        {% set expectedTimeLeft = expectedEndTime - now().timestamp() -%}
        {{ expectedTimeLeft }}

and the sensors.yaml

- platform: template
  sensors:
    washingstarted_date:
      friendly_name: Washing Started
      icon_template: mdi:clock-start
      value_template: >-
        {% set start = state_attr('sensor.washing_machine_states', 'washingStarted') | as_datetime  %}
        {{ start | as_timestamp | timestamp_custom("%d.%m.%Y %H:%M") }}
    washingstopped_date:
      friendly_name: Washing Stopped
      icon_template: mdi:clock-end
      value_template: >-
        {% if is_state("input_boolean.washing_running", "on") -%}
          Wasmachine draait nog
        {%- else -%}
          {% set start = states('input_datetime.washing_stopped') | as_datetime  %}        {{ start | as_timestamp | timestamp_custom("%d.%m.%Y %H:%M") }}
        {%- endif %}

Is there a way to replace:

{% set start = states('input_datetime.washing_stopped') | as_datetime  %}        {{ start | as_timestamp | timestamp_custom("%d.%m.%Y %H:%M") }}

to something like this:

{{ washingStopped | as_timestamp | timestamp_custom("%d.%m.%Y %H:%M") }}

Is there a reason you are using both legacy and current format template sensors?

As it is currently, your first example will only ever return the expected time left.

Not currently. Variables within a template are not accessible outside of the configuration stanza they are in. To access them as attributes of the sensor, you need to create those attributes and define their values. But you would still need to use state_attr() to get the data in other configuration entries.

In your second example, the first line of the value_template will always be “None” if you do not define the attribute in sensor.washing_machine_states.

Hi Drew, thank you for your time to answer my question.

Is there a reason you are using both legacy and current format template sensors?

No more than ignorance. Wich is legacy and wich is current format?

Is there another way to achieve the re-using calculated fields. Or should i simply put it all in one yaml file?

The current format is the one that you are using in your templates.yaml file.



Currently, there aren’t global template variables in Home Assistant. But you are also doing “calculations” that aren’t necessary. Every date-and-time Input datetime helper already includes a timestamp attribute, you do not need to use the as_timestamp() function.

Example: state_attr('input_datetime.washing_started', 'timestamp')

In your previous post you asked about the following template used in the last example sensor:

{% set start = states('input_datetime.washing_stopped') | as_datetime  %}
{{ start | as_timestamp | timestamp_custom("%d.%m.%Y %H:%M")

Which can be simplified by removing unecessary conversions:

{{ (states('input_datetime.washing_stopped') 
| as_datetime).strftime('%d.%m.%Y %H:%M') }}



It is difficult to give advice on how you might best structure your entities without knowing what the intended use or goal is for those entities.

Thank you for your assistance.
I updated my sensor in the templates.yml:

- sensor:
    #### Washing machine states ####
    - name: "Washing machine states"
      unique_id: "sensor.washing_machine_states"
      icon: mdi:clock-start
      state: >-
        {{ this.attributes.ExpectedTimeLeft | default('Value when missing') }}
      attributes:
        WashingStarted: "{{ ((states('input_datetime.washing_started')) | as_datetime)}}"
        # WashingStarted: "{{ as_timestamp(states('input_datetime.washing_started')) | timestamp_custom('%d.%m.%Y %H:%M')}}"
        WashingStopped: >
          {% if is_state("input_boolean.washing_running", "on") %}
            Wasmachine draait nog
          {% else %}
            {{ (states('input_datetime.washing_stopped') | as_datetime).strftime('%d-%m-%Y %H:%M') }}
          {% endif %}
        ExpectedEndTime: "{{ (this.attributes.WashingStarted  | as_datetime) + timedelta(seconds=states('input_number.washing_expected_runtime') | int) }}"
        ExpectedTimeLeftSeconds: "{{ (this.attributes.ExpectedEndTime | as_timestamp) - ('2023-04-03 16:07:29' | as_timestamp) }}"
        ExpectedTimeLeft: >
          {% if is_state("input_boolean.washing_running", "on") %}
            "{{ '%02d:%02d' % ((this.attributes.ExpectedTimeLeftSeconds/3600)|int, (this.attributes.ExpectedTimeLeftSeconds%3600)/60) }}"
          {% endif %}

I would like the day format to be as “Stopped” in the green square.

If i change the code

WashingStarted: "{{ ((states('input_datetime.washing_started')) | as_datetime)}}"

to this code

        WashingStarted: "{{ as_timestamp(states('input_datetime.washing_started')) | timestamp_custom('%d.%m.%Y %H:%M')}}"

The started (red square) is in the expected format.
Howerver then this code will fail:

ExpectedEndTime: "{{ (this.attributes.WashingStarted  | as_datetime) ....

Does anybody know how to solve it?
Or is there another way to format the datetime in the attribute/entity card

- type: attribute
        entity: sensor.washing_machine_states
        attribute: WashingStarted
        name: Gestart
        icon: mdi:clock-start
        format: datetime

@Didgeridrew: Do you have any idea?

Can you clarify what your goal is? I think something is getting lost in translation.

Are you trying to get the value in the red box to be the same format as the value in the green box?

Yes, but i would like to use this.attributes.WashingStarted in “ExpectedEndTime”.

ExpectedEndTime doesnt show if i use

WashingStarted: "{{ as_timestamp(states('input_datetime.washing_started')) | timestamp_custom('%d.%m.%Y %H:%M')}}"

Ok. The core Entities cards don’t allow templates. Based on that limitation you will need a seperate attribute that returns the information formatted the way you want it.

- sensor:
    - name: "Washing machine states"
      unique_id: "sensor.washing_machine_states"
      icon: mdi:clock-start
      state: >-
        {{ this.attributes.ExpectedTimeLeft | default('Value when missing') }}
      attributes:
        WashingStarted: >
          {{ states('input_datetime.washing_started') | as_datetime }}
        wash_start_format: >
          {{ this.attributes.WashingStarted.strftime('%d-%m-%Y %H:%M') }}
        WashingStopped: >
          {% if is_state("input_boolean.washing_running", "on") %}
            Wasmachine draait nog
          {% else %}
            {{ (states('input_datetime.washing_stopped') | as_datetime).strftime('%d-%m-%Y %H:%M') }}
          {% endif %}
        ExpectedEndTime: >
          {% set runtime = states('input_number.washing_expected_runtime') | int %}
          {{ this.attributes.WashingStarted + timedelta(seconds= runtime) }}
        ExpectedTimeLeftSeconds: >
          {{ (this.attributes.ExpectedEndTime - now()).total_seconds() }}
        ExpectedTimeLeft: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {% set seconds = this.attributes.ExpectedTimeLeftSeconds %}
            {{ '%02d:%02d' % (( seconds // 3600), (seconds % 3600)/60) }}
          {% else %} 
            Wasmachine Gestopt
          {% endif %}

Then the card config would be:

type: vertical-stack
title: Wasmachine
cards:
  - type: entities
    entities:
        - type: attribute
          entity: sensor.washing_machine_states
          attribute: wash_start_format
          name: Gestart
          icon: mdi:clock-start
        - type: attribute
          entity: sensor.washing_machine_states
          attribute: WashingStopped
          name: Gestopt
          icon: mdi:clock-end

That was also my alternative.
I was wondering if there another way to work arround this.
Thank you!

Hi, it is working. However in the home-assistant.log i see a few warnings:
Is this only at starup of home-assistant?

Template variable warning: ‘homeassistant.util.read_only_dict.ReadOnlyDict object’ has no attribute ‘WashingStarted’ when rendering ‘{{ as_timestamp(this.attributes.WashingStarted, 0) | timestamp_custom(’%d.%m.%Y %H:%M’)}}’

If someone needs it. There were a few small bugs with quotes.
I ended up with this. It works for me.

- sensor:
    #### Washing machine states ####
    - name: "Washing machine states"
      unique_id: "sensor.washing_machine_states"
      state: >-
        {{ this.attributes.ExpectedTimeLeft | default('Value when missing') }}
      attributes:
        WashingStarted: "{{ ((states('input_datetime.washing_started')) | as_datetime)}}"
        WashingStarted_format: "{{ as_timestamp(this.attributes.WashingStarted, 0) | timestamp_custom('%d.%m.%Y %H:%M')}}"
        WashingStopped: >
          {% if is_state("input_boolean.washing_running", "on") %}
            Wasmachine draait nog
          {% else %}
            {{ (states('input_datetime.washing_stopped') | as_datetime).strftime('%d-%m-%Y %H:%M') }}
          {% endif %}
        ExpectedEndTime: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ (this.attributes.WashingStarted  | as_datetime) + timedelta(seconds=states('input_number.washing_expected_runtime') | int) }}
          {% endif %}
        ExpectedEndTime_format: >
          {% set expEndTime = this.attributes.ExpectedEndTime %}
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ as_timestamp(this.attributes.ExpectedEndTime) | timestamp_custom('%H:%M')}}
          {% endif %}
        ExpectedTimeLeftSeconds: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ (this.attributes.ExpectedEndTime | as_timestamp) - (now() | as_timestamp) }}
          {% endif %}
        ExpectedTimeLeft: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ '%02d:%02d' % ((this.attributes.ExpectedTimeLeftSeconds/3600)|int, (this.attributes.ExpectedTimeLeftSeconds%3600)/60) }}
          {% endif %}

Damn… Almost right. Getting another error now.

2023-04-07 21:56:00.406 WARNING (MainThread) [homeassistant.helpers.template_entity] Template loop detected while processing event: <Event state_changed[L]: entity_id=sensor.washing_machine_states, old_state=<state sensor.washing_machine_states=00:46; WashingStarted=2023-04-07 21:02:39, WashingStarted_format=07.04.2023 21:02, WashingStopped=Wasmachine draait nog, ExpectedEndTime=2023-04-07 22:42:24, ExpectedEndTime_format=22:42, ExpectedTimeLeftSeconds=2783.6173210144043, ExpectedTimeLeft=00:46, friendly_name=Washing machine states @ 2023-04-07T21:56:00.328643+02:00>, new_state=<state sensor.washing_machine_states=00:46; WashingStarted=2023-04-07 21:02:39, WashingStarted_format=07.04.2023 21:02, WashingStopped=Wasmachine draait nog, ExpectedEndTime=2023-04-07 22:42:24, ExpectedEndTime_format=22:42, ExpectedTimeLeftSeconds=2783.6068120002747, ExpectedTimeLeft=00:46, friendly_name=Washing machine states @ 2023-04-07T21:56:00.328643+02:00>>, skipping template render for Template[{% if is_state(“input_boolean.washing_running”, “on”) %}
{{ (this.attributes.ExpectedEndTime | as_timestamp) - (now() | as_timestamp) }}
{% endif %}]

Got rid of the warnings. The log is now calm.
Here is what i ended up with:

- sensor:
    #### Washing machine states ####
    - name: "Washing machine states"
      unique_id: "sensor.washing_machine_states"
      state: >-
        {{ this.attributes.ExpectedTimeLeft | default('N/A') }}
      attributes:
        WashingStarted: "{{ ((states('input_datetime.washing_started')) | as_datetime)}}"
        WashingStarted_format: "{{ as_timestamp(this.attributes.WashingStarted, 0) | timestamp_custom('%d.%m.%Y %H:%M')}}"
        WashingStopped: >
          {% if is_state("input_boolean.washing_running", "on") %}
            Wasmachine draait nog
          {% else %}
            {{ (states('input_datetime.washing_stopped') | as_datetime).strftime('%d-%m-%Y %H:%M') }}
          {% endif %}
        ExpectedEndTime: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ (this.attributes.WashingStarted  | as_datetime) + timedelta(seconds=states('input_number.washing_expected_runtime') | int) }}
          {% endif %}
        ExpectedEndTime_format: >
          {% set expEndTime = this.attributes.ExpectedEndTime %}
          {% if is_state("input_boolean.washing_running", "on") %}
            {{ as_timestamp(this.attributes.ExpectedEndTime) | timestamp_custom('%H:%M')}}
          {% endif %}
        ExpectedTimeLeft: >
          {% if is_state("input_boolean.washing_running", "on") %}
            {% set seconds = (this.attributes.ExpectedEndTime | as_timestamp) - (now() | as_timestamp) %}
            {% set minutes = ((seconds % 3600) // 60) | int %}
            {% set hours = (seconds // 3600) | int  %}
            {{ '{:02}:{:02}'.format(hours, minutes) }}
          {% endif %}